python 魔术方法-示例
[TOC]
特殊属性
| 属性 | 含义 |
|---|
| __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)
return ret
def __init__(self, name, age):
self.name = name
self.age = age
print("初始化方法")
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)
print(str(person))
print(repr(person))
print("{}".format(person))
print("{!s}".format(person))
print("{!r}".format(person))
print("{!a}".format(person))
模拟容器类
| 容器类型 | |
|---|
| __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)
print(len(cart))
for x in cart:
print(x, end = ' ')
print(3 in cart)
print(1 in cart)
print(cart[1])
cart[1] = 'xyz'
print(cart)
print(cart + 4 + 'aaa' + 'ppp')
print(cart.__add__('iii'))
print(cart.items)
属性相关
| 有关属性 | |
|---|
| __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)
person.age = 40
print(person.age)
del person.email
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)
print(person.age)
print(person.xyz)
比较操作符
__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
参考资料
zhuanlan.zhihu.com/p/344951719
blog.csdn.net/weixin_4498…
blog.csdn.net/weixin_4498…