漫談Python魔術方法,見過的沒見過的都在這裡了

2023-03-09 18:00:43

漫談Python魔術方法,見過的沒見過的都在這裡了

就說一下,不深入

假的一覽

資料模型

https://docs.python.org/zh-cn/3.9/reference/datamodel.html

以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__