{__get__“个参数之一是多余的吗?

问题描述

如此处所述:

https://docs.python.org/3/reference/datamodel.html#object.__get__

传递给__get__方法的两个参数(不包括'self')分别是对象和用于访问属性的类。第二个论点不是多余的吗? 此外,当“类”也是对象时,为什么需要区分对象访问和类访问?

所以,在我看来,有两种可能性:

    从对象中访问
  • 属性在这种情况下, 所有者 参数将等于 type( instance em>,因此不会带来任何新信息
  • 可以从类(“类型”的对象)访问属性在这种情况下,源对象仅位于 owner 参数中,且 实例 没有

在我看来,如果仅使用一个参数(例如, 实例 ),它将始终保持原始对象,而无论是否使用原始参数,都可以实现相同的功能。它是不是一个“阶级”。如果确实需要该信息,则可以使用isinstance(instance,type)进行检查。

那么,为什么需要两个参数呢?

解决方法

它们分开的原因来自PEP 252

中的原始散文

__get__():可通过一个或两个参数调用的函数,该函数从对象中检索属性值。这也称为“绑定”操作,因为在方法描述符的情况下,它可能返回“绑定方法”对象。第一个参数X是必须从中检索属性或将属性绑定到的对象。当X为None时,可选的第二个参数T应该是元对象,并且绑定操作可能会返回一个限制于T实例的未绑定方法。当同时指定X和T时,X应该是T的实例。绑定操作返回的结果取决于描述符的语义;例如,静态方法和类方法(请参见下文)将忽略实例,而是绑定到类型。

换句话说,这两个参数允许区分“未绑定”描述符(一个调用该类)和一个“绑定”描述符(一个调用该实例)。 classmethod(它使用owner参数,却忽略了instance参数),这是您经常看到但却没有真正想到的一个示例。

如果您始终使用“绑定”描述符,那么对owner有点多余,因为instance应该是该类型的实例。

使用纯python实现的classmethod描述符也许更容易看到:

class MyClassmethod(object):
    def __init__(self,func):
        self._func = func

    def __get__(self,instance,owner = None):
        # instance is ignored,`owner` is bound to the first arg
        return self._func.__get__(owner)


class C:
    @MyClassmethod
    def func(cls,x):
        print(cls)
        print(x)

C.func(1)
C().func(2)

OUTPUT = '''\
$ python3 t.py 
<class '__main__.C'>
1
<class '__main__.C'>
2
'''

或考虑一下(有些不完整)cached_class_property

class cached_class_property:
    def __init__(self,fget):
        self.fget = fget

    def __get__(self,obj,owner):
        val = self.fget(owner)
        setattr(owner,self.fget.__name__,val)
        return val


class C:
    @cached_class_property
    def f(self):
        print('calculating...')
        return 42


print(C.f)
print(C().f)

OUTPUT = '''\
$ python3 t.py
calculating...
42
42
'''

请注意,由于python3,“ unbound”和“ bound”方法不再是一个真正的概念,但是api仍保留在描述符级别上-特别是类上的函数不再验证实例的类型是否与所有者:

class C:
    def d(self):
        print(self)

class D:
    pass

C().d()
C.d(D())

OUTPUT = '''\
$ python3 t.py
<__main__.C object at 0x7f09576d3040>
<__main__.D object at 0x7f09576d3040>

$ python2 t.py
<__main__.C instance at 0x7efe2c8a7910>
Traceback (most recent call last):
  File "t2.py",line 9,in <module>
    C.d(D())
TypeError: unbound method d() must be called with C instance as first argument (got D instance instead)
'''

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...