<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    海上月明

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

    [轉(zhuǎn)] 理解python中的method與function

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

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

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

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

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

    由此可見 test 就是個不折不扣的函數(shù)!

    />>> 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 的標(biāo)志(任何定義了 __get__, __set__, __delete__ 三個方法中的一個或幾個的對象都是 descriptor ,這幾個方法的意思大家應(yīng)該能猜到了)

    根據(jù)對象 attribute 的查找策略,當(dāng) t.test 時,首先根據(jù) attribute查找策略找到這個函數(shù)對象,然后會發(fā)現(xiàn)它有 __get__ 屬性,則調(diào)用之,并把它的返回值當(dāng)作該 attribute 的值。

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

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

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

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

    />>> 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 的嗎?怎么這里沒有去調(diào)用它的 __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 中的對象本質(zhì)上都是平等的,區(qū)分它們的唯一方法是它們的接口,所以我相信所謂 type object 與 非 type object 的區(qū)別也只在于接口而已。也就是說只要實現(xiàn) type object 所需的接口,任何對象都可以成為 type object 。

    參考:

    How-To Guide for Descriptors
    Python Attributes and Methods

    主站蜘蛛池模板: 亚洲一区二区在线免费观看| 精品国产日韩亚洲一区| 亚洲五月激情综合图片区| 亚洲免费日韩无码系列| 国产成人精品久久亚洲| 一区二区三区免费视频播放器| 国产国产人免费人成免费视频 | 一级午夜免费视频| 午夜国产羞羞视频免费网站| 亚洲国产精品无码第一区二区三区| 毛片A级毛片免费播放| 亚洲私人无码综合久久网| 韩国18福利视频免费观看| 久久久久久亚洲av无码蜜芽| 国产精品免费一级在线观看| 四虎国产精品永免费| 久久亚洲中文字幕精品一区| 中文字幕乱码一区二区免费| 亚洲视频精品在线| 免费大片黄在线观看yw| 亚洲国产欧美一区二区三区| 亚洲AⅤ永久无码精品AA | 亚洲精华国产精华精华液| 国产午夜鲁丝片AV无码免费| 亚洲精品国产日韩无码AV永久免费网| 国产中文在线亚洲精品官网| 一区二区免费视频| 亚洲中文字幕一二三四区| 国产精品嫩草影院免费| 在线免费播放一级毛片| 亚洲中文字幕人成乱码 | 成年大片免费视频| 相泽南亚洲一区二区在线播放| 亚洲精品无码AV中文字幕电影网站| 香蕉免费看一区二区三区| 亚洲欧洲精品久久| 国产免费观看青青草原网站| 国产在线一区二区综合免费视频| 亚洲最大的黄色网| 亚洲日韩VA无码中文字幕 | 久久青草精品38国产免费|