[英]python - Class attributes apparently not inherited
在最近的一個項目中,我嘗試做這樣的事情(更復雜,但結果相同):
class MetaA(type):
def __new__(cls, name, args, kwargs):
print kwargs["foo"]
return type.__new__(cls, name, args, kwargs)
class A(object):
__metaclass__ = MetaA
foo = "bar"
class B(A):
pass
我明白了:
bar
Traceback (most recent call last):
File "C:\Users\Thorstein\Desktop\test.py", line 10, in <module>
class B(A):
File "C:\Users\Thorstein\Desktop\test.py", line 3, in __new__
print kwargs["foo"]
KeyError: 'foo'
類屬性是否未繼承? 如果是這樣,在與上述類似的框架中是否有可能的解決方法?
編輯:可能更容易看到我的意思使用程序中的實際(簡化)示例..
class GameObjectMeta(type):
def __new__(cls, name, bases, attrs):
attrs["dark_color"] = darken(*attrs["color"])
return type.__new__(cls, name, bases, attrs)
class GameObject(object):
__metaclass__ = GameObjectMeta
color = (255,255,255) # RGB tuple
class Monster(GameObject):
pass
基本上,想要在基色上運行一個函數來制作一個保存在類中的較暗的函數(類的多個實例將需要相同的顏色,但是將有更長的類層次結構)。 我希望這會更有意義..
它不應該繼承那些。 元類接收在它實例化的類上定義的屬性,而不是其基類的屬性。 元類構造函數的重點是訪問類體中實際給出的內容。
實際上,基類的屬性實際上根本不在“子類”中。 當你定義子類時,並不是將它們“復制”到子類中,實際上在創建時,子類甚至“不知道”它的超類可能具有哪些屬性。 相反,當您訪問 B.foo
,Python首先嘗試在B上查找屬性,然后如果找不到它,則查看其超類。 每次嘗試讀取此類屬性時都會動態發生這種情況。 元類機制不應該訪問超類的屬性,因為那些實際上不存在於子類中。
一個可能相關的問題是你對__new__
的定義是不正確的。 元類__new__
的參數是cls,name,bases和attrs。 第三個參數是基類列表,而不是“args”(無論你想要的是什么)。 第四個參數是類體中定義的屬性列表。 如果要訪問繼承的屬性,可以通過基礎獲取它們。
無論如何,你想用這個方案完成什么? 可能有更好的方法來做到這一點。
如果使用__init__
而不是__new__
則可以繼承基類屬性:
class MetaA(type):
def __init__(self, name, bases, attr):
print self.foo # don't use attr because foo only exists for A not B
print attr # here is the proof that class creation does not follow base class attributes
super(MetaA, self).__init__(name, base, attr) # this line calls type(), but has no effect
class A(object):
__metaclass__ = MetaA
foo = 'bar'
class B(A):
pass
創建A時返回:
bar
{'__module__': '__main__', 'foo': 'bar', '__metaclass__': <class '__main__.MetaA'>}
當創建B時返回:
bar
{'__module__': '__main__'}
注意,這就是@BrenBarn在他的回答中所說的,當創建B
時foo
不在attr
。 這就是OP問題中的代碼引發KeyError的原因。 然而,調用self.foo
在B
查找foo
然后如果它找不到它在它的基礎上查看,IE A
兩個類的元類可以通過查看它的類來確定:
>>> print A.__class__
<class '__main__.MetaA'>
>>> print A.__class__
<class '__main__.MetaA'>
在分配和初始化B
時調用元類__init__
方法,在stdout
打印self.foo
和attr
也證明了B
的元類是MetaA
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.