我正在定义一个类似于这样的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'
这是否需要一个元类?
答案 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__
。