为什么Python描述符的__get__方法接受拥有者类作为参数?

18 投票
4 回答
1755 浏览
提问于 2025-04-17 09:29

为什么在Python的描述符中,__get__方法要接受第三个参数——拥有者类呢?能给个例子说明一下它的用法吗?

第一个参数(self)是显而易见的,第二个参数(instances)在通常的描述符模式中是有意义的(接下来会有例子),但我从来没有见过第三个参数(owner)的用法。有人能解释一下它的使用场景吗?

为了方便大家理解和回答,这里是我见过的描述符的典型用法:

class Container(object):
    class ExampleDescriptor(object):
        def __get__(self, instance, owner):
            return instance._name 
        def __set__(self, instance, value):
            instance._name = value
    managed_attr = ExampleDescriptor()

考虑到instance.__class__是可以使用的,我能想到的就是显式传递类可能与直接从类访问描述符有关,而不是从实例访问(比如Container.managed_attr)。即便如此,我还是不太明白在这种情况下__get__里应该做些什么。

4 个回答

1

是的,这样做是为了让描述符在访问 Container.managed_attr 时能够看到 Container。你可以返回一些适合具体情况的对象,比如在使用描述符来实现方法时,可以返回一个未绑定的方法。

2

当从类中访问描述符时,instance 的值会是 None。如果你没有考虑到这种情况(就像你的示例代码没有考虑到的那样),那么在那时就会出现错误。

那么在这种情况下你应该怎么做呢?做一些合理的事情。😉 如果没有其他更好的办法,你可以参考 property 的做法,当从类中访问时返回描述符本身。

13

owner 是用来表示当你从类本身访问某个属性时,而不是从类的实例访问。在这种情况下,instance 的值会是 None

在你的例子中,如果你尝试像这样运行 print(Container.managed_attr),就会失败,因为此时 instanceNone,所以 instance._name 会引发一个 AttributeError 错误。

你可以通过检查 instance is None 来改善这种情况,这样在记录日志或抛出更有帮助的错误信息时,可以知道这个描述符属于哪个类,因此需要用到 owner 属性。例如:

        def __get__(self, instance, owner):
            if instance is None:
                # special handling for Customer.managed_attr
            else:
                return instance._name 

撰写回答