Python高级 - 魔术方法
__call__
1 # __call__ 2 class A: 3 def __call__(self, *args, **kwargs): 4 print('执行call方法') 5 6 a = A() 7 a() # 对象()相当于调用__call__方法 8 9 A()() # 类名()()相当于先实例化得到一个对象,再对对象(),调用__call__方法 10 11 class B(): 12 def __init__(self, cls): 13 self.a = cls() 14 self.a() 15 16 b = B(A)
__len__
1 # __len__ 2 内置函数(len)和类的内置方法(__len__)是有奸情的 3 class mylist(): 4 def __init__(self): 5 self.lst = [1,2,3] 6 self.name = 'alex' 7 self.age = 83 8 9 def __len__(self): 10 return len(self.__dict__) 11 12 l = mylist() 13 print(len(l)) 14 # len(obj)相当于调用了这个obj的__len__方法 15 # __len__方法return的值就是len函数的返回值 16 # 如果一个obj对象没有__len__方法,那么len函数就会报错
17 # 要求obj必须实现了__len__,要求这个方法的返回值必须是数字int类型
__new__
1 # __new__ # 构造方法 : 在实例化的过程中,最先执行的方法,在执行init之前,用来创建一个对象 2 # __init__ # 初始化方法 : 在实例化的过程中,在new执行之后,自动触发的一个初始化方法 3 4 class Single: 5 def __new__(cls, *args, **kwargs): 6 print("new方法") 7 return object.__new__(cls) 8 9 def __init__(self): 10 print("init方法") 11 12 # 1.开辟一个空间,属于对象的 13 # 2.把对象的空间传给self,执行init 14 # 3.把这个对象的空间返回给调用者 15 class Single: 16 def __new__(cls, *args, **kwargs): 17 obj = object.__new__(cls) 18 print("new方法", obj) 19 return obj 20 21 def __init__(self): 22 print("init方法", self) 23 24 obj = Single() 25 # single的new, single没有, 只能调用object的new方法 26 # new方法在什么时候执行? 27 # 在实例化之后,__init__之前先执行new来创建一块空间
单例类
1 # 如果一个类,从头到尾只能有一个实例,说明从头到尾只开辟了一块属于对象的空间,那么这个类就是一个单例类 2 class Single: 3 __ISINSTANCE = None 4 def __new__(cls, *args): 5 if not cls.__ISINSTANCE: 6 cls.__ISINSTANCE = object.__new__(cls) 7 return cls.__ISINSTANCE 8 9 def __init__(self, name, age): 10 self.name = name 11 self.age = age 12 13 s1 = Single("alex", 83) 14 s2 = Single("taibai", 43) 15 print(s1, s2)
__str__
1 class Student: 2 def __str__(self): 3 return '%s %s' % (self.name, self.school) 4 5 def __init__(self, name): 6 self.name = name 7 self.school = "oldboy" 8 9 alex = Student("alex") 10 print(alex) 11 print(str(alex)) # 内置的数据类型, 内置的类, 相当于执行__str__ 12 print('学生 : %s' % alex) 13 14 # print(obj) 相当于执行obj.__str__方法 15 # str(obj) 相当于执行obj.__str__方法 16 # '%s' 相当于执行obj.__str__方法
17 # str(obj),要求必须实现了__str__,要求这个方法的返回值必须是字符串str类型
__repr__
1 # __str__ : str(obj),要求必须实现__str__,要求这个方法的返回值必须是字符串str类型 2 # print %s str 3 # __repr__ : 是__str__备胎.如果有__str__方法,那么# print %s str都先去执行__str__方法,并且使用str的返回值 4 # 如果没有__str__,那么print %s str都会执行__repr__ 5 # repr(obj), %r 6 # 如果子类没有__str__, 先找父类(除object)的__str__,没有再找子类的__repr__(备胎) 7 class A: 8 def __repr__(self): 9 return "A repr" 10 11 def __str__(self): 12 return "A str" 13 14 class B(A): 15 def __init__(self, name): 16 self.name = name 17 18 def __repr__(self): 19 return "B repr" 20 21 # def __str__(self): 22 # return "B str" 23 24 a = B("alex") 25 print(str(a), repr(a)) 26 print("%s | %r" % (a, a))
总结:
__call__ 相当于 obj()
__len__ 相当于 len(obj)
__new__ 特别重要, 开辟内存空间,类的构造方法
__str__ str(obj)、print(obj)、'%s' % obj
__repr__ repr(obj)、'%r' % obj还是__str__的备胎
__repr__ 在继承中父类__str__优先级高于子类(备胎)__repr__
所有的双下方法,都没有 需要在外部直接调用的
而是总有一些其他的 内置函数 特殊的语法 来自动触发这些 双下方法
set集合的去重机制:先调用hash,再调用eq,eq不是每次都会触发,只有hash值相等的时候才会触发
hash(obj) # obj内部必须实现了__hash__方法
hash对同一个值在同一次执行python代码的时候hash值永远不变
对同一个值在多次执行python代码的时候hash值是不同的
hash的结果找到一块内存地址,只要这快地址没有数据,就说明之前没有重复的数据
如果这款地址上有数据存在了才判断这个值和要存储的值是否一样
如果一样覆盖去重
如果不一样,二次寻址给这个值换个地址存储