標籤:

python中的綁定方法和未綁定方法是什麼?


bound和unbound方法是個很簡單的概念。在許多語言當中,類似於a.b()這樣的調用方法是一個整體,但在Python中,它其實是兩部分:獲取屬性a.b,調用()。所以也可以寫成:

c = a.b
c()

跟直接調用a.b()是等效的。當a是某個類的實例,b是這個類的方法的時候,a.b的返回值就是bound method,也就是綁定方法。它實際上是個bound method對象,這個對象提前將self參數進行了綁定。實際演示一下就很容易懂了:

&>&>&> class A(object):
... def b(self):
... pass
...
&>&>&> a = A()
&>&>&> a.b
&&>
&>&>&> A.b
&
&>&>&>

相應的unbound method是沒有綁定self的對象。在Python 3中,它就是普通的函數,在Python 2中則是unbound method類型,不過區別不大。

我們知道像A.b這樣的方法實際上跟一個普通定義的函數沒有本質區別,這個函數有一個參數self,所以實際上完全可以用A.b(a)的方式來調用,也就是手工將self參數指定為a。這也就是unbound method的用法。而相應的,bound method是一個實現了__call__的對象,它自動將調用這個對象的過程重定向到A.b(a)上面,相當於通過functools.partial綁定了第一個參數的效果,所以叫做bound method。

內部實現機制上來說,類的方法通過descriptor機制在運行時返回bound method對象,跟@property 本質上是一樣的,參考以前寫的另一篇答案 Python @property使用的問題?


  • 描述符

描述符實現了__get__,__set__,__delete__方法。如果實現了__set__,就稱為數據描述符;否則稱為非數據描述符。classmethod,staticmethod,函數為非數據描述符;property為數據描述符。下面為一個例子:

class staticmethod(object):

"reconstruct __builtins__.staticmethod"

def __init__(self, f):
self.f = f

def __get__(self, obj, typ=None):
return self.f

  1. Understanding __get__ and __set__ and Python descriptors

  2. 如何理解 Python 的 Descriptor?

  • 函數

上面說了函數是一個描述符,那它肯定實現了__get__方法。

&>&>&> def f(x):
return x

&>&>&> f.__get__
&
&>&>&> f.__get__(None, 1)
&
&>&>&> f.__get__(1, 1)
&

所以__get__的第一個參數為None的時候就返回unbound method;否則就返回bound method。

  • 類中的方法

    class classmethod(object):

    "reconstruct __builtins__.classmethod"

    def __init__(self, f):
    self.f = f

    def __get__(self, obj, typ=None):
    return self.f.__get__(typ, type)

    class staticmethod(object):

    "reconstruct __builtins__.staticmethod"

    def __init__(self, f):
    self.f = f

    def __get__(self, obj, typ=None):
    return self.f

    class A(object):

    a = 1

    def __init__(self):
    self.b = 2

    # instance method
    def f(self):
    return self.b

    # class method
    @classmethod
    def g(cls):
    return cls.a

    # static method
    @staticmethod
    def h():
    return 3

    類和類的實例在調用

  1. 實例方法,將調用函數的__get__;

  2. 類方法,將調用classmethod的__get__;
  3. 靜態方法,將調用staticmethod的__get__。

具體過程如下

&>&>&> A.f # 等價於 A.__dict__[f].__get__(None, A)
&
&>&>&> A().f # 等價於 A.__dict__[f].__get__(A(), A)
&&>
&>&>&> A.g # 等價於 A.__dict__[g].__get__(None, A)
&&>
&>&>&> A().g # 等價於 A.__dict__[g].__get__(A(), A)
&&>
&>&>&> A.h # 等價於 A.__dict__[h].__get__(None, A)
&
&>&>&> A.h # 等價於 A.__dict__[h].__get__(A(), A)
&

你把上述等價式結合上函數,classmethod和staticmethod的__get__就知道什麼時候返回unbounded method,什麼時候返回bounded method。

  1. 如何理解 Python 的 Descriptor?


python 2 中,所謂綁定,就是方法必須是類生成的實例對象,才能調用的方法,也就是實例方法。

詳細請看《python核心編程第2版》350頁。


綁定方法,就是該方法必須和具體的某個類對象進行綁定!同一個類中可以有無數多個對象,某個方法又必須與一個實例對象綁定,故叫綁定方法。


推薦閱讀:

在python 中如何將 list 轉化成 dictionary

TAG:Python |