Python Override-Class属性-getter

Python Override-Class属性-getter,python,python-3.x,Python,Python 3.x,我定义了一个调试类,如下所示: _debug = False class Debug: DrawOutlines = True InvinciblePlayer = True 我想重写Debug类,这样如果_Debug为False,Debug的任何类属性(存在)都将为False。为了更改类属性的访问方式,我应该覆盖哪些功能 编辑: 我知道简单地重写\uuuu getattribute\uuuu对类属性不起作用: >>> _debug = False Fals

我定义了一个调试类,如下所示:

_debug = False

class Debug:
    DrawOutlines = True
    InvinciblePlayer = True
我想重写
Debug
类,这样如果_Debug为False,Debug的任何类属性(存在)都将为False。为了更改类属性的访问方式,我应该覆盖哪些功能

编辑:

我知道简单地重写
\uuuu getattribute\uuuu
对类属性不起作用:

>>> _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'
>>\u debug=False
假的
>>>类调试:
...     DrawOutlines=真
...
...     def uu getattribute_uu(self,name):
...         返回调试和对象。获取属性(self,name)
...
>>>Debug.DrawOutlines
真的
>>>调试蛋糕
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:类型对象“Debug”没有属性“cake”

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

您可以重写
\uuuuuGetAttribute\uuuuuuu
来拦截所有的属性访问,或者
\uuuuuuuGetAttr\uuuuuuuuuu
来仅为不存在的属性调用:

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

是的,您需要一个元类,因为如果您在类Debug(注意,它必须是一个新样式的类)中定义
\uuuu getattribute\uuuu
,Python将调用该元类来对Debug实例进行属性查找,而不是对Debug本身进行属性查找

这是有意义的,因为
Debug.\uuuuu getattribute\uuuuu
被定义为在Debug实例上操作,而不是类Debug。(您可以想象定义一个classmethod
\uuuu getattribute\uuuu
,但我找不到任何证据表明Python有任何机制可以调用这样的东西。)

这里我想到的第一件事是添加另一个
\uuuuu getattribute\uuuu
,Python将在其中查找调试类属性查找,也就是说,在调试类作为实例的类中:
Debug.\uuuu class\uu.\uuuu getattribute\uuu

这确实存在,并且按照您的预期工作:

>>> 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'

因此,归结起来,类的默认类实现是
type
,因此类属性的默认属性查找器上限是
type.\uuuu getattribute.\uuuu
,您不能直接修改或替换
type.\uu uu getattribute.\uuu
,但可以使用元类机制替换
type
,并且,在上面的示例中,将其替换为
类型的子类,该子类具有所需的
\uuu getattribute\uuu

这并没有解决它是类属性的问题,因为它只在实例上工作。这里是否需要元类?是的,如果您编写元类,并编写元类`
\uuu getattr\uuu
方法,它将适用于类属性。它可能不适用于特殊的dunder方法,例如
\uuuuu add\uuuuuu
\uuuuuuu eq\uuuuu
,因为Python的机器库会覆盖对这些特殊属性的访问,以提高效率。它只是使用了一个对象并使用了一个类的单个实例,就像这样。然而,我最初的问题是重写类属性,而不是对象属性。如果您编辑此答案以指定我可以使用单个对象(我的示例没有
self.
属性),或者提供了一个元类示例,我可以“接受”它。如前所述,您的
\uuuu getattribute\uuuuu
方法不会被调用,因为调试不会从
对象继承,即它是一个旧式类,而
\uuu getattribute\uu
仅适用于新样式的类。但是,即使解决了这个问题,您真正的问题仍然存在:该方法将被调用以查找调试实例的属性,而不是类Debug。@metamatt Python 3.x类将自动从
对象继承。
>>> 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'
_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