python基础语法18 类的内置方法(魔法方法),单例模式

类的内置方法(魔法方法):

  凡是在类内部定义,以__开头__结尾的方法,都是类的内置方法,也称之为魔法方法。

  类的内置方法,会在某种条件满足下自动触发。

内置方法如下:
  __new__: 在__init__触发前,自动触发。 调用该类时,内部会通过__new__产生一个新的对象。
  __init__: 在调用类时自动触发。 通过产生的对象自动调用__init__()

class Demo(object):
    # 条件: __new__: 在__init__触发前,自动触发。
    def __new__(cls, *args, **kwargs):
        print('此处是__new__方法的执行')
        # python内部通过object调用内部的__new__实现产生一个空的对象  ---> 内存地址
        return object.__new__(cls,*args,**kwargs)

    # 条件: __init__: 在调用类时自动触发。
    def __init__(self):
        print('此处是__init__方法的执行')

demo_obj=Demo()
'''result:
此处是__new__方法的执行
此处是__init__方法的执行
'''

__getattr__: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。

class Demo(object):
    # __getattr__: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。
    def __getattr__(self, item):
        print('此处是__getattr__方法的执行')
        print(item)
     # return 想要返回的值
return '别闹,没有该属性' demo_obj=Demo() print(demo_obj.x) ''' 此处是__getattr__方法的执行 x 别闹,没有该属性 ''' demo_obj.x=3 print(demo_obj.x) # 3
条件: __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。
注意: 只要__getattr__ 与 __getattribute__ 同时存在类的内部,只会触发__getattribute__。
class Demo(object):
    # 条件: __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。
    def __getattribute__(self, item):
        print('此处是__getattribute__方法的执行')
        print(item,'<-----打印属性名字')
        # return self.__dict__[item]    # 注意: 此处不能通过 对象.属性,否则会产生递归调用,程序崩溃
        # return getattr(self.item)   # getattr: 内部调用了 ----> __getattribute__, 也会递归

# 注意: 只要__getattr__ 与 __getattribute__ 同时存在类的内部,只会触发__getattribute__。
demo_obj=Demo()
print(demo_obj.x)
'''
此处是__getattribute__方法的执行
x <-----打印属性名字
None
'''
demo_obj.x=3
print(demo_obj.x)   # 3
'''
此处是__getattribute__方法的执行
x <-----打印属性名字
None
'''

条件: 当 “对象.属性 = 属性值” , 添加或修改属性时触发

class Demo(object):
    # 条件: 当 “对象.属性 = 属性值” , 添加或修改属性时触发
    def __setattr__(self, key, value):  # key---> 对象.属性名  value ---》 属性值
        print('# key---> 对象.属性名  value ---》 属性值')
        print(key,value)
        #self.key=value  #产生递归

        self.__dict__[key]=value    # 此处是对 对象的名称空间 ---》 字典进行操作

demo_obj=Demo()
# print(demo_obj.x)

demo_obj.x=3
'''
# key---> 对象.属性名  value ---》 属性值
x 3
'''
print(demo_obj.x)   # 3

条件: 在调用对象 “对象 + ()” 时触发。

class Demo(object):
    # 条件: 在调用对象 “对象 + ()” 时触发。
    def __call__(self, *args, **kwargs):
        print('此处是__call__方法的执行')
        #调用对象时返回的值
        return [1,2,3,4,5]

demo_obj=Demo()
res=demo_obj()  # 此处是__call__方法的执行
print(res)  # [1, 2, 3, 4, 5]

条件: 在打印对象时触发。

class Demo: 
   # 条件: 在打印对象时触发。
    #注意:该方法必须要有一个"字符串"返回值
    def __str__(self):
        print('此处是__str__方法的执行')
        return '111'

demo_obj=Demo()
print(demo_obj)
'''
此处是__str__方法的执行
111
'''

在对象通过 “对象[key]” 获取属性时触发。

class Demo:
    # 在对象通过 “对象[key]” 获取属性时触发。
    def __getitem__(self, item):
        print('此处是__getitem__方法的执行')
        print(item)
        return self.__dict__[item]

demo_obj=Demo()
demo_obj.x=10
res=demo_obj['x']
'''
此处是__getitem__方法的执行
x
'''
print(res)  # 10

在对象通过 “对象[key]=value值” 设置属性时触发。

