簡體   English   中英

python - 類屬性顯然不是繼承的

[英]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在他的回答中所說的,當創建Bfoo不在attr 這就是OP問題中的代碼引發KeyError的原因。 然而,調用self.fooB查找foo然后如果它找不到它在它的基礎上查看,IE A

兩個類的元類可以通過查看它的類來確定:

>>> print A.__class__
<class '__main__.MetaA'>
>>> print A.__class__
<class '__main__.MetaA'>

在分配和初始化B時調用元類__init__方法,在stdout打印self.fooattr也證明了B的元類是MetaA

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM