海上月明

          editer by sun
          posts - 162, comments - 51, trackbacks - 0, articles - 8
             :: 首頁 :: 新隨筆 ::  :: 聚合  :: 管理

          [轉] 理解python中的method與function

          Posted on 2008-10-15 14:21 pts 閱讀(3725) 評論(0)  編輯  收藏 所屬分類: Python
          轉自:白菜: python

          總是看到有人對 python 中的 method 和 function 之間關系的困惑,其實初學 python 時我也困惑過,不過現在自認為對這個問題還是基本清楚了 ;-)。

          我在前面寫過的 selfless python 里面說過 method 本質上就是 function,這個從它們的形式上也看得出來,呵呵,而讓人困惑的問題主要就是那個隱式傳入的 self 參數。這其實是利用了descriptor 機制,請看代碼:

          />>> class Temp(object):
          ... def test(self, a):
          ... print self, a
          ...
          />>> func = Temp.__dict__['test']
          />>> func

          />>> func(1, 2)
          1 2

          由此可見 test 就是個不折不扣的函數!

          />>> Temp.test

          />>> t = Temp()
          />>> t.test
          <__main__.Temp object at 0x00B46CD0>>

          但是這又是怎么回事了?哪里冒出個 bound/unbound method 來了?

          />>> dir(func)
          ['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__ge
          tattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__r
          educe__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure',
          'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_na
          me']

          請注意其中的 __get__ 方法,這就是 descriptor 的標志(任何定義了 __get__, __set__, __delete__ 三個方法中的一個或幾個的對象都是 descriptor ,這幾個方法的意思大家應該能猜到了)

          根據對象 attribute 的查找策略,當 t.test 時,首先根據 attribute查找策略找到這個函數對象,然后會發現它有 __get__ 屬性,則調用之,并把它的返回值當作該 attribute 的值。

          Temp.test 等價于 Temp.__dict__['test'].__get__(None, Temp)
          t.test 等價于 Temp.__dict__['test'].__get__(t, Temp)

          其實你可以把 func.__get__ 的實現想象成下面這個等價物:

          />>> class Function(object):
          ... def __get__(self, obj, objtype=None):
          ... import types
          ... return types.MethodType(self, obj, objtype)

          到這里事情已經比較清楚了,不過還有一點可能仍然會讓你感到困惑:

          />>> Temp.test = test

          />>> t.test(1)
          <__main__.Temp object at 0x00B46E90> 1
          />>> t.test = test
          />>> t.test(1)
          Traceback (most recent call last):
          File "", line 1, in ?
          TypeError: test() takes exactly 2 arguments (1 given)
          />>> t.test


          咦?不是說 function 是 descriptor 的嗎?怎么這里沒有去調用它的 __get__ 方法呢?

          另外:

          />>> class Meta(type):pass
          ...
          />>> class Temp(object):
          ... __metaclass__ = Meta
          ...
          />>> class Desc(object):
          ... def __get__(self, instance, type):
          ... print instance, type
          ...
          />>> desc = Desc()
          />>> Meta.d = desc
          />>> Meta.d
          None

          />>> Temp.d

          />>> Temp.d = desc
          />>> Temp.d
          None
          />>> t = Temp()
          />>> t.d
          <__main__.Temp object at 0x00B46DD0>

          />>> t.d = desc
          />>> t.d
          <__main__.Desc object at 0x00B46D30>

          注意到,到最后一步 t.d 的時候也沒有對 descriptor 求值。這個道理和上面那個是一樣的,仔細看一下 attribute 查找策略 就可以找到答案了, descriptor 只有綁定在 type object 上才有效。

          這里我們涉及到了 python對象一種分類: type object 和 非 type object ,這兩種對象在 attribute 查找過程中的待遇是不一樣的。

          簡單地說 type object 包括 type, type 的子類( 也就是 metaclass 了 )、 type 的實例( 也就是 class 了 )

          一般來說 type object 和 非 type object 不光在 attribute 受到不平等待遇,而且非 type object 還不能成為其它對象的基類型,想成為 metaclass 更是癡心妄想了。

          不過就像我以前說過的那樣,python 中的對象本質上都是平等的,區分它們的唯一方法是它們的接口,所以我相信所謂 type object 與 非 type object 的區別也只在于接口而已。也就是說只要實現 type object 所需的接口,任何對象都可以成為 type object 。

          參考:

          How-To Guide for Descriptors
          Python Attributes and Methods

          主站蜘蛛池模板: 南京市| 扎兰屯市| 连南| 琼结县| 固始县| 泽普县| 右玉县| 阳高县| 衡水市| 北辰区| 沾益县| 淮滨县| 凉城县| 千阳县| 青州市| 北辰区| 商城县| 宾川县| 东乌珠穆沁旗| 玉环县| 宜宾市| 英超| 沂源县| 夹江县| 平谷区| 安远县| 宁乡县| 东兰县| 育儿| 策勒县| 湟中县| 天水市| 永吉县| 葫芦岛市| 福鼎市| 峨山| 习水县| 乳山市| 武义县| 阿合奇县| 四川省|