class Demo:
    # 在对象通过 “对象[key]=value值” 设置属性时触发。
    def __setitem__(self, key, value):
        print('此处是__setitem__方法的执行')
        print(key,value)
        self.__dict__[key] = value

demo_obj=Demo()
demo_obj['y']=300
'''
此处是__setitem__方法的执行
y 300
'''
print(demo_obj.y)  # 10

单例模式:

  指的是在确定 "类中的属性与方法" 不变时,需要反复调用该类,
  产生不同的对象,会产生不同的内存地址,造成资源的浪费。

  让所有类在实例化时,指向同一个内存地址,称之为单例模式。 ----> 无论产生多个对象,都会指向 单个 实例。

  - 单例的优点:
    节省内存空间。

#反面案例
class
Foo: def __init__(self,x,y): self.x=x self.y=y foo_obj1=Foo(10,20) print(foo_obj1) # <__main__.Foo object at 0x0000000001D85CF8> foo_obj2=Foo(10,20) print(foo_obj2) # <__main__.Foo object at 0x00000000021BCC88>

单例模式: (面试让你手撸,一定要背下来。)
1.通过classmethod
2.通过装饰器实现
3.通过__new__实现
4.通过导入模块时实现
5.通过元类实现。

classmethod实现

class MySQL:
    # 一个默认值,用于判断对象是否存在, 对象不存在证明值是None
    # __instance是类的属性,可以由类来调用
    __instance = None  # ---》 若已有对象会返回给它 ---》 obj
    # __instance = obj

    def __init__(self,host,port):
            self.host=host
            self.port=port

    @classmethod
    def singleton(cls,host,port):   # 单例方法 ---》 类方法

        # 判断__instance中若没有值,证明没有对象
        if not cls.__instance:
            # 产生一个对象并返回
            obj=cls(host,port)
            # None ---> obj
            cls.__instance=obj

        # 若__instance中有值,证明对象已经存在,则直接返回该对象
        return cls.__instance
    def start_mysql(self):
        print('启动mysql')
    def close(self):
        print('关闭mysql')
obj1=MySQL.singleton('180.101.49.12',443)
print(obj1) # <__main__.MySQL object at 0x000000000255D160>
obj2=MySQL.singleton('180.101.49.12',443)
print(obj2) # <__main__.MySQL object at 0x000000000255D160>

或者:

class Borg:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,'_instance'):
            ob = super(Borg,cls)
            cls._instance = ob.__new__(cls,*args,**kwargs)
        return cls._instance

        # if not hasattr(cls,'_instance'):
        #     # 造一个空对象
        #     cls._instance = object.__new__(cls)
        # return cls._instance

class MyClass(Borg):
    def __init__(self):
        self.a = 1

obj1 = MyClass()
obj2 = MyClass()
print(obj1)
print(obj2)
View Code

 __new__实现

# __new__创造单例模式
class Singleton:
    __instance = None
    @classmethod    # 此处可以不加此装饰器,__new__默认为类方法
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            # 造一个空对象
            cls.__instance = object.__new__(cls)
        return cls.__instance

obj1= Singleton()
obj2= Singleton()
obj3= Singleton()
print(obj1) # <__main__.Singleton object at 0x000000000255D048>
print(obj2) # <__main__.Singleton object at 0x000000000255D048>
print(obj3) # <__main__.Singleton object at 0x000000000255D048>

装饰器实现

def singleton(cls):
    _instance = {}  #此处必须为可变类型
    def inner(*args,**kwargs):
        if cls not in _instance:
            _instance[cls] = cls(*args,**kwargs)
        return _instance[cls]
    return inner

@singleton
class Father:
    pass

print(Father()) # <__main__.Father object at 0x0000000001DA5D68>
print(Father()) # <__main__.Father object at 0x0000000001DA5D68>

为什么不能用_instance=None赋值说明

def singleton(cls):    
    _instance = None  #此处必须为可变类型
    def inner(*args,**kwargs):
        if not _instance: # 报错,因为_instance优先指向内置空间的对象,也就是下面的_instance,没有就报错,无解!此处必须用字典等方法
            _instance = cls(*args,**kwargs) 
        return _instance
    return inner

@singleton
class Father:
    pass

print(Father()) 
print(Father()) 

模块导入

# 以下为singleton模块
class SingletonCls:
    pass
obj = SingletonCls()

# 以下为测试程序
from singleton模块 import obj
print(obj)
print(obj)
原文地址:https://www.cnblogs.com/ludingchao/p/11959022.html