python常用的魔法方法
双下划线开头和双下划线按结尾的函数称为魔法函数,魔法函数一般都是在类里面使用,在触发的时候可以写其他的逻辑
# __call__:可以让对象带有函数的行为,通过()就可以调用 # 函数为什么可以使用()调用,是因为函数对象里面有__call__方法,而我们写的函数逻辑实际上是存在__call__这个方法里面的 def func(): print("xxx") print(dir(func)) # 可以看到这个函数的对象是有__call__方法的,这也是函数为什么可以使用()调用的原因 """ ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] """ func() """ xxx """ func.__call__() # 使用这两个方法的结果是一样的,说明一个普通函数里面的逻辑是写在__call__下面的。 """ xxx """ # 一般__call__魔法方法是和类一起使用,作用就是让类实例化的时候可以被调用,使调用这个实例可以改变直接改变对象状态。 class A: def __call__(self, *args, **kwargs): print("调用call方法") a = A() # a是一个对象 print(dir(a)) """ ['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'] """ a() """ 调用call方法 """ # 斐波那契数列 class Fibonacci(object): def __call__(self, num): a, b = 1, 1 self.lst = [] if num <= 2: self.lst.append(a) self.lst.append(b) else: for i in range(1, num + 1): self.lst.append(a) a, b = b, a + b return self.lst fibo = Fibonacci() ret = fibo(10) print(ret) """ [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] """ def fibonacci(num): a, b = 1, 1 lst = [] if num <= 2: lst.append(a) lst.append(b) else: for i in range(1, num + 1): lst.append(a) a, b = b, a + b return lst print(fibonacci(10)) """ [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] """ # 这两段程序是一样的, 对于类里面的call的逻辑也是就相当于是写在函数里面的逻辑。 # __new__:实例化第一个被调用的方法,至少传一个cls参数,返回一个对象实例 # __init__:实例化第二个被调用的方法,至少传一个self参数,没有返回值 #作用: __new__:就是为了给对象在被实例化的时候, 分配一块内存地址。 __init__:就是给分配的到的地址里面填内容,就是赋值的过程,也叫属性初始化。 注意:实例化对象是Object类底层实现的,其他类要继承Object的__new__方法才能实现实例化对象 class Earth: def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): # 判断这个属性是否存在 cls._instance = super().__new__(cls) # 如果不存在那么就新建一个地址给他 return cls._instance # 如果存在,就把现有的地址给他 def __init__(self, value1, value2): # 这个方法是一个传值的过程,就是给地址里面写内容,通过上面这个__new__方法使地址永远都只有一个 self.value1 = value1 self.value2 = value2 a = Earth(1,2) print(a.value1, a.value2) """ 1 2 """ b = Earth("a", "b") print(b.value1, b.value2) """ a b """ print(a.value1, a.value2) """ a b """ 结论:这样写每次都保存最后一次实例化的值 ==================================================================== class Earth: instance = None def __new__(cls, *args, **kwargs): if cls.instance is None: cls.instance = super().__new__(cls) return cls.instance def __init__(self, value1, value2): self.value1 = value1 self.value2 = value2 c = Earth('11', '22') print(Earth.instance) """ <__main__.Earth object at 0x0000023E4A8F0B48> """ print(c.value1, c.value2) d = Earth('aa', 'bb') print(Earth.instance) """ <__main__.Earth object at 0x0000023E4A8F0B48> """ print(d.value1, d.value2) """ aa bb """ print(c.value1, c.value2) """ aa bb """ 两个方法都一样:第二个方法好些 #__del__:当一个对象在内存中被销毁的时候会自动触发这个方法 # 这个方法至少接收一个self参数,无返回值 注意:程序会自动调用这个方法,不需要手动执行 class Person(object): def __init__(self): print('init') def __del__(self): print('销毁了。。。') person = Person() # 只要则个程序执行完了,系统系统就会自动去执行__del__ """ init """ """ 销毁了。。。 """ # __str__:字符串显示,至少传递一个self参数,优先调用它 # __repr__:字符串显示,至少传递一个self参数,当没有__str__的时候才会调用__repr__ # 当没有自定义上面的方法的时候,就回去默认执行内置的__str__方法 注意:自定义方法的优先级高于内置方法的优先级,因为每个方法里面都有内置的打印函数,当有自定义的时候,以自定义的优先执行,这也叫重写(优先调用子类方法,如果没有再去调用父类的方法) class Person(object): def __init__(self, value): self.value = value def __repr__(self): info = '调用__repr__方法:%s' % (self.value) return info person = Person('aa') print(person) # 当没有自定义__str__的时候,就调用自定义的__repr__ """调用__repr__方法:aa""" class Person(object): def __init__(self, value): self.value = value def __str__(self): info = '调用__str__方法:%s' % (self.value) return info def __repr__(self): info = '调用__repr__方法:%s' % (self.value) return info person = Person('aa') print(person) # 当两个都重写了,那么就优先调用__str__方法 """调用__str__方法:aa""" class Person(object): def __init__(self, value): self.value = value person = Person('aa') print(person) # 如果都没有自定义,那么就会默认去调用内置的__str__方法 """<__main__.Person object at 0x000002666FA79888>"""