![](/img/trans.png)
[英]Calling super() inside a class' classmethod to get at the metaclass method
[英]Calling super in a class inheriting a metaclass throws an error
我正在嘗試使用元類使用子類的自動注冊,
但是下面的代碼在該行的Dep_A類中引發了錯誤
super(Dep_A,self).__init__().
*NameError: global name 'Dep_A' is not defined*
嘗試了MetaClass中的注釋行,但有相同的錯誤。 我知道這在不使用元類時有效,因此如何初始化父類的init方法
registry = {}
def register(cls):
print cls.__name__
registry[cls.__name__] = cls()
return cls
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
register(newclass)
return newclass
class Department(object):
__metaclass__ = MetaClass
def __init__(self):
self.tasks = dict()
class Dep_A(Department):
def __init__(self):
super(Dep_A,self).__init__()
...
您正在嘗試在class
語句完成之前創建該類的實例。 類對象已創建,但尚未分配給全局名稱。
事件的順序是:
class Dep_A
語句,並執行類主體以形成屬性(創建__init__
函數)。 'Dep_A'
, (Department,)
和{'__init__': <function ...>, ...}
)調用元類__new__
方法。 registry()
,傳入新的類對象 registry()
調用類對象 __init__
類的方法稱為 通常情況下, Dep_A
是當元類分配__new__
方法返回新創建的對象。 在此之前,未分配全局名稱Dep_A
,因此super(Dep_A, self).__init__()
調用失敗。
您可以先從那里設置名稱:
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
globals()[clsname] = newclass
register(newclass)
return newclass
另外, 不要嘗試在注冊表中創建實例 ,而要存儲一個類。 以后總是可以創建一個實例。
以下實現了一個注冊表,該注冊表在以后需要時透明創建一個實例,並僅存儲創建的那個實例:
from collections import Mapping
class Registry(Mapping):
def __init__(self):
self._classes = {}
self._instances = {}
def __getitem__(self, name):
if name not in self._instances:
self._instances[name] = self._classes.pop(name)()
return self._instances[name]
def __iter__(self):
return iter(self._classes.viewkeys() | self._instances.viewkeys())
def __len__(self):
return len(self._classes) + len(self._instances)
def register(self, cls):
self._classes[cls.__name__] = cls
registry = Registry()
class MetaClass(type):
def __new__(mcs, clsname, bases, attrs):
# newclass = super(MetaClass, mcs).__new__(mcs, clsname, bases, attrs)
newclass = type.__new__(mcs,clsname, bases, attrs)
registry.register(newclass)
return newclass
現在,將類存儲在單獨的映射中,並且只有當您隨后在注冊表映射中查找該類時,才會創建並緩存實例:
>>> class Department(object):
... __metaclass__ = MetaClass
... def __init__(self):
... self.tasks = dict()
...
>>> class Dep_A(Department):
... def __init__(self):
... super(Dep_A,self).__init__()
...
>>> registry.keys()
['Department', 'Dep_A']
>>> registry['Dep_A']
<__main__.Dep_A object at 0x110536ad0>
>>> vars(registry)
{'_instances': {'Dep_A': <__main__.Dep_A object at 0x110536ad0>}, '_classes': {'Department': <class '__main__.Department'>}}
您的register
函數嘗試在實際定義全局名稱之前實例化Dep_A
。 (即,在將Dep_A
的調用結果分配給元類之前,在仍然執行類語句的主體時調用它。)
您想存儲類本身 :
def register(cls):
registry[cls.__name__] = cls # Not cls()
return cls
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.