覆盖-类属性-吸气剂
问题内容:
我正在定义一个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__
你想要的。