python 魔术方法-示例
特殊属性
|
属性 |
含义 |
|
__name__ |
类、函数、方法的名字,不能实例调用 |
|
__module__ |
类、函数、方法所在的模块 |
|
__class__ |
对象、属性的类 |
|
__bases__ |
类的基类,不能实例调用 |
|
__doc__ |
类、函数的文档 |
|
__dict__ |
类或者实例的属性 |
class People(object):
# 实例化对象
def __init__(self, name, age):
self.name = name
self.age = age
print("__init__")
p1 = People("beike", 18)
print(People.__name__)
print(People.__class__)
print(People.__bases__)
print(People.__doc__)
print(People.__dict__)
#
print("-"*50)
print(p1.__class__)
print(p1.__doc__)
print(p1.__dict__)
# 执行结果----------------------------------------------------------------------------
__init__
People
<class 'type'>
(<class 'object'>,)
None
{'__module__': '__main__', '__init__': <function People.__init__ at 0x0000017602883820>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
--------------------------------------------------
<class '__main__.People'>
None
{'name': 'beike', 'age': 18}
构造方法
|
魔法方法 |
含义 |
|
__new__(cls[, ...]) |
__new__ 是在一个对象实例化的时候所调用的第一个方法 |
|
__init__(self[, ...]) |
构造器,当一个实例被创建的时候调用的初始化方法 |
|
__del__(self) |
析构器,当一个实例被销毁的时候调用的方法 |
|
__call__(self[, args...]) |
允许一个类的实例像函数一样被调用:x(a, b) 调用 x.__call__(a, b) |
构造方法__new__
触发时机: 实例化对象时自动触发(在__init__之前触发)
参数:至少一个cls 接收当前类,其他参数根据初始化方法参数决定
返回值:必须返回一个对象实例,没有返回值,则实例化对象的结果为 None,新实例的 __init__() 方法就不会被执行
作用:实例化对象
初始化方法__init__
触发机制:实例化对象之后立即触发
参数:至少有一个self,接收当前对象,其他参数根据需要进行定义
返回值:无
作用:初始化对象的成员
析构方法__del__
触发时机:当该类对象被销毁时,自动触发
参数:一个self,接受当前对象
返回值:无
作用:关闭或释放对象创建时资源
注意:del不一定会触发当前方法,只有当前对象没有任何变量引用时才会触发
可调用对象__call__
调用对象的魔术方法
触发时机:将对象当作函数调用时触发, 方式: 对象()
参数:至少一个self接收对象,其余根据调用时参数决定
返回值:自定义
作用:可以将复杂的步骤进行合并操作,减少调用的步骤,方便使用
class People(object):
# 创建对象
def __new__(cls, *args, **kwargs):
print("触发了构造方法")
ret = super().__new__(cls) # 调用父类的__new__()方法创建对象
return ret ## 将对象返
# 实例化对象
def __init__(self, name, age):
self.name = name
self.age = age
print("初始化方法")
# 删除对象
# del 对象名或者程序执行结束之后
def __del__(self):
print("析构方法,删除对象")
if __name__ == '__main__':
p1 = People('xiaoming', 16)
del p1
print("程序结束")
触发了构造方法
初始化方法
析构方法,删除对象
程序结束
基本方法
|
魔法方法 |
含义 |
|
__len__(self) |
定义当被 len() 调用时的行为 |
|
__str__(self) |
定义当被 str() 调用时的行为 |
|
__repr__(self) |
定义当被 repr() 调用时的行为 |
|
__format__(self, format_spec) |
定义当被 format() 调用时的行为 |
|
|
|
|
__bool__(self) |
判断对象的bool() 值时执行的方法,返回值只能是bool类型, 应该返回 True 或 False |
|
__bytes__(self) |
定义当被 bytes() 调用时的行为 |
|
__hash__(self) |
定义当被 hash() 调用时的行为 |
__len__
触发时机:使用len(对象) 的时候触发
参数:一个参数self
返回值:必须是一个整型
作用:可以设置为检测对象成员个数,但是也可以进行其他任意操作
注意:返回值必须必须是整数,否则语法报错,另外该要求是格式要求
__bool__
触发时机: 使用bool(对象)的时候触发
参数:一个self接收对象
返回值:必须是布尔值
作用:根据实际情况决定,可以作为快捷方式使用
注意:仅适合于返回布尔值的操作
__repr__
触发时机:在使用repr(object)的时候触发
参数:一个self接收对象
返回值:必须是字符串
作用:将对象转使用repr化为字符串时使用,也可以用于快捷操作
此方法通常被用于调试
__str__
触发时机: 通过 str(object) 以及内置函数 format() 和 print()
参数:一个self接收对象
返回值:必须是字符串
作用:将对象转使用str化为字符串时使用,也可以用于快捷操作
__format__
触发时机:使用字符串.format(object)时候触发
参数:一个self接收对象,一个参数接收format的{}中的格式,例如:>5
返回值:必须是字符串
作用:设置对象可以作为format的参数,并且自定义对象格式化的规则
注意:无
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Person(name='{self.name}', age={self.age})"
def __str__(self):
return f"{self.name}, {self.age}"
def __format__(self, format_spec):
if format_spec == "":
return "s"
if format_spec == "s":
return str(self)
elif format_spec == "r":
return repr(self)
elif format_spec == "a":
return f"Person('{self.name}', {self.age})"
else:
raise ValueError(f"Invalid format specifier '{format_spec}'")
person = Person("Alice", 30)
print(person) # 输出:Alice, 30
print(str(person)) # 输出:Alice, 30
print(repr(person)) # 输出:Person(name='Alice', age=30)
print("{}".format(person)) # 输出:s
print("{!s}".format(person)) # 输出:Alice, 30
print("{!r}".format(person)) # 输出:Person(name='Alice', age=30)
print("{!a}".format(person)) # 输出:Person('Alice', 30)
模拟容器类
|
容器类型 |
|
|
__len__(self) |
定义当被 len() 调用时的行为(返回容器中元素的个数) |
|
__getitem__(self, key) |
定义获取容器中指定元素的行为,相当于 self[key] |
|
__setitem__(self, key, value) |
定义设置容器中指定元素的行为,相当于 self[key] = value |
|
__delitem__(self, key) |
定义删除容器中指定元素的行为,相当于 del self[key] |
|
__iter__(self) |
定义当迭代容器中的元素的行为 |
|
__reversed__(self) |
定义当被 reversed() 调用时的行为 |
|
__contains__(self, item) |
定义当使用成员测试运算符(in 或 not in)时的行为 |
__len__
1 内建函数len(),返回对象的长度(>=0的整数)
如果把对象当作容器类型看,就如同list或者dict
2 bool()函数调用的时候,如果没有__bool__()方法
则会看__len__()方法是否存在,存在返回非0为真
__iter__
1 迭代容器时,调用,返回一个新的迭代器
__contains__
1 in成员运算符,没有实现,就调用__iter__方法遍历
__getitem__
1 实现self[key]访问。序列对象,key接受整数为索引,或为切片
2 对于set和dict,key为hashable。key不存在引发KeyError异常
__setitem__
1 和__getitem__的访问类似,是设置值的方法
__missing__
1 字典或其子类使用__getitem__()调用时,key不存在执行该方法
# 模拟购物车类
class Cart:
def __init__(self):
self.items = []
def __len__(self):
return len(self.items)
def additem(self, item):
self.items.append(item)
def __iter__(self):
return iter(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, key, value):
self.items[key] = value
def __str__(self):
return str(self.items)
def __add__(self, other):
self.items.append(other)
return self
cart = Cart()
cart.additem(1)
cart.additem('a')
cart.additem('c')
print(cart) # [1, 'a', 'c']
print(len(cart)) # 3
for x in cart:
print(x, end = ' ') # 1 a c
print(3 in cart) # False
print(1 in cart) # True
print(cart[1]) # a
cart[1] = 'xyz'
print(cart) # [1, 'xyz', 'c']
print(cart + 4 + 'aaa' + 'ppp') # [1, 'xyz', 'c', 4, 'aaa', 'ppp']
print(cart.__add__('iii')) # [1, 'xyz', 'c', 4, 'aaa', 'ppp', 'iii']
print(cart.items) # [1, 'xyz', 'c', 4, 'aaa', 'ppp', 'iii']
属性相关
|
有关属性 |
|
|
__getattr__(self, name) |
定义当用户试图获取一个不存在的属性时的行为 |
|
__getattribute__(self, name) |
定义当该类的属性被访问时的行为 |
|
__setattr__(self, name, value) |
定义当一个属性被设置时的行为 |
|
__delattr__(self, name) |
定义当一个属性被删除时的行为 |
|
__dir__(self) |
定义当 dir() 被调用时的行为,返回对象的所有成员名称列表 |
|
|
|
|
__get__(self, instance, owner) |
定义当描述符的值被取得时的行为 |
|
__set__(self, instance, value) |
定义当描述符的值被改变时的行为 |
|
__delete__(self, instance) |
定义当描述符的值被删除时的行为 |
__getattribute__()
方法与 __getattr__()
方法的行为不同。__getattribute__()
方法用于访问任何属性,而 __getattr__()
方法仅在对象没有指定属性时才会被调用。
__getattr__
触发时机:获取不存在的对象成员时触发
参数:一个是接收当前对象的self,一个是获取成员名称的字符串
返回值:必须有值
作用:为访问不存在的属性设置值
__setattr__
触发时机:设置对象成员值的时候触发
参数:1个当前对象的self,一个是要设置的成员名称字符串,一个是要设置的值
返回值:无 过程操作
作用:接管设置操作,可以在设置前之前进行判断验证等行为
注意:在当前方法中无法使用成员=值的方式直接设置成员,否则会无限递归,必须借助object的设置方法来完成
__dir__
触发时机: 会在对相应对象调用 dir() 时被调用
参数:1个当前对象的self
返回值: 必须是一个序列
作用: dir() 会把返回的序列转换为列表并对其排序。
注意:在当前方法中无法使用成员=值的方式直接设置成员,否则会无限递归,必须借助object的设置方法来完成
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __getattr__(self, name):
if name == "email":
return f"{self.name.lower()}@example.com"
else:
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
def __setattr__(self, name, value):
if name == "age":
if value < 0:
raise ValueError("Age cannot be negative")
super().__setattr__(name, value)
def __delattr__(self, name):
if name == "email":
raise AttributeError("Cannot delete email attribute")
super().__delattr__(name)
person = Person("Alice", 30)
print(person.email) # 输出:alice@example.com
person.age = 40
print(person.age) # 输出:40
del person.email # 引发 AttributeError 异常
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
def __getattribute__(self, name):
if name == "name":
return "Hello, " + object.__getattribute__(self, "_name")
elif name == "age":
return object.__getattribute__(self, "_age")
else:
return object.__getattribute__(self, name)
person = Person("Alice", 30)
print(person.name) # 输出:Hello, Alice
print(person.age) # 输出:30
print(person.xyz) # 引发 AttributeError 异常
比较操作符
__lt__(self, other) |
定义小于号的行为:x < y 调用 x.__lt__(y) |
|
__le__(self, other) |
定义小于等于号的行为:x <= y 调用 x.__le__(y) |
|
__eq__(self, other) |
定义等于号的行为:x == y 调用 x.__eq__(y) |
|
__ne__(self, other) |
定义不等号的行为:x != y 调用 x.__ne__(y) |
|
运算符相关
|
算数运算符 |
运算符 |
说明 |
|
__add__(self, other) |
p1+p2 |
定义加法的行为:+ |
|
__sub__(self, other) |
p1-p2 |
定义减法的行为:- |
|
__mul__(self, other) |
p1*p2 |
定义乘法的行为:* |
|
__truediv__(self, other) |
p1/p2 |
定义真除法的行为:/ |
|
__floordiv__(self, other) |
p1//p2 |
定义整数除法的行为:// |
|
__mod__(self, other) |
p1%p2 |
定义取模算法的行为:% |
|
__divmod__(self, other) |
(a // b, a % b) |
定义当被 divmod() 调用时的行为 |
|
__pow__(self, other[, modulo]) |
p1**p2 |
定义当被 power() 调用或 ** 运算时的行为 |
|
__lshift__(self, other) |
p1<<p2 |
定义按位左移位的行为:<< |
|
__rshift__(self, other) |
p1>>p2 |
定义按位右移位的行为:>> |
|
__and__(self, other) |
p1&p2 |
定义按位与操作的行为:& |
|
__xor__(self, other) |
p1^p2 |
定义按位异或操作的行为:^ |
|
__or__(self, other) |
p1|p2 |
定义按位或操作的行为:| |
反运算
|
反运算法 |
|
|
__radd__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rsub__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rmul__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rtruediv__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rfloordiv__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rmod__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rdivmod__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rpow__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rlshift__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rrshift__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rand__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__rxor__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
|
__ror__(self, other) |
(与上方相同,当左操作数不支持相应的操作时被调用) |
增量赋值运算
|
增量赋值运算 |
说明 |
|
__iadd__(self, other) |
定义赋值加法的行为:+= |
|
__isub__(self, other) |
定义赋值减法的行为:-= |
|
__imul__(self, other) |
定义赋值乘法的行为:*= |
|
__itruediv__(self, other) |
定义赋值真除法的行为:/= |
|
__ifloordiv__(self, other) |
定义赋值整数除法的行为://= |
|
__imod__(self, other) |
定义赋值取模算法的行为:%= |
|
__ipow__(self, other[, modulo]) |
定义赋值幂运算的行为:**= |
|
__ilshift__(self, other) |
定义赋值按位左移位的行为:<<= |
|
__irshift__(self, other) |
定义赋值按位右移位的行为:>>= |
|
__iand__(self, other) |
定义赋值按位与操作的行为:&= |
|
__ixor__(self, other) |
定义赋值按位异或操作的行为:^= |
|
__ior__(self, other) |
定义赋值按位或操作的行为:|= |
一元操作符
|
一元操作符 |
|
|
__pos__(self) |
定义正号的行为:+x |
|
__neg__(self) |
定义负号的行为:-x |
|
__abs__(self) |
定义当被 abs() 调用时的行为 |
|
__invert__(self) |
定义按位求反的行为:~x |
类型转换
|
类型转换 |
|
|
__complex__(self) |
定义当被 complex() 调用时的行为(需要返回恰当的值) |
|
__int__(self) |
定义当被 int() 调用时的行为(需要返回恰当的值) |
|
__float__(self) |
定义当被 float() 调用时的行为(需要返回恰当的值) |
|
__round__(self[, n]) |
定义当被 round() 调用时的行为(需要返回恰当的值) |
|
__index__(self) |
1. 当对象是被应用在切片表达式中时,实现整形强制转换 2. 如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 index 3. 如果 index 被定义,则 int 也需要被定义,且返回相同的值 |
上下文管理器
|
魔术方法 |
说明 |
|
__enter__(self) |
定义当被 len() 调用时的行为(返回容器中元素的个数) |
|
__exit__(self, exc_type, exc_value, traceback) |
定义获取容器中指定元素的行为,相当于 self[key] |
上下文管理器 详细 见contextlib
参考资料
https://zhuanlan.zhihu.com/p/344951719
https://blog.csdn.net/weixin_44983653/article/details/123968967
https://blog.csdn.net/weixin_44983653/article/details/123968967