简单函数的__get__的目的

时间:2016-05-27 20:06:35

标签: python python-2.7

我想问一下简单函数__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__签名不匹配。

2 个答案:

答案 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