python 通过super()在描述符中获取基类

j9per5c4  于 2023-03-21  发布在  Python
关注(0)|答案(1)|浏览(165)

我有以下(当然是简化的)描述符:

class d:
    def __init__(self, method):
        self.method = method

    def __get__(self, instance, owner=None):
        print(instance, owner, self.method)
        return self.method(instance)

__get__()中,我想访问定义修饰函数的类,但在以下代码中发生的两次__get__()调用中,owner参数都是B

class A:
    @d
    def f(self):
        return "A"

class B(A):
    @d
    def f(self):
        return super().f + "B"

print(B().f)

我查看了Descriptor HowTo Guide关于通过super()调用描述符的部分,它说这个调用确实将子类类型传递给父类__get__()。这是否表明我可能需要定义__getattribute__()来获得我想要的,还是有别的方法?我知道super()调用不t只是返回A,而是B的代理,但我觉得应该有一种方法在描述符中获得A
我也希望能更清楚地解释我的代码中发生了什么。

oxalkeyp

oxalkeyp1#

更简单的做法是在描述符中记录在创建类时定义的类。
从Python 3.6开始,由于在描述符协议中添加了__set_name__方法,这是可能的。
__set_name__中接收的owner参数是定义描述符的actuall类。然后可以将其设置为描述符属性:

class d:
    def __init__(self, method):
        self.method = method

    def __set_name__(self, owner, name):
        self.name = name  # should be the same as self.method.__name__
        self.owner = owner

    def __get__(self, instance, owner=None):
        print(f"{instance=}, {owner=}, {self.owner=}, {self.method=}")
        return self.method(instance)

并将此代码与示例AB一起运行:

(env311) [gwidion@fedora tmp01]$ python script.py 
instance=<__main__.B object at 0x7f78c6094110>, owner=<class '__main__.B'>, self.owner=<class '__main__.B'>, self.method=<function B.f at 0x7f78c607d800>
instance=<__main__.B object at 0x7f78c6094110>, owner=<class '__main__.B'>, self.owner=<class '__main__.A'>, self.method=<function A.f at 0x7f78c607d760>
AB

如果不求助于__set_name__,那么要做的事情实际上就是线性遍历__mro__,直到找到self,只要它没有被另一个同类的装饰器遮蔽:

def __get__(self, instance, owner=None):
        for cls in owner.__mro__:
            if self in cls.__dict__.values():
                defined_at = cls 
            break
        else:
            raise RuntimeError()
        print(f"{instance=}, {owner=}, {self.defined_at=}, {self.method=}")
        return self.method(instance)

相关问题