python魔法方法详解

魔法方法概念

        在面向对象编程时,需要创建一个个对象,我们要用一些底层的方法来描述对象。使我们创建的对象在遇各种运算符、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__)

执行结果如下:

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值