2012-02-28 74 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