是什么功能,不受约束的方法和绑定方法之间的区别?(What is the difference be

2019-06-17 17:30发布

我这么问是因为的评论线程上讨论这个问题, 这个答案 。 我的方式让我的头一轮是90%。

In [1]: class A(object):  # class named 'A'
   ...:     def f1(self): pass
   ...:
In [2]: a = A()  # an instance

f1有三种不同的形式:

In [3]: a.f1  # a bound method
Out[3]: <bound method a.f1 of <__main__.A object at 0x039BE870>>
In [4]: A.f1  # an unbound method
Out[4]: <unbound method A.f1>
In [5]: a.__dict__['f1']  # doesn't exist
KeyError: 'f1'
In [6]: A.__dict__['f1']  # a function
Out[6]: <function __main__.f1>

是什么绑定的方法未结合的方法功能的目的,所有这一切都是由F1描述之间的差异? 一个人如何调用这三个对象? 如何对它们进行相互转化? 该文件对这个东西是很让人费解。

Answer 1:

函数创建由def语句,或lambda 。 下Python 2中,当一个功能的体内出现class语句(或传递到type类构造呼叫),它被转换成未绑定方法 。 (Python 3中没有未结合的方法;见下文)。当一个函数被在类实例访问,它被转换成一个绑定方法 ,可以自动实例提供给法作为第一self参数。

def f1(self):
    pass

这里f1是一个函数

class C(object):
    f1 = f1

现在C.f1是一个不受约束的方法。

>>> C.f1
<unbound method C.f1>
>>> C.f1.im_func is f1
True

我们还可以使用type类的构造函数:

>>> C2 = type('C2', (object,), {'f1': f1})
>>> C2.f1
<unbound method C2.f1>

我们可以将f1手动的不受约束的方法:

>>> import types
>>> types.MethodType(f1, None, C)
<unbound method C.f1>

未结合的方法是通过类实例访问的约束:

>>> C().f1
<bound method C.f1 of <__main__.C object at 0x2abeecf87250>>

访问被翻译成通过描述协议呼吁:

>>> C.f1.__get__(C(), C)
<bound method C.f1 of <__main__.C object at 0x2abeecf871d0>>

这些组合:

>>> types.MethodType(f1, None, C).__get__(C(), C)
<bound method C.f1 of <__main__.C object at 0x2abeecf87310>>

或者直接:

>>> types.MethodType(f1, C(), C)                
<bound method C.f1 of <__main__.C object at 0x2abeecf871d0>>

的函数,并且未结合的方法之间的主要区别是,后者知道哪个类势必; 调用或结合未结合的方法需要它的类类型的实例:

>>> f1(None)
>>> C.f1(None)
TypeError: unbound method f1() must be called with C instance as first argument (got NoneType instance instead)
>>> class D(object): pass
>>> f1.__get__(D(), D)
<bound method D.f1 of <__main__.D object at 0x7f6c98cfe290>>
>>> C.f1.__get__(D(), D)
<unbound method C.f1>

由于功能和未结合的方法之间的差异相当小,Python 3中摆脱的区别; 下的Python 3类实例访问功能只是给你本身的功能:

>>> C.f1
<function f1 at 0x7fdd06c4cd40>
>>> C.f1 is f1
True

在这两种Python 2和Python 3中,然后,这三个是等效的:

f1(C())
C.f1(C())
C().f1()

结合的功能的实例有其第一个参数(通常称为固定的效果self )该实例。 因此,绑定的方法C().f1相当于任一的:

(lamdba *args, **kwargs: f1(C(), *args, **kwargs))
functools.partial(f1, C())


Answer 2:

颇为费解

嗯,这是一个相当艰难的话题,它与描述的事情。

让我们开始功能。 一切都清楚了这里 - 你只需要调用它,在执行所有提供的参数传递:

>>> f = A.__dict__['f1']
>>> f(1)
1

普通TypeError引发与参数个数任何问题的情况下:

>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f1() takes exactly 1 argument (0 given)

现在,方法。 方法是带着几分香料的功能。 描述符有游戏在这里。 如在描述的数据模型 , A.f1A().f1被翻译成A.__dict__['f1'].__get__(None, A)type(a).__dict__['f1'].__get__(a, type(a))分别。 而这些结果__get__的从原料不同f1功能。 这些对象是原包装周围f1和包含一些额外的逻辑。

在的情况下, unbound method此逻辑包括检查第一参数是否为实例A

>>> f = A.f1
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f1() must be called with A instance as first argument (got nothing instead)
>>> f(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f1() must be called with A instance as first argument (got int instance instead) 

如果检查成功,则执行原f1与实例作为第一个参数:

>>> f(A())
<__main__.A object at 0x800f238d0>

注意, im_self属性是None

>>> f.im_self is None
True

在的情况下, bound method此逻辑立即提供原始f1与实例A它的(这种情况下是实际存储在创建的im_self属性):

>>> f = A().f1
>>> f.im_self
<__main__.A object at 0x800f23950>
>>> f()
<__main__.A object at 0x800f23950>

因此, bound意味着潜在的功能,必将有一部分实例。 unbound意味着它仍难免,但只有一类。



Answer 3:

功能目的是通过一个函数定义创建一个可调用对象。 绑定和未绑定的方法是通过一个由点二元运算称为描述符创建可调用的对象。

结合和未结合的方法的对象具有3个主要的性能: im_func是在该类中定义的功能对象, im_class是类,和im_self是类的实例。 对于非绑定方法, im_selfNone

当结合的方法被调用时,它调用im_funcim_self作为第一个参数,接着其的调用参数。 非绑定方法调用,只需调用它的参数的基本功能。



Answer 4:

我今天看到一个有趣的事情是,当我一个函数分配给类成员,它成为一个不受约束的方法。 如:

class Test(object):
    @classmethod
    def initialize_class(cls):
        def print_string(self, str):
            print(str)
        # Here if I do print(print_string), I see a function
        cls.print_proc = print_string
        # Here if I do print(cls.print_proc), I see an unbound method; so if I
        # get a Test object o, I can call o.print_proc("Hello")


Answer 5:

请参阅的Python 2和Python 3的文档了解更多信息。

我的解释如下。

Function片段:

Python 3中:

class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        if obj is None:
            return self
        return types.MethodType(self, obj)

Python的2:

class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        return types.MethodType(self, obj, objtype)
  1. 如果一个函数被调用无类或实例,它是一个纯函数。
  2. 如果一个函数是从类或实例调用,其__get__被称为检索包装的函数:
    一个。 Bx是相同B.__dict__['x'].__get__(None, B) 在Python 3,此返回纯函数。 在Python 2,这将返回一个未结合的功能。

    bx是相同type(b).__dict__['x'].__get__(b, type(b) ,这将在两个Python 2和Python 3中返回一个绑定的方法,这意味着self将作为第一个参数来隐式地通过。



文章来源: What is the difference between a function, an unbound method and a bound method?