從我第一次瞭解Python中的元類開始,我一直在想「元元類可以做什麼?」。這至少在10年前 - 現在,就在幾個月前,對我來說很清楚,Python類創建中有一種機制實際上涉及到「元元」類。因此,有可能設法想象一些用途。
回顧Python中的對象實例化:每當使用與調用普通函數相同的語法「調用」它的類來實例化Python中的對象時,該類的__new__
和__init__
。什麼「編排」這些方法在課堂上的調用恰恰是課程的'類別'__call__
方法。通常當用Python寫元類時,元類的__new__
或__init__
方法是自定義的。
所以,事實證明,通過寫「元元」級一個可以自定義其__call__
方法,從而控制其參數傳遞和元類的__new__
和__init__
方法,如果一些其他的代碼被調用之前和之後。最終發現的結果是,metcalsses本身通常是硬編碼的,即使在非常大的項目中,也只需少數幾個(如果有的話)。因此,任何可能在「meta meta」調用中完成的定製通常都是直接在元類本身上完成的。
而它們,還有那些其他較少用於Python元類的用法 - 可以在元類中定製__add__
方法,以便它們定義的類是「可添加的」,並創建派生類,將兩個添加的類作爲超類。該機制對元類也是完全有效的 - 因此,我們只是「有一些實際的代碼」,它遵循一個「meta-meta」類的例子,它允許通過將類添加到類聲明中來構造類的「元類」 :
class MM(type):
def __add__(cls, other):
metacls = cls.__class__
return metacls(cls.__name__ + other.__name__, (cls, other), {})
class M1(type, metaclass=MM):
def __new__(metacls, name, bases, namespace):
namespace["M1"] = "here"
print("At M1 creation")
return super().__new__(metacls, name, bases, namespace)
class M2(type, metaclass=MM):
def __new__(metacls, name, bases, namespace):
namespace["M2"] = "there"
print("At M2 creation")
return super().__new__(metacls, name, bases, namespace)
,我們可以看到交互式控制檯上工作:通過允許
In [22]: class Base(metaclass = M1 + M2):
...: pass
...:
At M1 creation
At M2 creation
注意的是Python不同的元類通常很難結合起來,這其實是有用的用戶自制元類與庫或stdlib結合使用,而不必將其明確聲明爲前者的父代:
In [23]: import abc
In [24]: class Combined(metaclass=M1 + abc.ABCMeta):
...: pass
...:
At M1 creation
更新:很長一段時間過去了。我使用了很多元類,我想他們很有幫助,但後來我完全脫離了元類。原因在於,在研究了域環境交互以及IBM的一些研究之後,我意識到類型對於對象固有的概念本身就是有缺陷的。相反,類型取決於「誰的問題」。對一隻鳥來說,一棵樹只是一個築巢的地方。對於一個記錄者來說,收入來源,還是稅收評估者,或許還有其他的東西。 – 2011-03-16 18:55:12