我想问一下简单函数__get__
的目的是什么?为什么行为与描述符类__get__
不同?
我的调查:
import inspect
def a(x, y):
return x + y
def wr(f):
def wrapper(*args, **kwargs):
print f.__name__, 'called with', args, kwargs
return f(*args, **kwargs)
return wrapper
print inspect.getsource(a)
# def a(x, y):
# return x + y
print inspect.getsource(a.__get__) # we cannot inspect it because it is a method-wrapper
# Traceback (most recent call last):
# ...
# 'function, traceback, frame, or code object'.format(object))
# TypeError: <method-wrapper '__get__' of function object at 0x7fd43591e140> is not a module, class, method, function, traceback, frame, or code object
a.__get__ = wr(a.__get__) # replace with function that delegates work and prints passed arguments
a2 = a.__get__(2) # we can use __get__ for functools.partial purposes
# __get__ called with (2,) {}
print a.__class__, a2.__class__ # it looks like a is a normal function and a2 is a bound function, but there is no instance
# <type 'function'> <type 'instancemethod'>
print 'a2 result:', a2(3)
# a2 result: 5
print inspect.getsource(a2) # source the same as function a
# def a(x, y):
# return x + y
我们知道描述符类__get__
方法签名object.__get__(self, instance, owner),看起来它与函数a.__get__
签名不匹配。
答案 0 :(得分:4)
Python函数是描述符。这是方法对象的创建方式。执行obj.method
时,将激活描述符协议,并调用函数的__get__
方法。这将返回一个绑定方法。
这就是为什么您将a2
视为实例方法的原因。执行a.__get__(2)
时,您将2
作为“实例”参数传递给__get__
。如果您执行print(a2)
,则会看到<bound method ?.a of 2>
,表示Python认为a2
是对象2
的绑定方法。
owner
参数在描述符协议中是可选的(或者至少在函数的实现中),这就是为什么你只能用一个参数调用__get__
。您可以调用a.__get__(2, 1)
并获取类似的对象。
答案 1 :(得分:2)
此__get__
是标准描述符__get__
。数据模型没有反映这一点,但owner
__get__
参数经常是可选的,因为它没有为非None
instance
提供额外信息。这不违反描述符协议。
作为属性访问的一部分,函数__get__
通常被称为正常方式描述符__get__
方法:
class Foo(object):
def bar(self):
return 3
foo = Foo()
# The following attribute access calls bar.__get__(foo, Foo) to create a method object.
bar_method = foo.bar