2012-02-28 110 views
2

我定義,像這樣一個Debug類:覆蓋-Class屬性 - 吸氣

_debug = False 

class Debug: 
    DrawOutlines = True 
    InvinciblePlayer = True 

我想覆蓋Debug類,這樣,如果_debug是假,調試的任何類屬性(存在)會是假的。什麼__函數__我是否重寫以改變如何訪問類屬性?

編輯:

我知道,只是重寫__getattribute__不會爲工作類屬性:

>>> _debug = False 
False 
>>> class Debug: 
...  DrawOutlines = True 
... 
...  def __getattribute__(self, name): 
...   return _debug and object.__getattribute__(self, name) 
... 
>>> Debug.DrawOutlines 
True 
>>> Debug.cake 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: type object 'Debug' has no attribute 'cake' 

會是這樣,我需要一個元類的情況?

+1

正如所寫,您的'__getattribute__'方法不會被調用,因爲調試不會從'object'繼承,即它是一種舊式的類,'__getattribute__'僅適用於新式類。但是,即使修復了這個問題,您的真正問題仍然存在:將在調試實例上調用該方法的屬性查找,但不調試類。 – metamatt 2012-10-26 22:20:55

+0

@metamatt Python 3.x類自動從'object'繼承。 – Darthfett 2012-10-27 18:13:11

回答

4

是的,你需要一個元類,因爲如果你在課堂上調試定義__getattribute__ (注意,它必須是一個新風格的類),Python將調用它來針對Debug實例的屬性查找,但不會針對調試本身的屬性查找。

這很有道理,因爲Debug.__getattribute__被定義爲對Debug實例進行操作,而不是類Debug。 (你能想象定義類方法__getattribute__,但我無法找到任何證據,Python有會調用這樣的事情任何機器。)

我想到這裏的第一件事是添加另一個__getattribute__那裏的Python會看因爲它用於Debug類屬性查找,即Debug類爲實例的類:Debug.__class__.__getattribute__

這確實存在,正如你所期望的工作原理:

>>> Debug.__class__.__getattribute__(Debug, 'Draw') 
True 
>>> Debug.__class__.__getattribute__(Debug, 'Bogus') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in __getattribute__ 
AttributeError: 'DebugType' object has no attribute 'Bogus' 

但它不是修改:

>>> Debug.__class__.__getattribute__ = Debug.__getattribute__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: can't set attributes of built-in/extension type 'type' 

這似乎只是一個Python實現生活的事實;當這個概念存在時,你不允許修改內建類型的屬性,所以這種方法將不起作用。

然而,元類救援。你可能已經知道如何做到這一點,但是對於其他讀者,我會舉一個例子(this answer還有另外一個例子,我的答案欠一些債務)。

_debug = True 
>>> class DebugType(type): 
...  def __getattribute__(self, name): 
...    print 'attr lookup for %s' % str(name) 
...    return _debug and object.__getattribute__(self, name) 
... 
>>> class Debug(object): 
...  Draw = True 
...  __metaclass__ = DebugType 
... 
>>> _debug 
False 
>>> Debug.Draw 
attr lookup for Draw 
False 
>>> _debug = True 
>>> Debug.Draw 
attr lookup for Draw 
True 

所以熬下來,對於類的默認類的實現是type,所以默認屬性收看上的類屬性是type.__getattribute__,你不能修改或直接更換type.__getattribute__,但可以使用替代type元類機制,並且如上例所示,將其替換爲type的子類,該子類具有您想要的__getattribute__

5

您覆蓋__getattribute__攔截所有屬性的訪問,或__getattr__到被調用只爲不存在的屬性:

_debug = True 
class A(object): 
    def __getattribute__(self, attr): 
     if _debug: 
      print attr 
     return object.__getattribute__(self, attr) 
+0

這並沒有解決它是類屬性的問題,因爲它只適用於實例。這裏需要一個Metaclass嗎? – Darthfett 2012-02-29 20:45:50

+1

是的,如果你寫了一個元類,並且寫元類''__getattr__'方法,它將適用於類屬性。它可能不適用於特殊的dunder方法,但是,像Python的機械設置中的'__add__'和'__eq__'將覆蓋對這些特殊屬性的訪問以提高效率 – jsbueno 2012-03-01 20:33:35

+0

我剛結束使用一個對象並使用一個類的單個實例像這樣。但是,我最初的問題是重寫類屬性,而不是對象屬性。如果你編輯了這個答案,要麼指定我可以使用單個對象(我的例子沒有'self。*'屬性),要麼提供一個元類例子,我可以'接受'它。 – Darthfett 2012-03-02 18:59:51