6

漫谈Python魔术方法,见过的没见过的都在这里了 - 松勤吴老师

 1 year ago
source link: https://www.cnblogs.com/wuxianfeng023/p/17198774.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

漫谈Python魔术方法,见过的没见过的都在这里了

就说一下,不深入

假的一览

  • 提到魔术方法,学过python都应该知道一些。至少你得会__init__吧。
  • 在我之前写的博文中有很多都涉及魔术方法。比如

  • 在《Python源码剖析》中做了个简单的概括(侵删),但仍然是不全的

2482761-20230309154828527-457569893.png

数据模型

https://docs.python.org/zh-cn/3.9/reference/datamodel.html#special-method-names

以3.9为例

  • 最全的还是在官方(但仍然会有漏网之鱼)
  • 我稍作整理,仅供参考

1. ★基本定制

方法 说明
__init__(self[, ...]) 所谓的初始化,在实例 (通过__new__) 被创建之后,返回调用者之前调用
__new__(cls[, ...]) 调用以创建一个 cls 类的新实例
__del__(self) 在实例将被销毁时调用。 这还被称为终结器或析构器(不适当)
__repr__(self) 由 repr() 内置函数调用以输出一个对象的“官方”字符串表示
__str__(self) 通过 str(object) 以及内置函数 format() 和 print() 调用以生成一个对象的“非正式”或格式良好的字符串表示
__bytes__(self) 通过 bytes 调用以生成一个对象的字节串表示
__format__(self,format_spec) 通过 format() 内置函数、扩展、格式化字符串字面值 的求值以及 str.format() 方法调用以生成一个对象的“格式化”字符串表示
__hash__(self) 通过内置函数 hash() 调用以对哈希集的成员进行操作,属于哈希集的类型包括 set、frozenset 以及 dict。__hash__() 应该返回一个整数
__bool__(self) 调用此方法以实现真值检测以及内置的 bool() 操作;应该返回 FalseTrue

2. 富比较方法

方法 说明
__lt__(self, other) 小于
__le__(self, other) 小于等于
__eq__(self, other) 等于
__ne__(self, other) 不等于
__gt__(self, other) 大于
__ge__(self, other) 大于等于

3. ★自定义属性访问

方法 说明
__getattr__(self, name) 当默认属性访问因引发 AttributeError 而失败时被调用
__getattribute__(self, name) 此方法会无条件地被调用以实现对类实例属性的访问
__setattr__(self, name, value) 此方法在一个属性被尝试赋值时被调用
__delattr__(self, name) 类似于 __setattr__() 但其作用为删除而非赋值
__dir__(self) 此方法会在对相应对象调用 dir() 时被调用

4. ★实现描述器

方法 说明
__get__(self, instance, owner=None) 调用此方法以获取所有者类的属性(类属性访问)或该类的实例的属性(实例属性访问)
__set__(self, instance, value) 用此方法以设置 instance 指定的所有者类的实例的属性为新值 value
__delete__(self, instance) 调用此方法以删除 instance 指定的所有者类的实例的属性。
__set_name__(self, owner, name) 在所有者类 owner 创建时被调用。描述器会被赋值给 name

5. 自定义类创建

方法 说明
__init_subclass__(cls) 当所在类派生子类时此方法就会被调用

6. 自定义实例及子类检查

方法 说明
__instancecheck__(self, instance) 如果 instance 应被视为 class 的一个(直接或间接)实例则返回真值
__subclasscheck__(self, subclass) 如果 subclass 应被视为 class 的一个(直接或间接)子类则返回真值

7. 模拟泛型类型

方法 说明
__class_getitem__(cls, key) 按照 key 参数指定的类型返回一个表示泛型类的专门化对象。
  • 当在类上定义时,__class_getitem__() 会自动成为类方法。 因此,当它被定义时没有必要使用 @classmethod 来装饰。

8. ★模拟可调用对象

方法 说明
__call__(self[, args...]) 此方法会在实例作为一个函数被“调用”时被调用

9. ★模拟容器类型

方法 说明
__len__(self) 调用此方法以实现内置函数 len()。应该返回对象的长度
__length_hint__(self) 调用此方法以实现 operator.length_hint()。 应该返回对象长度的估计值(可能大于或小于实际长度)
__getitem__(self, key) 调用此方法以实现 self[key] 的取值(注:官文是未付,英文是evaluation)
__setitem__(self, key, value) 调用此方法以实现向 self[key] 赋值
__delitem__(self, key) 调用此方法以实现 self[key] 的删除
__missing__(self, key) 此方法由 dict.__getitem__() 在找不到字典中的键时调用以实现 dict 子类的 self[key]
__iter__(self) 此方法在需要为容器创建迭代器时被调用
__reversed__(self) 此方法(如果存在)会被 reversed() 内置函数调用以实现逆向迭代
__contains__(self, item) 调用此方法以实现成员检测运算符in

10. ★模拟数字类型

方法 说明
__add__(self, other) +
__sub__(self, other) -
__mul__(self, other) *
__matmul__(self, other) @这个你可能没听过
__truediv__(self, other) 除法 /
__floordiv__(self, other) 地板除 //
__mod__(self, other) 取余 %
__pow__(self, other[,modulo]) 幂运算 **
__lshift__(self, other) 左移 <<
__rshift__(self, other) 右移 >>
__and__(self, other) & 与
__xor__(self, other) ^ 异或
__or__(self, other) | 或
  • 上面的方法再加个r又是另外一大类
方法 说明
__radd__(self, other) +
__rsub__(self, other) -
__rmul__(self, other) *
__rmatmul__(self, other) @
`rtruediv(self, other) /
__rfloordiv__(self, other) //
__rmod__(self, other) 取余 %
__rpow__(self, other[,modulo]) 幂运算 **
__rlshift__(self, other) 左移 <<
__rrshift__(self, other) 右移 >>
__rand__(self, other) &
__rxor__(self, other) ^
__ror__(self, other) |
  • 调用这些方法来实现具有反射(交换)操作数的二进制算术运算 (+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |)。这些成员函数仅会在左操作数不支持相应运算 3 且两个操作数类型不同时被调用。4 例如,求表达式 x - y 的值,其中 y 是具有 __rsub__() 方法的类的一个实例,则当 x.__sub__(y) 返回 NotImplemented 时会调用 y.__rsub__(x)

    请注意三元版的 pow() 并不会尝试调用 __rpow__() (因为强制转换规则会太过复杂)


  • 加个i又是另外一套
方法 说明
__iadd__(self, other) +=
__isub__(self, other) -=
__imul__(self, other) *=
__imatmul__(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) |=
  • 调用上面这些方法来实现扩展算术赋值

  • 数字是最多的
  • 不光上面的,还要一些
方法 说明
__neg__(self) 一元运算符 -
__pos__(self) 一元运算符 +
__abs__(self) abs()
__invert__(self) 一元运算符 ~
__complex__(self) 实现内置函数complex()
__int__(self) 实现内置函数int()
__float__(self) 实现内置函数float()
__index__(self) 调用此方法以实现 operator.index()
__round__(self[,ndigits]) 实现内置函数round()
__trunc__(self) 实现内置函数trunc()
__floor__(self) 实现内置函数floor()
__ceil__(self) 实现内置函数ceil()

11. 上下文管理器

方法 说明
__enter__(self) 进入与此对象相关的运行时上下文
__exit__(self, exc_type, exc_value, traceback) 退出关联到此对象的运行时上下文

12. 协程相关

可等待对象

方法 说明
__await__(self) awaitable 对象主要实现了该方法,它必须返回一个 iterator

异步迭代器

方法 说明
__aiter__(self) 必须返回一个 异步迭代器 对象
__anext__(self) 必须返回一个 可迭代对象 输出迭代器的下一结果值

异步上下文管理器

方法 说明
__aenter__(self) 在语义上类似于 __enter__(),仅有的区别是它必须返回一个 可等待对象
__aexit__(self) 在语义上类似于 __exit__(),仅有的区别是它必须返回一个 可等待对象

00. 漏网之鱼

方法 说明
__objclass__ 会被 inspect 模块解读为指定此对象定义所在的类
__slots__ 允许我们显式地声明数据成员(如特征属性)并禁止创建 dictweakref
__mro_entries__
__prepare__
__class__
__classcell__

说在最后

  • 码农高天出了一个系列讲解魔术方法,推荐观看https://www.bilibili.com/video/BV1b84y1e7hG

  • 流畅的python对魔术方法的讲解比较深入,贯穿全文,有一定难度,基础薄弱的谨慎

  • 前面在哪里说过很多内置函数、操作、运算符的背后多数都是这些魔术方法的实现。

    • with上下文管理器的背后是__enter__(self)__exit__(self, exc_type, exc_value, traceback)
    • 多数的运算符背后都是的10. 模式数字类型
    • 内置函数如len的背后是__len__

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK