覆盖-Class Attribute-getter

时间:2012-02-28 15:22:37

标签: python python-3.x

我正在定义一个类似于这样的Debug类:

_debug = False

class Debug:
    DrawOutlines = True
    InvinciblePlayer = True

我想覆盖Debug类,这样如果_debug为False,Debug的任何类属性(存在)都将为False。为了更改类属性的访问方式,我覆盖了__函数__

编辑:

我知道简单地覆盖__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'

这是否需要一个元类?

2 个答案:

答案 0 :(得分:6)

您覆盖__getattribute__以拦截所有属性访问权限,或__getattr__仅针对不存在的属性进行调用:

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

答案 1 :(得分:5)

是的,你需要一个元类,因为如果你在Debug类中定义__getattribute__(注意,必须是一个新式的类),Python将调用它来针对Debug的实例进行属性查找,但不是用于针对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实现的一个事实;虽然存在这个概念,但是你不允许修改内置类型的属性,因此这种方法不起作用。

然而,metaclasses救援。你可能已经知道如何做到这一点,但是对于其他读者我会给出一个例子(还有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,所以类属性的默认属性looker-upper是type.__getattribute__,你不能修改或替换type.__getattribute__直接,但您可以使用元类机制替换type,并且,如上例所示,将其替换为type的子类,其中包含您想要的__getattribute__