在Python 2中,用一個技巧就可以創建一個帶有幾個鹼基的類,儘管鹼基的元類是而不是的子類。在Python 3中,是否有可能爲具有多個基類的類動態創建元類?
訣竅是這些元類本身具有一個元類(將其命名爲「metametaclass」),並且此metameta類爲元類提供了一個調用方法,以便在必要時動態創建基類元類的公共子元類。最終,一個類的結果,其元類是新的子元類。下面是代碼:
>>> class MetaMeta(type):
... def __call__(mcls, name, bases, methods):
... metabases = set(type(X) for X in bases)
... metabases.add(mcls)
... if len(metabases) > 1:
... mcls = type(''.join([X.__name__ for X in metabases]), tuple(metabases), {})
... return mcls.__new__(mcls, name, bases, methods)
...
>>> class Meta1(type):
... __metaclass__ = MetaMeta
...
>>> class Meta2(type):
... __metaclass__ = MetaMeta
...
>>> class C1:
... __metaclass__ = Meta1
...
>>> class C2:
... __metaclass__ = Meta2
...
>>> type(C1)
<class '__main__.Meta1'>
>>> type(C2)
<class '__main__.Meta2'>
>>> class C3(C1,C2): pass
...
>>> type(C3)
<class '__main__.Meta1Meta2'>
這個例子(當然改變語法class C1(metaclass=Meta1)
等)在Python 3
問題1不起作用:我是否理解正確的是Python 2,首先使用第一個基類的元類構造第一個C3
,並且僅在type(C3)
不是type(C1)
和type(C2)
的常見子類時纔會導致錯誤,而在Python 3中,錯誤早於提出?
問題2:(How)是否有可能使上面的例子在Python 3中工作?我確實嘗試使用abc.ABCMeta
的子類作爲metameta類,但即使使用定製__subclasscheck__
使得issubclass(Meta1, Meta2)
返回True
,但創建C3仍然會導致錯誤。
注:我當然可以使Python 3高興通過靜態定義Meta1Meta2
並明確利用它作爲C3
元類。但是,那不是我想要的。我希望公共的子元類是動態創建的。
爲了使事情變得複雜起見,這感覺有點像複雜性:-)。爲什麼你想這樣做,而不是通過明確地將'C1'和'C2'的元類混合在一起來爲'C3'創建一個新的元類的更容易閱讀和理解的變體? – mgilson
我是SageMath的開發人員,他的用戶語言目前是Python 2.7。在該CAS中,使用了實現單獨功能的不同元類。說五個特徵,這意味着有32種可能的特徵組合。靜態定義每種可能的組合有點尷尬,事實上SageMath目前只提供*些*組合。另外,爲用戶創建新的類應該很容易:用戶不需要查找所有基類的元類並明確地選擇正確的組合元類。 –