1 回答

TA貢獻(xiàn)1795條經(jīng)驗(yàn) 獲得超7個贊
正如評論中所述 - 沒有這樣的東西,也不需要它 - 中的所有魔術(shù)方法都o(jì)bject可以被覆蓋并且可以正常工作。
字典、列表和其他集合會發(fā)生什么,正如 MisterMiyagi 在評論中解釋的那樣,例如,dictget不會使用該__getitem__方法,因此如果您要自定義其行為,您還必須重寫get. 正確解決這個問題的類,允許人們用最少的可重用代碼創(chuàng)建完全可用的映射、序列和集合,這些類是在collections.abc模塊中定義的。
現(xiàn)在,如果您希望其中一種魔術(shù)方法對一個對象的類而不是該類的實(shí)例起作用,則必須在該類的類中實(shí)現(xiàn)這些方法——這就是“元類”。
這與“超類”有很大不同——超類定義了子類繼承的方法和屬性,這些方法和屬性在子類中可用。但是類上的魔術(shù)方法只影響實(shí)例,而不影響類本身(__init_subclass__, 和當(dāng)然除外__new__,它可以更改為做其他事情而不是創(chuàng)建新實(shí)例)。
元類控制類的構(gòu)建方式 (使用__new__,__init__和__call__方法) - 并且允許擁有關(guān)于它們?nèi)绾瓮ㄟ^魔術(shù)方法表現(xiàn)的方法 - 我認(rèn)為元類中的魔術(shù)方法如何在類中工作沒有特殊情況,與它們在類與普通實(shí)例的關(guān)系中的工作相比。如果您在元類上實(shí)現(xiàn)__add__, __getitem__,__len__所有這些都將適用于使用該元類創(chuàng)建的類。
如果您不想在元類本身中為該類編寫魔術(shù)方法,可以做的是創(chuàng)建一個元類,該元類將在被調(diào)用時自動創(chuàng)建另一個動態(tài)元類,并復(fù)制 dunder 方法到那個班級。但很難將其視為任何嚴(yán)肅應(yīng)用程序中的“健康”設(shè)計(jì)——將魔法方法應(yīng)用于類已經(jīng)有點(diǎn)過頭了——盡管在某些情況下這樣做很方便。
因此,例如,如果您希望一個類具有一個__geitem__允許您檢索該類的所有實(shí)例的類,這將起作用:
class InstanceRegister(type):
def __init__(cls, name, bases, namespace, **kw):
super().__init__(name, bases, namespace, **kw)
cls._instances = []
original_new = cls.__new__
def new_wrapper(cls, *args, **kw):
if original_new is object.__new__:
instance = original_new(cls)
else:
instance = original_new(cls, *args, **kw)
cls._instances.append(instance)
return instance
cls.__new__ = new_wrapper
def __len__(cls):
return len(cls._instances)
def __getitem__(cls, item):
return cls._instances[item]
這將起作用,正如在本次互動會議中所顯示的那樣:
In [26]: class A(metaclass=InstanceRegister): pass
In [27]: a = A()
In [28]: len(A)
Out[28]: 1
In [29]: A[0] is a
Out[29]: True
添加回答
舉報(bào)