为什么人们在__get__中将所有者参数默认为无?

时间:2015-07-25 12:53:54

标签: python python-3.x descriptor python-descriptors

我经常看到这个:

None

为什么有些人使用默认值owner作为descr.__get__(self, obj, type=None) --> value 参数?

甚至在Python docs

中完成
@echo off
setlocal
call :SplitFile < split.html > split-1.html
goto :EOF

:SplitFile
   set "line="
   set /P "line="
   set /P "=%line%" < NUL
   echo/
   if "%line%" equ "</html>" (
      rem Copy the rest of lines to part 2 and terminate
      findstr "^" > split-2.html
      exit /B
   )
goto SplitFile

3 个答案:

答案 0 :(得分:6)

因为可以很容易地从实例派生所有者,所以第二个参数是可选的。只有当没有实例从中派生所有者时,才需要所有者参数。

在引入描述符PEP 252 - Making Types Look More Like Classes

的提案中对此进行了描述
  

__get__:一个可以用一个或两个参数调用的函数         从对象中检索属性值。这也是         被称为&#34;绑定&#34;操作,因为它可能会返回一个         &#34;约束方法&#34;方法描述符的情况下的对象。该         第一个参数X是属性必须从的对象         被检索或必须被绑定。 当X为None时,         可选的第二个参数T应该是元对象和         绑定操作可能会返回限制为的未绑定方法         T 的实例。

(大胆强调我的)

从第一天起,绑定意味着仅适用于实例,类型是可选的。例如,方法不需要它,因为它们可以单独绑定到实例:

>>> class Foo: pass
... 
>>> def bar(self): return self
... 
>>> foo = Foo()
>>> foo.bar = bar.__get__(foo)  # look ma! no class!
>>> foo.bar
<bound method Foo.bar of <__main__.Foo object at 0x10a0c2710>>
>>> foo.bar()
<__main__.Foo object at 0x10a0c2710>

此外,第二个参数可以很容易地从第一个参数派生;见证classmethod仍然绑定到类,即使我们没有传递一个:

>>> classmethod(bar).__get__(foo)
<bound method type.bar of <class '__main__.Foo'>>
>>> classmethod(bar).__get__(foo)()
<class '__main__.Foo'>

首先论证的唯一原因是支持绑定到类,例如当没有实例绑定到时。类方法又来了;绑定到None因为实例不起作用,它只有在我们实际传入类时才有效:

>>> classmethod(bar).__get__(None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __get__(None, None) is invalid
>>> classmethod(bar).__get__(None, Foo)
<bound method type.bar of <class '__main__.Foo'>>

答案 1 :(得分:3)

这是执行此操作的标准方法;我已经看到的所有Python内置描述符,包括函数,属性,静态方法等。我知道在描述符​​协议中没有所有情况,在没有所有者参数的情况下调用__get__,但是如果你想要手动调用__get__,不必通过所有者是有用的。所有者的论点通常不会做太多。

例如,you might want是一种更简洁的方法,可以为单个对象提供新方法。以下装饰器清除语法并让方法可以访问self

def method_of(instance):
    def method_adder(function):
        setattr(instance, function.__name__, function.__get__(instance))
        return function
    return method_adder

@method_of(a)
def foo(self, arg1, arg2):
    stuff()

现在a有一个foo方法。我们手动使用__get__函数的foo方法创建一个绑定方法对象,除了因为这个方法没有与一个类相关联,我们没有通过__get__一堂课。几乎唯一的区别是,当您打印方法对象时,您会看到?.foo而不是SomeClassName.foo

答案 2 :(得分:2)

因为这是描述符协议的指定方式:

  

descr.__get__(self, obj, type=None) --> value

cf https://docs.python.org/2/howto/descriptor.html#descriptor-protocol

type参数允许访问在查找类而不是实例时查找描述符的类。由于您可以从实例中获取类,因此在实例上查找描述符时,它在某种程度上是多余的,因此它已被设置为可选的,以允许较不详细的desc.__get__(obj)调用(而不是desc.__get__(obj, type(obj)))。