双下划线开头和双下划线按结尾的函数称为魔法函数,魔法函数一般都是在类里面使用,在触发的时候可以写其他的逻辑
# __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>"""