魔法方法
魔法方法是python十分强大的一个特性,他允许我们自定义类的行为,从而实现各种功能,只要实现了对应的魔法方法,那么在进行指定的操作时,python解释器就会自动去调用这些方法,这些方法一般都是以双下划线__
开头和结尾。
(魔法方法也可以看做是一种python协议,其和类本身没有关系,他是python解释器可以直接调用的方法)
使用注意
魔法方法是针对于类对象的方法特性,python虚拟机在对一个实例对象进行指定操作时,会去寻找其对应的类对象上是否存在对应的魔法方法,从而调用该方法,举例:
def call(self):
print(self, "调用")
class A:
__call__ = call
class B: pass
class C: pass
a = A()
a()
b = B()
# 往类对象上添加__call__魔法方法
B.__call__ = call
# 调用成功
b()
c = C()
# 往实例对象上添加
c.__call__ = call
# 这里会调用失败
c()
# <__main__.A object at 0x0000013F1E9AA588> 调用
# <__main__.B object at 0x0000013F1EC347B8> 调用
# TypeError: 'C' object is not callable
基本魔法方法
字符串展示相关
__repr__(self)
原始字符串展示,当直接展示对象时,会隐式调用该方法,行为:obj/repr(obj)
,举例:
class A:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"class: A, name: {self.name}"
a = A("aaa")
print(a)
# class: A, name: aaa
在交互式环境中(如idle、jupyter里,直接输入a
,那么也是默认调用repr
进行展示)
__str__(self)
字符串展示,例如调用print
或str
方法时都会首先去寻找该方法,如果没找到,则会寻找__repr__
方法,行为:str(obj)
,举例:
class A:
def __init__(self, name):
self.name = name
def __str__(self):
return f"str - name:{self.name}"
class B:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"repr - name:{self.name}"
print(A(1))
print(B(2))
# str - name:1
# repr - name:2
__repr__
/__str__
区别
- 调用方法不同:两个分别有对应的调用方法-
repr()
/str()
,而一些函数也会隐式地去调用对应的方法,举例:
class A: pass
a = A()
print(a)
# 等价于:print(str(a))/print(a.__str__())
a
# 等价于:a.__repr__()/repr(a)
- 依赖关系不同:如果找不到
__str__
则会寻找__repr__
,反之则不会 - 展示目标不同:
__repr__
主要用于转成更底层的格式供开发人员使用,__str__
主要用于简单的用户展示
repr/str区别参考:
https://blog.csdn.net/kongsuhongbaby/article/details/87398394
https://blog.csdn.net/Watkins_OS/article/details/100042680
__format__(self, formatstr)
格式化对象时的行为,行为:format(obj, formatstr)
,举例:
class A:
def __init__(self):
self.s = "A"
def __format__(self, formatstr):
return self.s * int(formatstr)
# 根据传入的数字决定返回的字符串
a = A()
print(format(a, "10"))
# 将a类转成字符串,并复制10次
# AAAAAAAAAA
集合/序列相关
__len__(self)
定义当被len()
调用时的行为(返回容器中元素的个数),例如我们可以通过重写该方法实现一个自定义的list
,其在计算长度时会将嵌套列表的长度也算进去,举例:
class mlist(list):
def __len__(self):
mylen = 0
for each in self:
if isinstance(each, list):
mylen += len(mlist(each))
else:
mylen += 1
return mylen
li = [1,2,3,[4,5,6,[7,8,9]]]
mli = mlist(li)
print(len(li), len(mli))
# 4 9
__getitem__(self, key)
定义获取容器中指定元素的行为,行为:obj[key]
,举例:
class A:
def __getitem__(self, key):
return "value:" + str(key)
a = A()
print(a[0])
# value:0
注:
python内部为我们做了很多的优化,例如for
循环的会先寻找该类是否实现了__iter__
和__next__
方法,如果没有,还回去寻找是否实现了__getitem__
方法,如果有,则会传入数字尝试是否能够进行迭代,举例:
class A:
def __init__(self):
self.data = [1, 2, 3]
def __getitem__(self, item):
return self.data[item]
for each in A():
print(each)
# 没有实现__iter__方法也能进行迭代
__setitem__(self, key, value)
定义设置容器指定元素的行为,行为:obj[key] = value
,举例:
class A:
def __init__(self):
self.name = None
self.age = None
def __setitem__(self, key, value):
self.name = key
self.value = value
def __str__(self):
return "{}:{}".format(self.name, self.value)
a = A()
a["xxx"] = 100
print(a)
# xxx:100
__delitem__(self, key)
定义删除容器中指定元素的行为,行为:del obj[key]
,举例:
class A:
def __init__(self):
self.data = [1, 2, 3]
def __delitem__(self, key):
self.data.pop(key)
def __str__(self):
return str(self.data)
a = A()
del a[1]
print(a)
# [1, 3]
注:
如果要定义不可变容器就只用定义__len__
、__getitem__
两个方法,如果要定义的是可变的还得定义__setitem__
、__delitem__
__contains__(self, key)
判断是否存在,行为:key in obj
,举例:
class A:
def __init__(self):
self.data = [1, 2, 3]
def __contains__(self, key):
return key in self.data
a = A()
print(10 in a)
__reversed__(self)
定义被调用reversed
方法时的行为,行为:reversed(obj)
,举例:
class A(list):
def __reversed__(self):
print("取反操作")
self.reverse()
return self
a = A([1,2, 3])
print(reversed(a))
# 取反操作
# [2, 3, 1]
__missing__(self, key)
定义访问不存在的key
时的行为,行为:obj[key]
(key
不存在),举例:
class A(dict):
def __missing__(self, key):
print(f"key:{key}不存在,默认返回0!")
return 0
a = A({"x": 1, "y": 2})
print(a["z"])
# key:z不存在,默认返回0!
# 0
迭代相关
__iter__(self)
返回一个迭代器,行为:iter(obj)
,而迭代器类必须要先实现__iter__
和__next__
这两个魔法方法,举例:
class A:
def __init__(self):
self.data = [1, 2, 3]
self.index = 0
def __iter__(self):
return self
def __next__(self):
self.index += 1
return self.data[self.index - 1]
a = A()
ia = iter(a)
print(next(a))
print(next(a))
print(next(a))
print(next(a))
__next__(self)
决定了迭代器的迭代规则,行为:next(obj)
,举例实现斐波那契数列:
class A:
def __init__(self, n=10):
self.a = 0
self.b = 1
self.n = n
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > self.n:
raise StopIteration
return self.a
a = A()
for each in a:
print(each,end=' ')
# 1 1 2 3 5 8
注:
for
循环实质就是将数据转成迭代器进行迭代输出,当接收到StopIteration
异常时结束迭代,我们可以简单模拟for
行为:
class A:
def __init__(self):
self.data = [1, 2, 3]
self.index = 0
def __iter__(self):
return self
def __next__(self):
self.index += 1
if self.index > len(self.data):
raise StopIteration
return self.data[self.index - 1]
def fake_for(data):
"""模拟for"""
while True:
i = iter(data)
try:
print(next(i))
except StopIteration:
break
fake_for(A())
调用相关
__call__(self)
将该对象当成函数调用时执行,行为:obj()
,举例:
class A:
def __call__(self):
print('1')
a = A()
a()
# 1
上下文管理器相关
__enter__(self)
实现了该__enter__
和__exit__
方法,就可以把当前类当做上下文管理器来使用(可以使用with
关键字来进行处理),该方法定义了进入上下文时的操作,其中__enter__
的返回值将会提供给with xxx as yyy
的yyy
__exit__(self, exc_type, exc_value, traceback)
定义了离开上下文时的操作,接收的几个参数是在上下文执行期间出现的异常,和上面的结合举例:
class A:
def __enter__(self):
print("enter...")
return self
def do(self):
print("context do")
def __exit__(self, exc_type, exc_value, traceback):
print("exit...")
with A() as a:
a.do()
print("do something...")
# enter...
# context do
# do something...
# exit...
当上下文中出现异常时,在__exit__
中返回True
则不会向外抛异常,否则向上一层抛出异常,举例:
class A:
def __enter__(self):
print("enter...")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("exit...")
# 如果不返回True,就会将异常向上抛出
return True
with A() as a:
raise
# enter...
# exit...
更多参考:https://blog.csdn.net/mydistance/article/details/86553431
类型转换相关
__bytes__(self)
转字节值时操作,行为:bytes(obj)
,必须返回bytes
类型,举例:
class A:
def __bytes__(self):
return b"1"
a = A()
print(bytes(a))
# b'1'
__bool__(self)
转布尔值时操作,行为:bool(obj)
__int__(self)
转整数值时操作,行为:int(obj)
__float__(self)
转浮点数时操作,行为:float(obj)
__complex__(self)
转复数时操作,行为:complex(obj)
__hash__(self)
转哈希值时操作,行为:hash(obj)
__oct__(self)
转八进制时操作,行为:oct(obj)
__hex__(self)
转十六进制时操作,行为:hex(obj)
__index__(self)
当一个类被用作索引/切片时调用,必须返回int
类型,举例:
class A:
def __init__(self, x):
self.x = x
def __index__(self):
return self.x
a1 = A(1)
a2 = A(3)
li = ['a', 'b', 'c']
print(li[a1])
print(li[a1:a2])
# b
# ['b', 'c']
可以看出A类被当做索引/切片时,会自动转成int
类型,从而可以索引
元类相关
__new__(cls[, ...])
实例化时第一个被调用的方法,接收的是需要进行实例化的类,其定义了实例化返回的内容,一般必须返回一个实例化对象,举例:
class A:
def __new__(cls):
print(cls)
return super().__new__(cls)
a = A()
print(a)
# <class '__main__.A'>
# <__main__.A object at 0x000001F27B7594A8>
下面一种是错误的示范:
class ABC:
def __new__(cls, string):
string = string.upper() #把字符串全变成大写
return string
a = ABC('abc')
print(a) #ABC
此时实例化返回的是个str,虽然可以执行,但并不是正确的用法,比如上面这个返回对象被改成了str类型,所以a已经不是之前的类了,所以对应的__init__
等方法也不会执行了,举例:
class ABC:
def __new__(cls,string):
string = string.upper() #把字符串全变成大写
return string
def __init__(self, x):
print(x)
a = ABC('abc')
有时候如果我们想在分配空间实例化之前执行一些代码的话也可以像下面这样重写:
class My_dict(dict):
def __new__(self, name):
print("分配一个空间给自定义字典:", name)
return super().__new__(self)
# 因为是继承于dict类,所以使用dict类的__new__方法
# 并且实例化的参数不需要在方法中传入,其会自动传入,只需传入对象本身即可
def __init__(self, name):
print("自定义字典:{},创建成功!".format(name))
my_dict = My_dict("aaa")
print(type(my_dict))
__init__(self[, param1, param2, ...])
初始化方法,实例化后初始化时被调用,接收的是实例化后的对象,举例:
class ABC:
def __init__(self,name):
self.name = name
print(name)
abc = ABC('aaa')
注:
__init__
方法返回的必须是None
,否则无法成功初始化。因此像下面这种是不被允许的:
class ABC:
def __init__(self):
return 0
abc = ABC()
#TypeError: __init__() should return None, not 'int'
__del__(self)
当对象被销毁时调用,举例:
class A:
def __init__(self, name):
self.name = name
print("create {}...".format(self.name))
def __del__(self):
print("delete {}...".format(self.name))
a = A("a")
del a
print("...")
注:
该方法在对象被真正销毁的时候才会调用,并不是执行del obj
就会调用,因为python内部的垃圾回收机制中使用了引用计数,而del
语句只是将计数值减一,只有计数值为0的时候,才会调用__del__
方法,举例:
class A:
def __init__(self, name):
self.name = name
print("create {}...".format(self.name))
def __del__(self):
print("delete {}...".format(self.name))
a = A("a")
b = a
del a
print("...")
del b
print("...")
# create a...
# ...
# delete a...
# ...
可以看出a和b同时指向同一个对象,此时引用计数为2,当删除a以后,计数变成1,再删除b以后,计数变为0,才执行了对应的魔法方法
属性相关
__getattr__(self, name)
当试图获取对象中不存在的属性时调用,行为:obj.attr
/getattr(obj, name)
,举例:
class A:
def __init__(self, val):
self.val = val
def __getattr__(self, name):
print("{}属性不存在".format(name))
a = A("a")
print(a.val)
print(a.xxx)
# a
# xxx属性不存在
# None
使用场景:
- 属性大小写通配,举例:
class A:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
return getattr(self, item.lower())
# 当没找到属性名的时候,则将属性名转小写继续查找
a = A("xxx")
print(a.Name)
# xxx
- 返回内部维护的属性,举例:
class A:
_attr = {}
def __init__(self, name):
self._attr["name"] = name
def __getattr__(self, item):
return self._attr.get(item)
# 当没找到属性名的时候,则进入内部维护的字典当中查找
a = A("xxx")
print(a.name)
# xxx
- 实现能够以属性方式获取字典内部值的字典,举例:
class Mydict(dict):
def __getattr__(self, name):
return self[name]
a = Mydict()
a["x"] = 1
print(a.x)
# 1
__setattr__(self, name, value)
当一个属性被设置时调用,行为:obj.attr = val
/setattr(obj, name, val)
,举例:
class A:
def __setattr__(self, name, value):
print("设置属性:{}".format(name))
super().__setattr__(name, value)
a = A()
a.x = 1
print(a.x)
# 设置属性:x
# 1
注:
使用属性相关的魔法方法时要小心无限递归问题:例如__setattr__
在设置属性时会被调用,假如自定义的__setattr__
方法里也有设置属性值的操作时,可能就会无限递归调用自己,错误举例:
class A:
def __setattr__(self, name, value):
self.x = value # 在设置属性的魔法方法里设置属性
a = A()
a.x = 1 #此时就会无限循环报错
- 解决方法1:
class A:
def __setattr__(self, name, value):
super().__setattr__(name, value) # 调用基类的__setattr__
# object.__setattr__(self, name, value) # 两种本质都是一样的
使用这种方式之所以不会造成无限递归是因为调用的是基类的__setattr__
方法,因此当前类中的该方法并不会被触发,举例:
class A:
def __init__(self):
# object.__setattr__(self, "data", 1)
super().__setattr__("data", 1)
# 上面两个都等价于:self.data = 1,并且不会触发到当前类的__setattr__方法
def __setattr__(self, name, value):
self.data = 2
a = A()
print(a.data)
# 1
可以看到并没有触发当前类的__setattr__
方法(否则结果为2)
- 解决方法2:
class A:
def __setattr__(self, name, value):
super().__dict__[name] = value #这句改成从类字典里(管理该类的属性)设置即可
__delattr__(self, name)
当一个属性被删除时调用,行为:del obj.attr
/delattr(obj, name)
,举例:
class A:
def __init__(self):
self.x = 1
def __delattr__(self, name):
print("删除属性:{}".format(name))
super().__delattr__(name)
a = A()
print(a.x)
delattr(a, "x")
# 1
# 删除属性:x
__getattribute__(self, name)
当该类的属性被访问时调用,不论属性存不存在都会调用,实际上在访问属性时都会先进入该方法,而该方法内部会对属性是否存在进行判断,如果不存在,就会在方法内部调用__getattr__
,举例:
class A:
def __init__(self):
self.x = 1
def __getattribute__(self, name):
print("访问属性:{}".format(name))
def __getattr__(self, name):
print("属性:{}不存在".format(name))
a = A()
print(a.x)
print(a.y)
# 访问属性:x
# None
# 访问属性:y
# None
可以看出这里我们访问不存在的属性y
,却没有进入__getattr__
方法,原因是我们重写了__getattribute__
,导致默认的该方法被覆盖,我们可以在里面添加自己的逻辑,然后再调用默认的__getattribute__
方法,举例:
class A:
def __init__(self):
self.x = 1
def __getattribute__(self, name):
print("访问属性:{}".format(name))
return object.__getattribute__(self, name)
def __getattr__(self, name):
print("属性:{}不存在".format(name))
a = A()
print(a.x)
print(a.y)
# 访问属性:x
# 1
# 访问属性:y
# 属性:y不存在
# None
__dir__(self)
获取类中所有属性调用,行为:dir(obj)
,举例:
class A:
def __init__(self):
self.x = 1
def __dir__(self):
print("获取所有属性")
return object.__dir__(self)
a = A()
print(dir(a))
# 获取所有属性
# ['__class__', ... '__weakref__', 'x']
__sizeof__(self)
对对象使用sys.getsizeof()
时调用,行为:sys.getsizeof(obj)
,举例:
import sys
class A:
def __init__(self):
self.data = 1
def __sizeof__(self):
return self.data.__sizeof__()
a = A()
print(sys.getsizeof(a))
# 52
属性描述符相关
__get__(self, instance, owner)
实现该方法的类能够控制属性的访问,它返回属性的值,此时另一个类中的属性调用实现了该方法的类,则可以对属性进行控制举例:
class Data:
def __init__(self):
self.x = 1
def __get__(self, instance, owner):
print(f"类:{owner.__name__}的对象-{instance}对{type(self).__name__}访问")
return self.x
# 访问A对象的data属性,返回的是Data对象的x属性
class A:
data = Data()
# A对象的data属性有Data类来控制
a = A()
print(a.data)
# 类:A的对象-<__main__.A object at 0x0000012801A9DCF8>对Data访问
# 1
__set__(self, instance, value)
控制属性修改操作,不返回任何值
__delete__(self, instance)
控制属性删除操作,不返回任何内容,三个属性描述符结合举例:
class Data:
def __init__(self):
self.x = 1
def __get__(self, instance, owner):
print(f"类:{owner.__name__}的对象-{instance}对{type(self).__name__}访问")
return self.x
def __set__(self, instance, value):
if value >= 100:
print("data必须小于100")
return
self.x = value
def __delete__(self, instance):
print("删除data")
class A:
data = Data()
# data属性的get/set/delete由Data类来控制
a = A()
print(a.data)
a.data = 10
print(a.data)
a.data = 1000
del a.data
# 类:A的对象-<__main__.A object at 0x00000220E6E0DCC0>对Data访问
# 1
# 类:A的对象-<__main__.A object at 0x00000220E6E0DCC0>对Data访问
# 10
# data必须小于100
# 删除data
实际上实现了这三个方法的类就算是property
描述符了(属性描述符内部本身也是实现了这三个魔法方法的装饰器),将上面代码使用属性描述符实现举例:
class A:
def __init__(self):
self.x = 1
@property
def data(self):
return self.x
# 用方法定义data,并将data当做属性使用,返回的是x的属性值
@data.setter
def data(self, val):
if val >= 100:
print("data必须小于100")
return
self.x = val
@data.deleter
def data(self):
print("删除data")
a = A()
print(a.data)
a.data = 10
print(a.data)
a.data = 1000
del a.data
# 1
# 10
# data必须小于100
# 删除data
反射相关
__instancecheck__(self, instance)
对当前对象使用isinstance(instance, class)
时调用,行为:isinstance(xxx, obj)
,此时会判断某个对象是否为当前对象的实例,返回的值会自动被转成布尔类型,举例:
class A:
def __instancecheck__(self, instance):
if isinstance(instance, (A, B)):
return 1
return 0
class B: pass
a = A()
b = B()
print(isinstance(a, a))
print(isinstance(b, a))
print(isinstance(1, a))
# True
# True
# False
__subclasscheck__(self, subclass)
对当前对象使用issubclass(subclass, class)
时调用,行为:issubclass(xxx, obj)
,此时会判断某个对象是否为当前对象的子类,返回的值会自动被转成布尔类型,举例:
class A:
def __subclasscheck__(self, subclass):
if issubclass(subclass, (A, B)):
return 1
return 0
class B: pass
a = A()
print(issubclass(A, a))
print(issubclass(B, a))
# True
# True
拷贝相关
__copy__(self)
对当前对象使用copy.copy()
时调用,行为:copy.copy(obj)
,返回浅拷贝的对象,举例:
from copy import copy
class A:
def __init__(self, data):
self.data = data
def __copy__(self):
return type(self)(self.data[:])
a = A([1,2,[3]])
print(a.data)
b = copy(a)
b.data[2][0] = 100
print(a.data)
# [1, 2, [3]]
# [1, 2, [100]]
__deepcopy__(self, memodict={})
对当前对象使用copy.deepcopy()
时调用,行为:copy.deepcopy(obj)
,返回深拷贝的对象,举例:
from copy import deepcopy
class A:
def __init__(self, data):
self.data = data
def __deepcopy__(self, memodict):
return type(self)(deepcopy(self.data))
a = A([1,2,[3]])
print(a.data)
b = deepcopy(a)
b.data[2][0] = 100
print(a.data)
# [1, 2, [3]]
# [1, 2, [3]]
序列化相关
__getstate__(self)
将对象序列化成字节,行为:pickle.dump(file, obj)/pickle.dumps(obj)
,序列化默认是存储对象的__dict__
属性,但我们可以自定义返回存储的内容,举例:
import pickle
class A:
def __init__(self, x, y=0):
self.x = x
self.y = y
def __getstate__(self):
return {"x": self.x}
a = A(5, 10)
b = pickle.dumps(a)
c = pickle.loads(b)
print(c.__dict__)
# {'x': 5}
__setstate__(self, state)
将字节反序列化成对象的行为,行为:pickle.load(file, obj)
/pickle.loads(obj)
,举例:
import pickle
class A:
def __init__(self, x, y=0):
self.x = x
self.y = y
def __setstate__(self, state):
self.data = state
a = A(5, 10)
b = pickle.dumps(a)
c = pickle.loads(b)
print(c.__dict__)
# {'data': {'x': 5, 'y': 10}}
__reduce__(self)
序列化相关的更底层的接口方法,会返回对象的重构方法,以及对象对应的类、基类、__dict__
属性等,如__getstate__
底层就调用了该方法,举例:
import pickle
class A:
x = 1
def __init__(self):
self.y = 2
def __reduce__(self):
print(111)
return super().__reduce__()
a = A()
print(a.__reduce__())
p = pickle.dumps(a)
l = pickle.loads(p)
print(l, l.__dict__)
# 111
# <__main__.A object at 0x00000212F76A9160> {'y': 2}
# 111
# (<function _reconstructor at 0x00000212F76D7158>, (<class '__main__.A'>, <class 'object'>, None), {'y': 2})
__reduce_ex__(self, proto)
相比于__reduce__
,其可以传入协议版本,__reduce__
相当于__reduce_ex__(0|1)
,该方法主要用于版本的兼容,当传入的proto
值为0/1
和2~
时,执行的方式将有所不同,举例:
class A:
def __init__(self):
self.y = 2
a = A()
print(a.__reduce__())
print(a.__reduce_ex__(1))
print(a.__reduce_ex__(2))
# (<function _reconstructor at 0x00000222857E71E0>, (<class '__main__.A'>, <class 'object'>, None), {'y': 2})
# (<function _reconstructor at 0x00000222857E71E0>, (<class '__main__.A'>, <class 'object'>, None), {'y': 2})
# (<function __newobj__ at 0x00000222857E72F0>, (<class '__main__.A'>,), {'y': 2}, None, None)
协程相关
__await__(self)
异步IO编程时,awaitable
对象必须实现的方法,举例:
import asyncio
class A:
def __await__(self):
print("...")
yield
async def asyn_sleep():
await asyncio.sleep(1)
await A()
task = asyncio.wait([asyn_sleep() for _ in range(10)])
loop = asyncio.get_event_loop()
loop.run_until_complete(task)
__aiter__(self)
使用异步迭代器(async for
)必须实现的方法之一,返回一个异步迭代器,示例将结合__anext__
一起
__anext__(self)
使用异步迭代器必须实现的方法之一,实现异步迭代的规则,举例:
import asyncio
class A:
def __init__(self):
self.data = [1, 2, 3]
self.index = 0
def __aiter__(self):
return self
async def __anext__(self):
self.index += 1
if self.index >= len(self.data):
raise StopAsyncIteration
return self.data[self.index - 1]
async def test():
async for each in A():
print(each)
loop = asyncio.get_event_loop()
loop.run_until_complete(test())
# 1
# 2
__aenter__(self)
使用异步上下文(async with
)必须实现的方法之一,在进入异步上下文时执行,示例将结合__aexit__
一起
__aexit__(self)
使用异步上下文必须实现的方法之一,在离开异步上下文时执行,举例:
import asyncio
class A:
async def __aenter__(self):
print('enter context...')
await asyncio.sleep(1)
return self
async def __aexit__(self, exc_type, exc, tb):
print('exit context...')
await asyncio.sleep(1)
async def test():
async with A() as a:
print(a)
await asyncio.sleep(1)
loop = asyncio.get_event_loop()
loop.run_until_complete(test())
# enter context...
# <__main__.A object at 0x0000019AD4BDFD30>
# exit context...
更多异步相关内容参考:https://www.jb51.net/article/163540.htm
数学运算相关魔法方法
数学函数相关
__abs__(self)
计算绝对值时操作,行为:abs(obj)
,举例:
class A:
def __init__(self, val):
self.val = val
def __abs__(self):
return abs(self.val)
a = A(-100)
print(abs(a))
# 100
__round__(self)
四舍五入时操作,行为:round(obj)
__floor__(self)
向下取整时操作,行为:math.floor(obj)
__ceil__(self)
向上取整时操作,行为:math.ceil(obj)
__trunc__(self)
截取整数部分时操作,行为:math.trunc(obj)
__divmod__(self, other)
同时返回除数和余数操作,行为:divmod(obj, xxx)
,举例:
class A:
def __init__(self, x):
self.x = x
def __divmod__(self, other):
return self.x // other.x, self.x % other.x
a1 = A(5)
a2 = A(2)
print(divmod(a1, a2))
# (2, 1)
一元运算相关
__neg__(self)
前面加上负号时调用,行为:-obj
,举例:
class A:
def __init__(self, x):
self.x = x
def __neg__(self):
return -self.x
a = A(1)
print(-a)
# -1
__pos__(self)
前面加上正号时调用,行为:+obj
比较运算相关
__lt__(self, other)
使用<
比较时调用,行为:xxx < obj
,举例:
class A:
def __init__(self, x):
self.x = x
def __lt__(self, other):
return self.x < other.x
a1 = A(1)
a2 = A(2)
print(a1 < a2)
# True
__le__(self, other)
使用<=
比较时调用,行为:xxx <= obj
__eq__(self, other)
使用==
比较时调用,行为:xxx == obj
__ne__(self, other)
使用!=
比较时调用,行为:xxx != obj
__gt__(self, other)
使用>
比较时调用,行为:xxx > obj
__ge__(self, other)
使用>=
比较时调用,行为:xxx >= obj
注:
比较运算相关的魔法方法,只要实现了某一个,那么对应相反的操作也能同时被定义,例如定义了__lt__
,那么当进行>
操作时,就会自动调用__lt__
取反的结果;同理>=
和<=
都只要实现其中一个就行。而==
和!=
,只需要前面四个中实现其中一个就能用。(但像只实现了>
,那么>=
/<=
这些比较还是无法进行的),举例:
class A:
def __init__(self, x):
self.x = x
def __lt__(self, other):
return self.x < other.x
a1 = A(1)
a2 = A(2)
print(a1 < a2) # True
print(a1 > a2) # False
print(a1 == a2) # False
print(a1 >= a2) # 报错:没有实现对应的魔法方法
算术运算相关
__add__(self, other)
当进行加法运算时调用,行为:obj + xxx
,举例:
class A:
def __init__(self, x):
self.x = x
def __add__(self, other):
return self.x + other.x
a1 = A(1)
a2 = A(2)
print(a1 + a2)
# 3
__sub__(self, other)
当进行减法运算时调用,行为:obj - xxx
__mul__(self, other)
当进行乘法运算时调用,行为:obj * xxx
__truediv__(self, other)
当进行真除法时调用,,行为:obj / xxx
__floordiv__(self, other)
当进行整除法时调用,行为:obj // xxx
__mod__(self, other)
当进行求余运算时调用,行为:obj % xxx
__divmod__(self, other)
同时计算除数和余数操作,行为:divmod(obj, xxx)
__pow__(self, other)
当进行幂运算时调用,行为:obj ** xxx
位运算相关
__invert__(self)
取反运算,行为:~obj
__lshift__(self, other)
左移运算,行为:obj << xxx
__rshift__(self, other)
右移运算,行为:obj >> xxx
__xor__(self, other)
异或运算,行为:obj ^ xxx
__and__(self, other)
与运算,行为:obj & xxx
__or__(self, other)
或运算,行为:obj | xxx
反向算术运算相关
反向和普通的运算的差别:前面的普通运算,例如加法运算行为:obj + xxx
,而反向加法运算就行为:xxx + obj
__radd__(self, other)
反向加法,行为:xxx + obj
,举例:
class A:
def __init__(self, x):
self.x = x
def __radd__(self, other):
return self.x + other
a = A(1)
print(1 + a)
# 如果计算:a + 1,则不会调用到__radd__方法
# 2
__rsub__(self, other)
反向减法,行为:xxx - obj
__rmul__(self, other)
反向乘法,行为:xxx * obj
__rtruediv__(self, other)
反向真除法,行为:xxx / obj
__rfloordiv__(self, other)
反向整除法,行为:xxx // obj
__rmod__(self, other)
反向求余,行为:xxx % obj
__rdivmod__(self, other)
反向计算除数和余数操作,行为:divmod(xxx, obj)
__rpow__(self, other)
反向幂运算,行为:xxx ** obj
__rlshift__(self, other)
反向左移运算,行为:obj << xxx
__rrshift__(self, other)
反向右移运算,行为:obj >> xxx
__rxor__(self, other)
反向异或运算,行为:obj ^ xxx
__rand__(self, other)
反向与运算,行为:obj and xxx
__ror__(self, other)
反向或运算,行为:obj or xxx
增量算术运算相关
__iadd__(self, other)
增量赋值加法运算,行为:obj += xxx
,举例:
class A:
def __init__(self, v):
self.a = []
self.a.extend(v)
def __iadd__(self, v):
self.a.extend(v)
return A(self.a)
def __repr__(self):
return str(self.a)
a = A([1,2,3])
a += [4,5,6]
print(a)
# [1, 2, 3, 4, 5, 6]
__isub__(self, other)
行为:obj -= xxx
__imul__(self, other)
行为:obj *= xxx
__itruediv__(self, other)
行为:obj /= xxx
__ifloordiv__(self, other)
行为:obj //= xxx
__imod__(self, other)
行为:obj %= xxx
__ipow__(self, other)
行为:obj **= xxx
__ilshift__(self, other)
行为:obj <<= xxx
__irshift__(self, other)
行为:obj >>= xxx
__ixor__(self, other)
行为:obj ^= xxx
__iand__(self, other)
行为:obj &= xxx
__ior__(self, other)
行为:obj |= xxx
更多魔法方法参考
http://bbs.fishc.com/thread-48793-1-1.html
https://blog.csdn.net/bluehawksky/article/details/79027055
https://blog.csdn.net/yusuiyu/article/details/88292460
https://www.jianshu.com/p/81e9be7be993
网友评论