Python __实例和类上的getattribute

Python __实例和类上的getattribute,python,inheritance,metaclass,Python,Inheritance,Metaclass,我有一个元类和and类,它们都使用\uu getattribute\uu来拦截属性调用。它们看起来像这样: class B(type): def __getattribute__ (self, name) : print(f'hello {self}') return super().__getattribute__(name) class C(metaclass=B): MY_ATTR = 'hello attr' def _

我有一个元类和and类,它们都使用
\uu getattribute\uu
来拦截属性调用。它们看起来像这样:

class B(type):    
    def __getattribute__ (self, name) :
        print(f'hello {self}')
        return super().__getattribute__(name)

class C(metaclass=B):
    MY_ATTR = 'hello attr'

    def __getattribute__ (self, name) :
        print(f'hello {self}')
        return super().__getattribute__(name)
这符合我的意愿:

C.MY_ATTR  
# hello <class 'C'>
# 'hello attr'

C().MY_ATTR
# hello <C object at 0x10bcbbda0>
# 'hello attr'
不幸的是,这不再像以前那样:

C.MY_ATTR  
# 'hello attr'

C().MY_ATTR
# hello <C object at 0x10bcbbda0>
# 'hello attr'
C.MY\u ATTR
#“你好,艾特”
C().我的属性
#你好
#“你好,艾特”
我假设问题在于元类无法从常规类继承,但我不确定。我也愿意接受任何其他实现(可能不需要元类)来获得相同的行为——尽管我仍然希望调用
C.MISSING
来引发
AttributeError

这方面也有类似的问题(例如),但它们略有不同,无法达到我的目的


谢谢

比这要复杂一点- 元类确实接受普通类作为mixin—在这些mixin上提供的任何方法都将在使用这些元类的类上可用,就好像它们是classmethods一样(但它们将从实例中隐藏—因为n实例上的属性查找查找的是类上的属性,而不是元类上的属性)

然而,
\uuuuuuGetAttribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

我自己做了一些尝试和错误,得到了
type
\uuu getattribute\uuu
确实存在并且与
对象不同-这就是为什么在执行
类M(type,a)
继承时不调用自定义版本的原因。而且,如果您交换继承顺序,您会看到
super()
得到一个特殊情况,即它没有填充正确调用
类型所需的参数

我试图用一个
if
语句对
type.\uuuu getattribute\uuuuu
的调用进行硬编码,并且进入了一个属性查找循环,我无法理解-这件事很重要(但可能是由于IPython内省-见下文)

尽管如此,在类和元类本身上重用代码是我从未见过的事情

如果您想在
\uuuuu getattribute\uuuu
主体中执行的操作不重要(与示例的
打印
相反),我建议您将
\uuu getattribute\uuuu
主体分解为普通函数,并在示例中放置
打印
的地方显式调用它,只需在元类和类基础上保留三行
\uuuu getattribute\uuuu

def getattribute(instance_or_class, attr_name):
    # complex attr_name consuming body goes here.
    # even colateral effects on "self" can be applied
    # to the  "instance_or_class" object
    print(instance_or_class, attr_name)


class B(type):
    def __getattribute__ (cls, name):
        getattribute(cls, name)
        return super().__getattribute__(name)


class C(metaclass=B):
    MY_ATTR = 'hello attr'
    def __getattribute__ (self, name):
        getattribute(self, name)
        return super().__getattribute__(name)
现在,我看到了与第一次输出不同的一点-我实际得到:

In [43]: C().MY_ATTR
<class '__main__.C'> __class__
<class '__main__.C'> __class__
<__main__.C object at 0x7fa420a314a8> MY_ATTR
Out[43]: 'hello attr'

OOC,如果您首先从
A
继承,例如
类B(A,类型):
会发生什么?是的,我已经尝试过了。C.MY_ATTR引发了一个异常
hello\uuuu getattribute\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我确实尝试过将逻辑分离成一个外部函数,但这导致了它自己的一组错误。这是很久以前的事了,所以我记不清了。尽管如此,我可能一直在使用REPL,并且出现了检查错误——就像你提到的那样。我将查看是否在git中提交了该代码,或者是否可以复制该代码。再次感谢
In [43]: C().MY_ATTR
<class '__main__.C'> __class__
<class '__main__.C'> __class__
<__main__.C object at 0x7fa420a314a8> MY_ATTR
Out[43]: 'hello attr'
>>> C().MY_ATTR
<__main__.C object at 0x7f0d4d908898> MY_ATTR
'hello attr'
>>> C.MY_ATTR
<class '__main__.C'> MY_ATTR
'hello attr'
>>>