函数,未绑定方法和绑定方法有什么区别?

发布于 2021-01-29 17:40:48

我之所以问这个问题,是因为对该答案的评论主题进行了讨论。我有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描述?一个人怎么称呼这三个物体?它们如何相互转化?关于这些东西的文档很难理解。

关注者
0
被浏览
137
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    一个 功能 是创建由def声明,或通过lambda。在Python
    2下,当函数出现在class语句主体中(或传递给type类构造调用)时,它将转换为 未绑定方法 。(Python3没有未绑定的方法;请参见下文。)在类实例上访问函数时,它将转换为 绑定方法 ,该 方法 自动将实例作为第一个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())
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看