魔法方法概念
在面向对象编程时,需要创建一个个对象,我们要用一些底层的方法来描述对象。使我们创建的对象在遇各种运算符、python内置函数时,能做出相应的行为而不是直接报错。python中的魔法方法就是我们用来描述对象的底层方法,只有我们在类中定义了这些魔法方法,类的实例对象才能对各种运算符和python内置函数有反应。当然我们也不用在类中定义所有的魔法方法,我们要根据设计这个类的用途来定义相关的魔法方法。例如我只希望这个类能做加法,就只需要在类中定义跟加号相关的魔法方法,而不用去定义跟减号、乘号、除号相关的魔法方法。
构造方法(__new__)
__new__方法是用来创建实例对象的方法,跟C++里面的构造方法相似。实例化类时,首先调用__new__方法。__new__方法必须返回一个实例,我们才能得到类的实例;如果__new__方法不返回实例,那么这个类的实例为None。object中的__new__方法是python提供在内存中开辟地址的方法,所以我们要创建实例要么依靠父类的__new__方法,要么使用object的__new__方法。因为object是所有类的父类,所以都是使用object的__new__方法来创建实例的。
不返回实例
class Person:
def __new__(cls, *args, **kwargs):
"""创建实例"""
print('创建实例')
person = Person()
person.name = '小明'
print(person.name)
__new__方法没有用return返回实例,Person的实例是None。执行结果如下:
Person的实例person为None,None是不能定义属性的,因为不能保存在内存中,所以报错显示空对象没有属性name。
返回实例
class Person:
def __new__(cls, *args, **kwargs):
"""创建实例"""
print('创建实例')
return object.__new__(cls) # 使用object中的__new__方法创建实例(开辟内存地址)
person = Person()
person.name = '小明'
print(person.name)
使用object的__new__方法来创建实例,并返回创建的实例,就能得到实例对象了。执行结果如下:
所以我们可以在__new__方法中做一些骚操作,例如设计单例模式,但要记住最后用return返回实例,不然我们就得不到实例对象。
初始化方法(__init__)
__init__方法是用来给实例属性赋值的,所以又被称为初始化方法(设定初始值)。实例化的第二步就是把__new__方法返回的实例给__init__方法,__init__方法就会给这个实例的属性赋初值。所以我们经常在__init__中定义实例的属性。
class Person:
def __new__(cls, *args, **kwargs):
print('创建实例')
return object.__new__(cls)
def __init__(self, name):
print('初始化')
self.name = name
person = Person('小明')
print(person.name)
执行结果如下:
析构方法(__del__)
__del__方法是在释放实例对象的时候会调用的方法,python中规定当一个对象被另一个对象引用时,该对象的引用计数+1;该对象没有被其他对象引用时,引用计数为0。当一个对象的引用计数为0时,它会被python的内存回收机制销毁掉,以释放其占用的内存资源(如果所有创建的对象都不会被销毁释放掉,那么内存迟早会出现不够用的情况)。我们可以把一些需要在对象销毁时关闭的子进程对象、文件对象等放在__del__中,在销对象时调用关闭它们的方法来关闭它们。
class Person:
def __init__(self, history):
self.history = open(history, 'a', encoding='utf-8')
def __del__(self):
self.history.close()
person = Person('./history.txt')
person.history.write('生于1999年')
实例属性history是一个文件对象,我们把history的关闭放在__del__中,我们就可以在对象存在的周期内随意的写history文件。而不用担心history不会被关闭,因为对象被销毁时会关闭history文件对象。
描述相关
当我们使用print函数打印某个对象时,print函数会打印出这个对象的字符串形式,跟使用str函数一样,会调用这个对象的__str__或__repr__方法。当定义了__str__方法时,使用__str__方法;没有定义__str__方法但定义了__repr__方法时,使用__repr__方法;都没有定义时,使用父类的__str__方法。
__str__方法
__str__方法是用来描述对象的,主要面向使用者,为了给使用这个对象的人描述这个对象,使用的描述字符应偏向于适合人阅读。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __str__(self):
return f'{self.__name}性别{self.__sex}今年{self.__age}岁'
person = Person('小明', '男', 18)
print(person)
description = str(person)
print(description)
执行结果如下:
当没有定义__str__方法但定义了__repr__方法时,会使用__repr__方法。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __repr__(self):
return f'{self.__name}性别{self.__sex}今年{self.__age}岁'
person = Person('小明', '男', 18)
print(person)
description = str(person)
print(description)
执行结果如下:
__repr__方法
__repr__方法是用来描述对象的,主要面向开发者,为了给调试这个对象的人描述这个对象,使用的描述字符应偏向于适合被当作代码执行。__repr__方法主要被repr函数使用,有时也作为str函数和print函数的客串方法。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __repr__(self):
return f"Person('{self.__name}', '{self.__sex}', {self.__age})"
person = Person('小明', '男', 18)
print(person)
description = repr(person)
print(description)
执行结果如下:
__unicode__方法
__unicode__方法用来返回对象的Unicode字符串,当对象被unicode函数使用时,会调用对象的__unicode__方法来返回Unicode字符串。但python3中没有unicode函数了,只有str函数。但str函数也不会调用__unicode__方法,__unicode__就非常尴尬,处于可有可无的状态。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __unicode__(self):
return u'Person'
person = Person('小明', '男', 18)
print(person.__unicode__())
执行结果如下:
__bytes__方法
__bytes__方法是用来返回对象字节字符串的,当对象被bytes函数使用时,会调用__bytes__方法来返回字节字符串。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __bytes__(self):
return bytes(f'{self.__name}性别{self.__sex}今年{self.__age}岁', encoding='utf-8')
person1 = Person('小明', '男', 18)
print(bytes(person1))
执行结果如下:
__format__方法
__format__方法是用来格式化输出当前对象的,当前对象被format函数使用时,会调用__format__方法输出用来描述当前对象的某种格式的字符串。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __format__(self, format_spec):
if format_spec == ":":
return f'姓名: {self.__name} 性别: {self.__sex} 岁数: {self.__age}'
elif format_spec == "-":
return f'姓名-{self.__name} 性别-{self.__sex} 岁数-{self.__age}'
else:
return f'{self.__name}性别{self.__sex}今年{self.__age}岁'
person = Person('小明', '男', 18)
print('人物信息: {:-}'.format(person))
print(format(person, ':'))
执行结果如下:
__hash__方法
__hash__方法使用来返回当前对象唯一标识符的,具有唯一标识符的对象具有唯一性,可以用来比较当前对象与其他对象是否相等,也被用于字典中键的快速比较。当前对象被hash函数使用时,会调用__hash__方法。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __hash__(self):
return hash(f'{self.__name}性别{self.__sex}今年{self.__age}岁')
person1 = Person('小明', '男', 18)
person2 = Person('李梅', '女', 20)
print(hash(person1))
print(hash(person2))
print(person1 == person2)
print(person1 == person1)
执行结果如下:
__bool__方法
__bool__方法是用来返回bool值的,可以设置当前对象的真假值,当前对象被bool函数使用时,会调用bool方法。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __bool__(self):
if self.__sex == '男':
return True
return False
person1 = Person('小明', '男', 18)
person2 = Person('李梅', '女', 20)
print(bool(person1))
print(bool(person2))
if person1:
print('小明')
if person2:
print('李梅')
执行结果如下:
__dir__方法
__dir__方法使用来输出对象的所有属性和方法的,当前对象被dir函数使用时,会调用__dir__方法返回当前对象的所有属性和方法。一般我们不用自定义__dir__方法,直接使用父类或者object的__dir__方法。如果我们想隐藏属性或方法,或者设置了未知属性或方法就可以自定义__dir__。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __dir__(self):
return [i for i in super().__dir__() if '_Person__' not in i] # 去掉隐藏属性
person1 = Person('小明', '男', 18)
print(dir(person1))
执行结果如下:
__sizeof__方法
__sizeof__方法用来返回当前对象的内存大小(单位:bytes),使用sys中的getsizeof函数会调用__sizeof__方法,我们最好不要自定义这个方法,免得返回的内存大小有误。
import sys
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __sizeof__(self):
print('__sizeof__')
return 32
person1 = Person('小明', '男', 18)
print(sys.getsizeof(person1))
执行结果如下:
__instancecheck__方法
__instancecheck__方法用来返回一个实例是否是当前类的实例,__instancecheck__方法必须定义在元类中才有用。我们在元类中定义了__instancecheck__方法后,需要在其他类中声明我们定义的元类,__instancecheck__方法才可以被其他类使用。
class Person(type):
def __instancecheck__(self, instance):
print('__instancecheck__')
return True
class Student(metaclass=Person):
...
print(isinstance(1, Student))
执行结果如下:
我们这个__instancecheck__方法比较随意,没加什么判断,任何对象都是它的实例。
__subclasscheck__方法
__subclasscheck__方法是用来返回一个类是否是当前类的子类,__subclasscheck__方法必须定义在元类中才有用。我们在元类中定义了__subclasscheck__方法后,需要在其他类中声明我们定义的元类,__subclasscheck__方法才可以被其他类使用。
class Person(type):
def __subclasscheck__(self, subclass):
print('__subclasscheck__')
return True
class Student(metaclass=Person):
...
print(issubclass(int, Student))
执行结果如下:
__copy__方法
__copy__方法用来浅拷贝当前对象,浅拷贝就是只拷贝父级对象,不拷贝子级对象。当被copy中的copy函数使用时,会调用__copy__方法。
import copy
class Person:
def __init__(self, name, sex, age, list1):
self.__name = name
self.__sex = sex
self.__age = age
self.list = list1
def __copy__(self):
print('__copy__')
return Person(self.__name, self.__sex, self.__age, self.list)
person1 = Person('小明', '男', 18, [1, 2, 3])
person2 = copy.copy(person1) # 浅拷贝
print(person1 is person2) # 父级对象不同
print(person1.list is person2.list) # 子级对象相同,即使是列表这种可变类型
执行结果如下:
__deepcopy__方法
__deepcopy__方法用来深拷贝对象,深拷贝就是递归拷贝,一直考完所有对象为止。当被copy中的deepcopy函数使用时,会调用__deepcopy__方法。
import copy
class Person:
def __init__(self, name, sex, age, list1):
self.__name = name
self.__sex = sex
self.__age = age
self.list = list1
def __deepcopy__(self, memodict={}):
print('__deepcopy__')
return Person(copy.deepcopy(self.__name, memodict), copy.deepcopy(self.__sex, memodict),
copy.deepcopy(self.__age), copy.deepcopy(self.list))
person1 = Person('小明', '男', 18, [1, 2, 3])
person2 = copy.deepcopy(person1) # 深拷贝
print(person1 is person2) # 父级对象不同
print(person1.list is person2.list) # 子级对象不同,即使是列表这种可变类型
执行结果如下:
运算符
运算符有很多,比较运算、数值运算、算术运算、位运算、赋值运算、成员运算。在这里我想说一点,就是所有的魔法方法我们都可以给它定义成我们自己的运算逻辑,比如大于符号的魔法方法中我们可以写加法逻辑,对象遇到大于符号就变成了加法运算而不是比较大小。但是这样做会造成一个后果,别人无法根据正常思维来使用你写的类,只有你自己才懂运算规则(你的记忆能力要比较好,不然你自己也搞忘了)。所以我们还是要用正常思维来设计这些魔法方法中的运算逻辑。
比较运算
比较运算分为等于、不等于、大于、小于、大于等于、小于等于。
__eq__方法(==)
__eq__方法用来处理对象遇到==符号时的行为,判断当前对象与其他对象是否相等,要返回bool值(True或False)。
class Number:
def __init__(self, number):
self.number = number
def __eq__(self, other):
return self.number == other
number1 = Number(3)
print(number1 == 1)
print(number1 == 3)
Number是我们自定义的对象,它并非整型,为什么它的实例可以和整型作比较,因为我们定义了__eq__方法,只要遇到==符号就会使用__eq__方法。我们在__eq__方法中使用实例属性number去和其他对象做比较的,因为number是整型所以number1可以和整型作比较。(后面的方法原理也是这样,我就不重复解释了)执行结果如下:
__ne__方法(!=)
__ne__方法用来处理对象遇到!=符号时的行为,判断当前对象与其他对象是否不相等,要返回bool值(True或False)。
class Number:
def __init__(self, number):
self.number = number
def __ne__(self, other):
return self.number != other
number1 = Number(3)
print(number1 != 1)
print(number1 != 3)
执行结果如下:
__gt__方法(>)
__gt__方法用来处理对象遇到>符号时的行为,判断当前对象是否大于其他对象,要返回bool值(True或False)。
class Number:
def __init__(self, number):
self.number = number
def __gt__(self, other):
return self.number > other
number1 = Number(3)
print(number1 > 1)
print(number1 > 3)
执行结果如下:
__lt__方法(<)
__lt__方法用来处理对象遇到<符号时的行为,判断当前对象是否小于其他对象,要返回bool值(True或False)。
class Number:
def __init__(self, number):
self.number = number
def __lt__(self, other):
return self.number < other
number1 = Number(3)
print(number1 < 1)
print(number1 < 5)
执行结果如下:
__ge__方法(>=)
__ge__方法用来处理对象遇到>=符号时的行为,判断当前对象是否大于等于其他对象,要返回bool值(True或False)。
class Number:
def __init__(self, number):
self.number = number
def __ge__(self, other):
return self.number >= other
number1 = Number(3)
print(number1 >= 1)
print(number1 >= 3)
执行结果如下:
__le__方法(<=)
__le__方法用来处理对象遇到<=符号时的行为,判断当前对象是否小于等于其他对象,要返回bool值(True或False)。
class Number:
def __init__(self, number):
self.number = number
def __le__(self, other):
return self.number <= other
number1 = Number(3)
print(number1 <= 1)
print(number1 <= 3)
执行结果如下:
数值运算
数值运算有取正运算、取负运算、绝对值运算、精度保留、向下取整、向上取整、取整。
__pos__方法(取正运算)
__pos__方法用来处理对象前面有+号时(不是加法运算哦)的行为。(我觉得取正运算没什么用,给大家开个玩笑)
class Number:
def __init__(self, number):
self.number = number
def __pos__(self):
return f'想对{self.number}取正,我不干'
number1 = Number(3)
print(+number1)
number2 = Number(-5)
print(+number2)
执行结果如下:
__neg__方法(取负运算)
__neg__方法用来处理对象前面有-号时(不是减法运算哦)的行为,负数变正数,正数变负数。
class Number:
def __init__(self, number):
self.number = number
def __neg__(self):
return -self.number
number1 = Number(3)
print(-number1)
number2 = Number(-5)
print(-number2)
执行结果如下:
__abs__方法(绝对值运算)
__abs__方法用来处理对象遇到abs函数时的行为,返回一个数的绝对值。
class Number:
def __init__(self, number):
self.number = number
def __abs__(self):
return self.number if self.number >= 0 else -self.number
number1 = Number(3.1)
print(abs(number1))
number2 = Number(-5.6)
print(abs(number2))
执行结果如下:
__round__方法(精度保留)
__round__方法用来处理对象遇到round函数时的行为,只保留n位的小数位数,并返回这个小数。(当运算逻辑过于复杂的时候,我们直接使用python中的内置函数,不失为一种更好的选择)
class Number:
def __init__(self, number):
self.number = number
def __round__(self, n=None):
return round(self.number, n)
number1 = Number(3.123456)
print(round(number1, 5))
number2 = Number(-5.8123)
print(round(number2, 2))
执行结果如下:
__floor__方法(向下取整)
__floor__方法在遇到math库中的floor函数时被使用,返回向下取整后的整数。
import math
class Number:
def __init__(self, number):
self.number = number
def __floor__(self):
if self.number >= 0:
return int(self.number)
else:
return int(self.number) - 1
number1 = Number(3.1)
print(math.floor(number1))
number2 = Number(-5.8)
print(math.floor(number2))
执行结果如下:
__ceil__方法(向上取整)
__ceil__方法在遇到math库中的ceil函数时被使用,返回向上取整后的整数。
import math
class Number:
def __init__(self, number):
self.number = number
def __ceil__(self):
if type(self.number) == int:
return self.number
elif type(self.number) == float and self.number >= 0:
return int(self.number) + 1
elif type(self.number) == float and self.number < 0:
return int(self.number)
else:
raise ValueError
number1 = Number(3)
print(math.ceil(number1))
number2 = Number(-5.8)
print(math.ceil(number2))
执行结果如下:
__trunc__方法(取整)
__trunc__方法在遇到math库中的trunc函数时被使用,返回取整后的整数。
import math
class Number:
def __init__(self, number):
self.number = number
def __trunc__(self):
return int(self.number)
number1 = Number(3.1)
print(math.trunc(number1))
number2 = Number(-5.8)
print(math.trunc(number2))
执行结果如下:
算术运算
算术运算包括最基本的加、减、乘、除四则运算,还有整除求余、整除求整、幂运算。
__add__方法(加法)
__add__方法用来处理对象遇到+号时的行为,求出当前对象与其他对象的和,并返回相加结果。
class Number:
def __init__(self, number):
self.number = number
def __add__(self, other):
return self.number + other
number1 = Number(3)
print(number1 + 2)
number2 = Number(-5)
print(number2 + 5)
执行结果如下:
__sub__方法(减法)
__sub__方法用来处理对象遇到-号时的行为,求出当前对象与其他对象的差,并返回相减结果。
class Number:
def __init__(self, number):
self.number = number
def __sub__(self, other):
return self.number - other
number1 = Number(3)
print(number1 - 2)
number2 = Number(-5)
print(number2 - 5)
执行结果如下:
__mul__方法(乘法)
__mul__方法用来处理对象遇到*号时的行为,求出当前对象与其他对象的积,并返回相乘结果。
class Number:
def __init__(self, number):
self.number = number
def __mul__(self, other):
return self.number * other
number1 = Number(3)
print(number1 * 2)
number2 = Number(-5)
print(number2 * 5)
执行结果如下:
__truediv__方法(除法)
__truediv__方法用来处理对象遇到/号时的行为,求出当前对象与其他对象的商,并返回相除结果。
class Number:
def __init__(self, number):
self.number = number
def __truediv__(self, other):
return self.number / other
number1 = Number(3)
print(number1 / 2)
number2 = Number(-5)
print(number2 / 5)
执行结果如下:
__mod__方法(求余)
__mod__方法用来处理对象遇到%号时的行为,求出当前对象与其他对象整除的余数,并返回余数。
class Number:
def __init__(self, number):
self.number = number
def __mod__(self, other):
return self.number % other
number1 = Number(3)
print(number1 % 2)
number2 = Number(-5)
print(number2 % 5)
执行结果如下:
__floordiv__方法(求整)
__floordiv__方法用来处理对象遇到//号时的行为,求出当前对象与其他对象整除的商,并返回商。
class Number:
def __init__(self, number):
self.number = number
def __floordiv__(self, other):
return self.number // other
number1 = Number(3)
print(number1 // 2)
number2 = Number(-5)
print(number2 // 5)
执行结果如下:
__pow__方法(幂运算)
__pow__方法用来处理对象遇到**号或pow函数时的行为,求出当前对象的n次方,并返回幂运算的结果。当使用pow函数传入第三个参数时,会求出对象的n次方后再对第三个参数求余。
class Number:
def __init__(self, number):
self.number = number
def __pow__(self, power, modulo=None):
if modulo:
return self.number ** power % modulo
else:
return self.number ** power
number1 = Number(3)
print(number1 ** 2)
number2 = Number(-5)
print(number2 ** 2)
print(pow(number2, 2, 2)) # -5 ** 2 % 2
执行结果如下:
反算术运算
反算术运算就是其他对象在+号前,当前对象在+号后的算术运算。(当前对象被当作右操作数)
__radd__方法(加法)
__radd__方法用来处理对象遇到+号时的行为,求出当前对象与其他对象的和,并返回相加结果。
class Number:
def __init__(self, number):
self.number = number
def __radd__(self, other):
return other + self.number
number1 = Number(3)
print(2 + number1)
number2 = Number(-5)
print(2 + number2)
执行结果如下:
__rsub__方法(减法)
__rsub__方法用来处理对象遇到-号时的行为,求出当前对象与其他对象的差,并返回相减结果。
class Number:
def __init__(self, number):
self.number = number
def __rsub__(self, other):
return other - self.number
number1 = Number(3)
print(2 - number1)
number2 = Number(-5)
print(2 - number2)
执行结果如下:
__rmul__方法(乘法)
__rmul__方法用来处理对象遇到*号时的行为,求出当前对象与其他对象的积,并返回相乘结果。
class Number:
def __init__(self, number):
self.number = number
def __rmul__(self, other):
return other * self.number
number1 = Number(3)
print(2 * number1)
number2 = Number(-5)
print(2 * number2)
执行结果如下:
__rtruediv__方法(除法)
__rtruediv__方法用来处理对象遇到/号时的行为,求出当前对象与其他对象的商,并返回相除结果。
class Number:
def __init__(self, number):
self.number = number
def __rtruediv__(self, other):
return other / self.number
number1 = Number(3)
print(2 / number1)
number2 = Number(-5)
print(2 / number2)
执行结果如下:
__rmod__方法(求余)
__rmod__方法用来处理对象遇到%号时的行为,求出当前对象与其他对象整除的余数,并返回余数。
class Number:
def __init__(self, number):
self.number = number
def __rmod__(self, other):
return other % self.number
number1 = Number(3)
print(2 % number1)
number2 = Number(-5)
print(2 % number2)
执行结果如下:
__rfloordiv__方法(求整)
__rfloordiv__方法用来处理对象遇到//号时的行为,求出当前对象与其他对象整除的商,并返回商。
class Number:
def __init__(self, number):
self.number = number
def __rfloordiv__(self, other):
return other // self.number
number1 = Number(3)
print(2 // number1)
number2 = Number(-5)
print(2 // number2)
执行结果如下:
__rpow__方法(幂运算)
__rpow__方法用来处理对象遇到**号或pow函数时的行为,求出其他对象的当前对象次方,并返回幂运算的结果。此时pow函数不能传入第三个参数,否者会报错,而且当前对象为第二个参数。
class Number:
def __init__(self, number):
self.number = number
def __rpow__(self, other):
return other ** self.number
number1 = Number(3)
print(2 ** number1)
number2 = Number(-5)
print(2 ** number2)
print(pow(2, number1))
执行结果如下:
位运算
位运算包括左移、右移、按位与、按位或、按位异或、按位取反运算。
__lshift__方法(左移)
__lshift__方法用来处理对象遇到<<号时的行为,求出当前对象在2进制下向左移n位后的值,并返回移位后的新值。
class Number:
def __init__(self, number):
self.number = number
def __lshift__(self, other):
return self.number << other
number1 = Number(3)
print(number1 << 2) # 011 << 2 -> 01100
number2 = Number(-5)
print(number2 << 2) # 1101 -> 1010 -> 1011 << 2 -> 101100 -> 110011 -> 110100
执行结果如下:
__rshift__方法(右移)
__rshift__方法用来处理对象遇到>>号时的行为,求出当前对象在2进制下向右移n位后的值,并返回移位后的新值。
class Number:
def __init__(self, number):
self.number = number
def __rshift__(self, other):
return self.number >> other
number1 = Number(3)
print(number1 >> 2) # 011 >> 2 -> 0
number2 = Number(-5)
print(number2 >> 2) # 1101 -> 1010 -> 1011 >> 2 -> 10 -> 11 -> 110
执行结果如下:
__and__方法(按位与)
__and__方法用来处理对象遇到&号时的行为,求出当前对象与其他对象在2进制下按位与运算后的值,并返回按位与后的新值。
class Number:
def __init__(self, number):
self.number = number
def __and__(self, other):
return self.number & other
number1 = Number(3)
print(number1 & 2) # 011 & 010 -> 010
number2 = Number(-5)
print(number2 & 2) # 1101 -> 1010 -> 1011 & 0010 -> 0010
执行结果如下:
__or__方法(按位或)
__or__方法用来处理对象遇到|号时的行为,求出当前对象与其他对象在2进制下按位或运算后的值,并返回按位或后的新值。
class Number:
def __init__(self, number):
self.number = number
def __or__(self, other):
return self.number | other
number1 = Number(3)
print(number1 | 2) # 011 | 010 -> 011
number2 = Number(-5)
print(number2 | 2) # 1101 -> 1010 -> 1011 | 0010 -> 1011 -> 1100 -> 1101
执行结果如下:
__xor__方法(按位异或)
__xor__方法用来处理对象遇到^号时的行为,求出当前对象与其他对象在2进制下按位异或运算后的值,并返回按位异或后的新值。
class Number:
def __init__(self, number):
self.number = number
def __xor__(self, other):
return self.number ^ other
number1 = Number(3)
print(number1 ^ 2) # 011 ^ 010 -> 001
number2 = Number(-5)
print(number2 ^ 2) # 1101 -> 1010 -> 1011 ^ 0010 -> 1001 -> 1110 -> 1111
执行结果如下:
__invert__方法(按位取反)
__invert__方法用来处理对象遇到~号时的行为,求出当前对象在2进制下按位取反的值,并返回按位取反的新值。
class Number:
def __init__(self, number):
self.number = number
def __invert__(self):
return ~self.number
number1 = Number(3)
print(~number1) # ~011 -> 100 -> 111 -> 1100
number2 = Number(-5)
print(~number2) # 1101 -> 1010 -> ~1011 -> 0100
执行结果如下:
反位运算
反位运算就是当前对象在位运算符号右面的位运算。(当前对象被当作右操作数)
__rlshift__方法(左移)
__rlshift__方法用来处理对象遇到<<号时的行为,求出其他对象在2进制下向左移当前对象位后的值,并返回移位后的新值。
class Number:
def __init__(self, number):
self.number = number
def __rlshift__(self, other):
return other << self.number
number1 = Number(3)
print(2 << number1) # 010 << 3 -> 010000
number2 = Number(5)
print(2 << number2) # 010 << 5 -> 01000000
执行结果如下:
__rrshift__方法(右移)
__rrshift__方法用来处理对象遇到>>号时的行为,求出其他对象在2进制下向右移当前对象位后的值,并返回移位后的新值。
class Number:
def __init__(self, number):
self.number = number
def __rrshift__(self, other):
return other >> self.number
number1 = Number(3)
print(8 >> number1) # 01000 >> 3 -> 01
number2 = Number(5)
print(2 >> number2) # 010 >> 5 -> 0
执行结果如下:
__rand__方法(按位与)
__rand__方法用来处理对象遇到&号时的行为,求出当前对象与其他对象在2进制下按位与运算后的值,并返回按位与后的新值。
class Number:
def __init__(self, number):
self.number = number
def __rand__(self, other):
return other & self.number
number1 = Number(3)
print(8 & number1) # 01000 & 00011 -> 00000
number2 = Number(5)
print(2 & number2) # 0010 & 0101 -> 0000
执行结果如下:
__ror__方法(按位或)
__ror__方法用来处理对象遇到|号时的行为,求出当前对象与其他对象在2进制下按位或运算后的值,并返回按位或后的新值。
class Number:
def __init__(self, number):
self.number = number
def __ror__(self, other):
return other | self.number
number1 = Number(3)
print(8 | number1) # 01000 | 00011 -> 01011
number2 = Number(5)
print(2 | number2) # 0010 | 0101 -> 0111
执行结果如下:
__rxor__方法(按位异或)
__rxor__方法用来处理对象遇到^号时的行为,求出当前对象与其他对象在2进制下按位异或运算后的值,并返回按位异或后的新值。
class Number:
def __init__(self, number):
self.number = number
def __rxor__(self, other):
return other ^ self.number
number1 = Number(3)
print(8 ^ number1) # 01000 | 00011 -> 01011
number2 = Number(5)
print(2 ^ number2) # 0010 | 0101 -> 0111
执行结果如下:
赋值运算
这里的赋值运算不包括=,是增量赋值运算。
__iadd__方法(+=)
__iadd__方法方法用来处理对象遇到+=号时的行为,求出当前对象与其他对象的和,并把相加结果赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __iadd__(self, other):
self.number += other
return self
number1 = Number(3)
number1 += 3
print(number1.number)
number2 = Number(-5)
number2 += 2
print(number2.number)
执行结果如下:
__isub__方法(-=)
__isub__方法用来处理对象遇到-号时的行为,求出当前对象与其他对象的差,并把相减结果赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __isub__(self, other):
self.number -= other
return self
number1 = Number(3)
number1 -= 3
print(number1.number)
number2 = Number(-5)
number2 -= 2
print(number2.number)
执行结果如下:
__imul__方法(*=)
__imul__方法用来处理对象遇到*号时的行为,求出当前对象与其他对象的积,并把相乘结果赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __imul__(self, other):
self.number *= other
return self
number1 = Number(3)
number1 *= 3
print(number1.number)
number2 = Number(-5)
number2 *= 2
print(number2.number)
执行结果如下:
__itruediv__方法(/=)
__itruediv__方法用来处理对象遇到/号时的行为,求出当前对象与其他对象的商,并把相除结果赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __itruediv__(self, other):
self.number /= other
return self
number1 = Number(3)
number1 /= 3
print(number1.number)
number2 = Number(-5)
number2 /= 2
print(number2.number)
执行结果如下:
__imod__方法(%=)
__imod__方法用来处理对象遇到%号时的行为,求出当前对象与其他对象整除的余数,并把余数赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __imod__(self, other):
self.number %= other
return self
number1 = Number(3)
number1 %= 3
print(number1.number)
number2 = Number(-5)
number2 %= 2
print(number2.number)
执行结果如下:
__ifloordiv__方法(//=)
__ifloordiv__方法用来处理对象遇到//号时的行为,求出当前对象与其他对象整除的商,并把商赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __ifloordiv__(self, other):
self.number //= other
return self
number1 = Number(3)
number1 //= 3
print(number1.number)
number2 = Number(-5)
number2 //= 2
print(number2.number)
执行结果如下:
__ipow__方法(**=)
__ipow__方法用来处理对象遇到**号时的行为,求出当前对象的n次方,并把幂运算的结果赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __ipow__(self, other):
self.number **= other
return self
number1 = Number(3)
number1 **= 3
print(number1.number)
number2 = Number(-5)
number2 **= 2
print(number2.number)
执行结果如下:
__ilshift__方法(<<=)
__ilshift__方法用来处理对象遇到<<=号时的行为,求出当前对象在2进制下向左移n位后的值,并把移位后的新值赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __ilshift__(self, other):
self.number <<= other
return self
number1 = Number(3)
number1 <<= 3 # 011 <<= 3 -> 011000
print(number1.number)
number2 = Number(-5)
number2 <<= 2 # 1101 -> 1010 -> 1011 <<= 2 -> 101100 -> 110011 -> 110100
print(number2.number)
执行结果如下:
__irshift__方法(>>=)
__irshift__方法用来处理对象遇到>>=号时的行为,求出当前对象在2进制下向右移n位后的值,并把移位后的新值赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __irshift__(self, other):
self.number >>= other
return self
number1 = Number(3)
number1 >>= 3 # 011 >>= 3 -> 0
print(number1.number)
number2 = Number(-5)
number2 >>= 2 # 1101 -> 1010 -> 1011 >>= 2 -> 10 -> 11 -> 110
print(number2.number)
执行结果如下:
__iand__方法(&=)
__iand__方法用来处理对象遇到&=号时的行为,求出当前对象与其他对象在2进制下按位与运算后的值,并把按位与后的新值赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __iand__(self, other):
self.number &= other
return self
number1 = Number(3)
number1 &= 3 # 011 &= 011 -> 011
print(number1.number)
number2 = Number(-5)
number2 &= 2 # 1101 -> 1010 -> 1011 &= 0010 -> 0010
print(number2.number)
执行结果如下:
__ior__方法(|=)
__ior__方法用来处理对象遇到|=号时的行为,求出当前对象与其他对象在2进制下按位或运算后的值,并把按位或后的新值赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __ior__(self, other):
self.number |= other
return self
number1 = Number(3)
number1 |= 3 # 011 |= 011 -> 011
print(number1.number)
number2 = Number(-5)
number2 |= 2 # 1101 -> 1010 -> 1011 |= 0010 -> 1011 -> 1100 -> 1101
print(number2.number)
执行结果如下:
__ixor__方法(^=)
__ixor__方法用来处理对象遇到^=号时的行为,求出当前对象与其他对象在2进制下按位异或运算后的值,并把按位异或后的新值赋值给当前对象,最后返当前对象。
class Number:
def __init__(self, number):
self.number = number
def __ixor__(self, other):
self.number ^= other
return self
number1 = Number(3)
number1 ^= 3 # 011 ^= 011 -> 000
print(number1.number)
number2 = Number(-5)
number2 ^= 2 # 1101 -> 1010 -> 1011 ^= 0010 -> 1001 -> 1110 -> 1111
print(number2.number)
执行结果如下:
成员运算
成员运算就是in和not in两个运算,判断某个对象是否存在于某个序列中。
__contains__方法
__contains__方法用来处理对象遇到in和not in两个运算符时,判断当前对象是否包含其他对象。
class List:
def __init__(self, list_):
self.list = list_
def __contains__(self, item):
return item in self.list
list1 = List([1, 2, 3, 4, 5])
print(1 in list1)
print(6 in list1)
print(-1 not in list1)
print(2 not in list1)
执行结果如下:
属性相关
当我们想设置、访问、获取、对象的属性时,就会调用跟属性相关的魔法方法。
__getattribute__方法
__getattribute__方法是在访问对象属性时第一个调用的方法,用来判断要访问的属性是否存在。如果存在,直接返回属性的值;如果不存在,调用__getattr__方法。通常我们不会自定义__getattribute__方法,而是直接使用父类或者object的__getattribute__方法。千万不要在__getattribute__中访问对象的属性(self.xxx),不然可能会出现无限递归。
class Person:
def __init__(self, name, sex, age):
self.name = name
self.__sex = sex
self.__age = age
def __getattribute__(self, item):
print('__getattribute__')
print(item)
return super().__getattribute__(item)
person1 = Person('小明', '男', 18)
print(person1.name)
执行结果如下:
__getattr__方法
__getattr__方法是在访问对象属性时,要访问的属性不存在会调用的方法,用来决定是返回默认值,还是给出提醒,还是直接报错。使用getattr函数访问对象属性时,也会调用__getattr__方法。千万不要在__getattr__中访问对象未知的属性(self.xxx),不然可能会出现无限递归。如果你希望后面可以继续使用当前对象,__getattr__方法必须返回当前对象(self)。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __getattribute__(self, item):
print('__getattribute__')
print(item)
return super().__getattribute__(item)
def __getattr__(self, item):
print('__getattr__')
return item
person1 = Person('小明', '男', 18)
print(person1.height)
执行结果如下:
__setattr__方法
__setattr__方法用来设置对象属性的值,当我们给对象的属性设置值时就会调用__setattr__方法。使用setattr函数给对象设置属性值时,也会调用__setattr__方法。__dict__是object中规定用来存放对象属性的字典,我们在__setattr__方法中需要用到对象的__dict__来存放属性和值。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __setattr__(self, key, value):
print(key, value)
self.__dict__[key] = value
person1 = Person('小明', '男', 18)
person1.height = 170
print(person1.height)
执行结果如下:
__delattr__方法
__delattr__方法用来删除对象的属性,当我们使用del函数或delattr函数删除对象的属性时,会调用__delattr__方法。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __delattr__(self, item):
print('__delattr__')
print(item)
del self.__dict__[item]
person1 = Person('小明', '男', 18)
person1.height = 170
print(person1.height)
del person1.height
执行结果如下:
__call__方法
__call__方法可以把对象的属性当作方法来执行,__call__通常和__getattr__联合在一起使用。把一些未知的属性按照方法执行,这个功能非常的秀,只要思想不滑坡,你甚至可以玩出花来。我们常用的函数和方法对象就是因为定义了__call__方法,所以它们才能被执行。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
self.func = None
def __getattr__(self, item):
self.func = item
return self
def __call__(self, *args, **kwargs):
if self.func == 'information':
return self.__information()
print(args, kwargs)
def __information(self):
print(f'姓名: {self.__name}\n性别: {self.__sex}\n年龄: {self.__age}')
person1 = Person('小明', '男', 18)
person1.information()
person1.height('身高', tal=170)
执行结果如下:
描述符
描述符是用来代理类的属性的,我们可以在描述符中设计被代理属性的值,达到数据校验等目的。描述符只能描述类属性,不能描述实例属性,如果你有使用property的经验,那你应该对这种机制比较熟悉。
__get__方法
__get__方法用于访问被代理属性的值,当我们访问对象的被代理属性时,会调用__get__方法返回被代理属性的值。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __get__(self, instance, owner):
print('__get__')
if type(instance) == NameSystem:
return f'{self.__name}'
elif type(instance) == SexSystem:
return f'{self.__sex}人'
else:
raise TypeError
class NameSystem:
person = Person('小明', '男', 18)
class SexSystem:
person = Person('小明', '男', 18)
name_system = NameSystem()
print(name_system.person)
sex_system = SexSystem()
print(sex_system.person)
执行结果如下:
__set__方法
__set__方法用于设置被代理属性的值,当我们设置对象的被代理属性时,会调用__set__方法设置被代理属性的值。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __set__(self, instance, value):
print('__set__')
if type(instance) == NameSystem:
self.__name = value
print(self.__name)
elif type(instance) == SexSystem:
self.__sex = value
print(self.__sex)
else:
raise TypeError
class NameSystem:
person = Person('小明', '男', 18)
class SexSystem:
person = Person('小明', '男', 18)
name_system = NameSystem()
name_system.person = '李梅'
sex_system = SexSystem()
sex_system.person = '女'
执行结果如下:
__delete__方法
__delete__方法用于删除被代理属性的值,当我们删除对象的被代理属性时,会调用__delete__方法删除被代理属性的值。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
def __delete__(self, instance):
print('__delete__')
if type(instance) == NameSystem:
del self.__name
print(self.__dict__)
elif type(instance) == SexSystem:
del self.__sex
print(self.__dict__)
else:
raise TypeError
class NameSystem:
person = Person('小明', '男', 18)
class SexSystem:
person = Person('小明', '男', 18)
name_system = NameSystem()
del name_system.person
sex_system = SexSystem()
del sex_system.person
执行结果如下:
容器类方法
像字符串、列表、元组、字典、集合这种类型就属于容器类,它们内部可以容纳多个其他对象,并且有的还可以实现对元素的增删改查。
__len__方法
__len__方法可以返回容器类对象的长度(元素个数),当容器类对象被len函数使用时,会调用__len__方法。
class Container:
def __init__(self, container):
self.container = container
def __len__(self):
return len(self.container)
str1 = Container('abcdef')
print(len(str1))
list1 = Container([1, 2, 3])
print(len(list1))
执行结果如下:
__getitem__方法
__getitem__方法可以通过下标索引值获取对应元素,当我们使用[n]下标索引来获取容器类对象的元素时,会调用__getitem__方法。
class Container:
def __init__(self, container):
self.container = container
def __getitem__(self, item):
return self.container[item]
str1 = Container('abcdef')
print(str1[1])
list1 = Container([1, 2, 3])
print(list1[1])
执行结果如下:
__setitem__方法
__setitem__方法可以通过元素下标索引值来设置对应元素的值,当我们使用[n]下标索引来设置容器类对象的元素的值时,会调用__setitem__方法。
class Container:
def __init__(self, container):
self.container = container
def __setitem__(self, key, value):
self.container[key] = value
def __str__(self):
return f'{self.container}'
dict1 = Container({'name': '小明', 'sex': '男', 'age': 18})
dict1['name'] = '爆笑蛙'
print(dict1)
list1 = Container([1, 2, 3])
list1[1] = 5
print(list1)
执行结果如下:
__delitem__方法
__delitem__方法可以通过元素下标索引值来删除对应元素,当我们使用[n]下标索引来删除容器类对象的元素时,会调用__delitem__方法。
class Container:
def __init__(self, container):
self.container = container
def __delitem__(self, key):
del self.container[key]
def __str__(self):
return f'{self.container}'
dict1 = Container({'name': '小明', 'sex': '男', 'age': 18})
del dict1['name']
print(dict1)
list1 = Container([1, 2, 3])
del list1[1]
print(list1)
执行结果如下:
__reversed__方法
__reversed__方法可以反转容器类对象元素的顺序,容器类对象被reversed函数使用时,会调用__reversed__方法。
class Container:
def __init__(self, container):
self.container = container
def __reversed__(self):
if type(self.container) == dict:
return {key: self.container[key] for key in reversed(self.container)}
elif type(self.container) == list:
return self.container[::-1]
else:
raise TypeError
def __str__(self):
return f'{self.container}'
dict1 = Container({'name': '小明', 'sex': '男', 'age': 18})
print(reversed(dict1))
list1 = Container([1, 2, 3])
print(reversed(list1))
执行结果如下:
__missing__方法
__missing__方法在字典的子类中使用,当用键[key]取访问字典的子类实例中不存在的键时,会调用__missing__方法。
class Container(dict):
def __missing__(self, key):
raise KeyError(f'key {key} not exists')
dict1 = Container({'name': '小明', 'sex': '男', 'age': 18})
print(dict1['height'])
执行结果如下:
迭代器
我们知道可迭代对象可以被迭代,那它能被迭代的原理是什么呢?因为可迭代对象中有__iter__方法,当我们想迭代一个对象时,会调用对象的__iter__方法返回迭代器。如果这个对象没有定义__iter__方法,那它就不是一个可迭代对象。那迭代器又是什么呢?迭代器对象中同时拥有__iter__方法和__next__方法。__next__方法用于迭代迭代器,当迭代器被next函数使用时,会调用迭代器中的__next__方法来返回迭代出来的值。所以迭代器的原理就是使用__iter__方法返回自己,使用__next__方法迭代自己。
__iter__方法
__iter__方法用来返回迭代器,当容器类对象被iter函数使用时,会调用__iter__方法。
class Iter:
def __iter__(self):
return iter([1, 2, 3]) # 借助iter()把可迭代对象变成迭代器
iter_ = Iter()
print(iter(iter_))
for i in iter_:
print(i)
执行结果如下:
__next__方法
__next__方法用来迭代迭代器,当前对象被next函数使用时,会调用__next__方法返回迭代值。为了避免无限迭代,我们需要设置迭代条件,满足条件才迭代,不满足条件时我们要抛出StopIteration错误来终止迭代。至于为什么是抛出StopIteration错误,是因为for循环中是通过捕获StopIteration错误来停止迭代的。如果我们定义的迭代器想要被for循环使用,就必须是抛出StopIteration错误。
class Iter:
number = 1
def __next__(self):
if self.number <= 3:
iter_value = self.number
self.number += 1
return iter_value
raise StopIteration
iter_ = Iter()
print(next(iter_))
print(next(iter_))
print(next(iter_))
print(next(iter_))
执行结果如下:
__iter__ & __next__
__next__和__iter__经常联合在一起使用,__iter__返回对象本身,__next__迭代对象本身,当前对象就变成了一个迭代器。
class Iter:
def __init__(self, number):
self.number = number
self.index = 0
def __iter__(self):
return self # 返回实例对象本身
def __next__(self):
if self.number > self.index: # 通过实例属性控制迭代次数
iter_value = self.index
self.index += 1
return iter_value
raise StopIteration
for i in Iter(5):
print(i)
执行结果如下:
__aiter__方法
__aiter__方法同样是用来返回迭代器的,只不过__aiter__用于python的异步编程中,感兴趣的话可以去看一下python的异步编程。__aiter__方法不能单独使用,必须结合__anext__方法。
__anext__方法
__anext__方法同样是用来迭代迭代器的,只不过__anext__用于python的异步编程,结束迭代时抛出StopAsyncIteration错误。__anext__不能单独使用,必须结合__aiter__方法。
__aiter__ & __anext__
__aiter__方法和__anext__方法联合在一起就可以在python的异步编程中定义迭代器了。
import asyncio
class Iter:
def __init__(self, number):
self.number = number
self.index = 0
def __aiter__(self):
return self
async def __anext__(self):
if self.number > self.index:
iter_value = self.index
self.index += 1
return iter_value
raise StopAsyncIteration
async def main(number):
iter_ = Iter(number)
async for i in iter_:
print(i)
asyncio.run(main(5))
执行结果如下:
上下文管理
上下文管理是一种用来管理资源的机制,在使用资源前打开资源,在资源使用完成后关闭资源,如果在使用资源的过程中报错,也会捕获错误并关闭资源,是一种安全使用资源的方式。上下文管理with语句。
__enter__方法
__enter__方法用于上下文管理中打开资源的步骤,当对象被with语句使用时,打开资源的步骤由__enter__方法完成。
__exit__方法
__exit__方法用于上下文管理中关闭资源的步骤,当对象被with语句使用时,关闭资源的步骤由__exit__方法完成。如果出现报错,__exit__中能接收到错误的类型、错误的值、错误的位置,我们可以打印出这些信息方便查看。在出现报错的情况下__exit__方法返回True时,会继续执行with语句后面的代码;返回False时,会抛出错误停止执行代码。
class Context:
def __enter__(self):
print('打开资源')
def __exit__(self, exc_type, exc_val, exc_tb):
print('关闭资源')
print(f'错误类型: {exc_type}')
print(f'错误值: {exc_val}')
print(f'错误位置: {exc_tb}')
return False
with Context() as context:
print('使用资源')
print(1 / 0)
print('with后面的语句')
执行结果如下:
__aenter__方法
__aenter__方法同样用于上下文管理中打开资源的步骤,只不过__aenter__用于python的异步编程。
__aexit__方法
__aexit__方法同样用于上下文管理中关闭资源的步骤,只不过__aexit__用于python的异步编程。如果出现报错,__aexit__中能接收到错误的类型、错误的值、错误的位置,我们可以打印出这些信息方便查看。在出现报错的情况下__aexit__方法返回True时,会继续执行with语句后面的代码;返回False时,会抛出错误停止执行代码。
import asyncio
class Context:
async def __aenter__(self):
print('打开资源')
async def __aexit__(self, exc_type, exc_val, exc_tb):
print('关闭资源')
print(f'错误类型: {exc_type}')
print(f'错误值: {exc_val}')
print(f'错误位置: {exc_tb}')
return True
async def main():
async with Context() as f:
print('使用资源')
print(1 / 0)
print('with后面的语句')
asyncio.run(main())
执行结果如下:
类型转换
有一些类型转换的魔法方法,定义了它们之后就可以被转换为其他类型的数据,例如整型转字符串、字符串转整型。
__int__方法
__int__方法在遇到int函数时把对象转换为整型,返回一个整数。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
self.func = None
def __int__(self):
return self.__age
person1 = Person('小明', '男', 18)
age = int(person1)
print(age)
执行结果如下:
__float__方法
__float__方法在遇到float函数时把对象转换为浮点型,返回一个小数。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
self.func = None
def __float__(self):
return self.__age / 1.0
person1 = Person('小明', '男', 18)
age = float(person1)
print(age)
执行结果如下:
__long__方法
__long__方法在遇到long函数时把对象转换为长整型,返回一个长整型。但是python3中没有long这种数据类型了,只有int类型,所以__long__在python3中没用。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
self.func = None
def __long__(self):
return self.__age
person1 = Person('小明', '男', 18)
age = person1.__long__()
print(age)
执行结果如下:
__complex__方法
__complex__方法在遇到complex函数时把对象转换为复数类型,返回一个复数。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
self.func = None
def __complex__(self):
return self.__age + 0j
person1 = Person('小明', '男', 18)
age = complex(person1)
print(age)
执行结果如下:
__oct__方法
__oct__方法能把对象转换为8进制数,但没有具体的调用方法。oct函数只能把整型转换为8进制数,它在转换之前首相会检查对象是不是整型,所以__oct__也很尴尬。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
self.func = None
def __oct__(self):
result = ''
number = self.__age
while number >= 8:
result = str(number % 8) + result
number = number // 8
result = '0o' + str(number) + result
return result
person1 = Person('小明', '男', 18)
age = person1.__oct__()
print(age)
执行结果如下:
__hex__方法
__hex__方法能把对象转换为16进制数,但没有具体的调用方法。hex函数只能把整型转换为16进制数,它在转换之前首相会检查对象是不是整型,所以__hex__也很尴尬。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
self.func = None
def __hex__(self):
result = ''
number = self.__age
while number >= 16:
result = str(number % 16) + result
number = number // 16
result = '0x' + str(number) + result
return result
person1 = Person('小明', '男', 18)
age = person1.__hex__()
print(age)
执行结果如下:
__index__方法
__index__方法用于当前对象被当作索引下标使用时,会调用__index__方法返回一个整型来作为索引下标。
class Person:
def __init__(self, name, sex, age):
self.__name = name
self.__sex = sex
self.__age = age
self.func = None
def __index__(self):
return 1
person1 = Person('小明', '男', 18)
list1 = [1, 2, 3, 4, 5]
print(list1[person1])
执行结果如下:
序列化
序列化是python中用于把对象存储到文件中,和从文件中生成对象的机制。通过序列化,我们可以动态生成对象,还可以在生成对象时重新定义对象的属性和值。pickle是专门用来序列化对象的模块,pickle中的dump函数可以把对象序列化后保存到文件中,pickle中的load函数可以把序列化文件中的数据取出来创建新对象。
__getnewargs__方法
__getnewargs__方法用于返回对象的属性,返回的属性会被保留到序列化文件中。pickle中的dump函数在序列化对象时,会调用__getnewargs__方法返回要保存的属性。pickle中的load函数在生成对象时,会把__getnewargs__方法返回的属性传给__new__方法,我们可以在__new__中定义实例的属性。
__getstate__方法
__getstate__方法用于返回对象属性的值,返回的值会被保留到序列化文件中。pickle中的dump函数在序列化对象时,会调用__getstate__方法返回要保存的值。pickle中的load函数在生成对象时,会把__getstate__方法返回的值直接赋给对象的属性,并不会调用__init__来初始化对象。
__setstate__方法
__setstate__方法用于初始化对象的属性值,会把序列化文件中的值赋值给对象的属性。pickle中的load函数在生成对象时,会调用__setstate__方法给对象的属性赋值,而不是用__init__来给对象赋值。(__setstate__代替了__init__)
序列化实例
import pickle
class Person:
def __new__(cls, *args, **kwargs):
print('使用__new__创建实例')
print(args, kwargs)
instance = super().__new__(cls)
if 'name' in args:
instance.__dict__ = {key: None for key in args}
return instance
def __init__(self, name, sex, age):
print('使用__init__初始化')
self.__name = name
self.__sex = sex
self.__age = age
def __getnewargs__(self):
print('使用__getnewargs__返回属性')
return 'name', 'sex', 'age'
def __getstate__(self):
print('使用__getstate__返回值')
return self.__name, self.__sex, self.__age
def __setstate__(self, state):
print('使用__setstate__初始化')
index = 0
for i in self.__dict__:
self.__dict__[i] = state[index]
index += 1
person = Person('小明', '男', 18)
print(person.__dict__)
print('保存对象到序列化文件')
with open('Person.txt', 'wb') as f:
pickle.dump(person, f)
print('使用序列化文件创建新对象')
with open('Person.txt', 'rb') as f:
new = pickle.load(f)
print(new.__dict__)
执行结果如下: