覆盖-类属性-吸气剂


问题内容

我正在定义一个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'

在这种情况下,我需要一个元类吗?


问题答案:

是的,您需要一个元类,因为如果您__getattribute__在Debug类中定义(请注意,它必须是一个新式类),Python将针对Debug实例调用该属性以进行属性查找,而不针对Debug自身进行属性查找。

这是有道理的,因为它Debug.__getattribute__被定义为在Debug实例上运行,而不是在Debug类上运行。(您可以想象定义一个classmethod
__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实现的事实。尽管存在该概念,但不允许您修改内置类型的属性,因此该方法将行不通。

但是,元类可以解救。您可能已经知道如何执行此操作,但是对于其他读者,我将举一个示例(此答案中还有另一个示例,我的欠了它一些债务)。

_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__你想要的。