Python的屬性搜索


這是我總結(jié)的Python屬性搜索的加長版筛璧,完整的描述了Python在做屬性訪問時的過程。
了解Python屬性搜索的整個過程房官,有助于更深入地理解Python屬性訪問删壮。


1. 對Python中屬性和方法的看法

理解Python時有一點(diǎn)很重要:一切皆對象搁骑。
為什么呢?
先看個例子:

>>> class Foo(object):
...    clsattr = 'this is class attribute'
...    def clsmethod(self):
...        print 'this is method'

在這個例子中酣衷,定義了class Foo涯捻。
通常我們稱clsattr屬性clsmethod方法墅诡。
這種叫法容易造成一種誤會:認(rèn)為對于類來說屬性和方法是兩種東西壳嚎。
其實(shí),由于在Python中一切皆對象,所以烟馅,拿上例來說说庭,clsattrFoo的一個str類型對象,而clsmethodFoo的一個function類型對象郑趁。
也就是對于Foo來講刊驴,clsattrclsmethod都是對象,除了類型不同寡润,其他的沒有什么不一樣捆憎。
這是一個看法上的細(xì)微區(qū)別,但是對后面理解Python的屬性搜索卻很重要悦穿。

2. Python屬性搜索的精簡版

Python存在類對象和實(shí)例對象之分:

>>> class Foo(object):
...    clsattr = 'this is class attribute'
...    def clsmethod(self):
...        print 'this is method'
...
>>> f = Foo()

在這個例子中Foo是類對象攻礼,f是實(shí)例對象。
但是我們知道栗柒,在OOP的理論中礁扮,類是抽象描述,實(shí)例是其具象瞬沦。Python支持OOP太伊,所以,也能通過自己的方式來“模擬并實(shí)現(xiàn)” OOP的要求逛钻。
其中最重要的就是屬性搜索規(guī)則僚焦。
當(dāng)不考慮描述符/描述器的時候,可以將Python屬性搜索精簡如下:

  1. Python的屬性搜索是按照繼承樹從下到上進(jìn)行的曙痘。
  2. 繼承樹以類對象為中心芳悲,向上是其基類,向下是其實(shí)例對象边坤。
  3. 當(dāng)通過實(shí)例.屬性的形式訪問某屬性時名扛,首先查找實(shí)例對象自身是否存在該屬性,如果存在茧痒,那么直接返回肮韧;如果不存在,那么向上查找旺订,直到找到為止弄企,否則返回異常。

還是拿上面的例子來說明:

>>> f.__dict__
{}
>>> Foo.__dict__
dict_proxy({'__module__': '__main__', 'clsattr': 'clsattr', '__dict__': <attribute '__dict__' of 'Foo' objects>, 'foo': <function foo at 0x7f2a86c31cf8>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None})

Python中對象通過__dict__內(nèi)置屬性來動態(tài)管理其所有屬性区拳。__dict__是一個字典拘领,其內(nèi)部為對象所有屬性名與屬性對象的對應(yīng)關(guān)系。
可以看到clsattr在類對象Foo中存在樱调,在實(shí)例對象f中不存在院究。
因此洽瞬,當(dāng)通過f.clsattr的形式訪問屬性clsattr的時候,首先业汰,查找實(shí)例對象f,沒有找到菩颖,所以繼續(xù)向上查找样漆,于是查找類對象Foo,找到晦闰,返回其值放祟。

按照這個規(guī)則,如果f中存在clsattr屬性呻右,則不會去查找Foo跪妥,即:

>>> f.clsattr = 'this is an instance attr'
>>> f.__dict__
{'clsattr': 'this is an instance attr'}
>>> f.clsattr
'this is an instance attr'

OK,了解了精簡版 的屬性搜索規(guī)則声滥,再來看看加長版 的規(guī)則眉撵。

3. Python屬性搜索的加長版

正如上面提到的,在不考慮描述符/描述器的時候落塑,才可以按照精簡版的規(guī)則來纽疟,那么考慮到描述符的時候呢?
關(guān)于描述符就不詳細(xì)展開了憾赁。簡單的說污朽,描述符就是一個實(shí)現(xiàn)了描述符協(xié)議 的類。
描述符協(xié)議包括__get__龙考、__set__蟆肆、__delete__方法。
其中晦款,只實(shí)現(xiàn)了__get__方法的描述符稱為non-data descriptor炎功;
而實(shí)現(xiàn)了__get____set__方法的描述符稱為data descriptor

當(dāng)把類的一個屬性為描述符這種特殊的對象時柬赐,會發(fā)生一件神奇的事情:
Python在類的__dict__中找到的對象如果擁有__get__()方法亡问,不會直接返回這個對象,而是返回其調(diào)用__get__()方法后的結(jié)果
注意:這里特別要強(qiáng)調(diào)是類的屬性肛宋,不是實(shí)例的屬性州藕。
舉例說明:

>>> class Foo(object):
...    clsattr = Descriptor()         # 假設(shè)Descriptor是自定義的描述符
...    def func(self):
...        print 'this is func'
... 

那么當(dāng)調(diào)用Foo.__dict__['clsattr']時,由于clsattr是描述符酝陈,所以床玻,返回的是Foo.__dict__['clsattr'].__get__(None, Foo)
這個時候,有趣的事情就來了沉帮,當(dāng)調(diào)用函數(shù)funcFoo.__dict__['func']時锈死,返回的是Foo.__dict__['func'].__get__(None, Foo), 在命令行中這是一個unbound method

所以贫堰,在Python中函數(shù)其實(shí)是一個描述符,只不過待牵,由于描述符必須在通過屬性訪問的情況下才起作用其屏,所以,并沒有察覺缨该。

看到這里偎行,可能你已經(jīng)恍然大悟:其實(shí)方法只是一個特殊的屬性而已。

好了贰拿,理解到這里蛤袒,就可以說說屬性搜索加長版**:

  1. 當(dāng)通過實(shí)例.屬性訪問一個屬性時,首先膨更,從其類對象開始向上查找妙真,如果存在并且是data-descriptor,那么返回查找結(jié)果荚守;否則珍德,進(jìn)行步驟2
  2. 在實(shí)例中查找屬性是否存在,如果存在健蕊,則返回其值菱阵,否則,進(jìn)行步驟3
  3. 向上查找缩功,直到找到晴及,返回其值,否則嫡锌,返回異常

由于描述符只能是類屬性虑稼,所以,可以有以下結(jié)論:

  1. data descriptor對于同名的實(shí)例屬性(非描述器)有屏蔽作用:
    例如:
#!/usr/bin/env python
# -*- conding: utf-8 -*-
class RevealAccess(object):
    """A data descriptor that sets and returns values
       normally and prints a message logging their access.
    """

    def __init__(self, initval=None, name='var'):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print 'Retrieving', self.name, self.val
        return self.val

    def __set__(self, obj, val):
        print 'Updating', self.name, self.val 

class Foo(object):
    attr = RevealAccess(10, 'var "x"')      #設(shè)置類屬性attr為描述符
    def __init__(self):
        self.attr = 20        #調(diào)用描述符的__set__方法势木,而不是為實(shí)例設(shè)置屬性

f = Foo()
print f.attr

執(zhí)行結(jié)果如下:

Updating var "x" 10
Retrieving var "x" 10
10

2.non-data descriptor對于同名的屬性蛛倦,會被屏蔽掉。這一點(diǎn)與正常的類屬性相同啦桌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末溯壶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子甫男,更是在濱河造成了極大的恐慌且改,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件板驳,死亡現(xiàn)場離奇詭異又跛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)若治,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門慨蓝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來感混,“玉大人,你說我怎么就攤上這事礼烈』÷” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵此熬,是天一觀的道長谱秽。 經(jīng)常有香客問我,道長摹迷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任郊供,我火速辦了婚禮峡碉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘驮审。我一直安慰自己鲫寄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布疯淫。 她就那樣靜靜地躺著地来,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熙掺。 梳的紋絲不亂的頭發(fā)上未斑,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機(jī)與錄音币绩,去河邊找鬼蜡秽。 笑死,一個胖子當(dāng)著我的面吹牛缆镣,可吹牛的內(nèi)容都是我干的芽突。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼董瞻,長吁一口氣:“原來是場噩夢啊……” “哼寞蚌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钠糊,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挟秤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后眠蚂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煞聪,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年逝慧,在試婚紗的時候發(fā)現(xiàn)自己被綠了昔脯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啄糙。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖云稚,靈堂內(nèi)的尸體忽然破棺而出隧饼,到底是詐尸還是另有隱情,我是刑警寧澤静陈,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布燕雁,位于F島的核電站,受9級特大地震影響鲸拥,放射性物質(zhì)發(fā)生泄漏拐格。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一刑赶、第九天 我趴在偏房一處隱蔽的房頂上張望捏浊。 院中可真熱鬧,春花似錦撞叨、人聲如沸金踪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胡岔。三九已至,卻和暖如春枷餐,著一層夾襖步出監(jiān)牢的瞬間靶瘸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工尖淘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留奕锌,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓村生,卻偏偏與公主長得像惊暴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子趁桃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理辽话,服務(wù)發(fā)現(xiàn),斷路器卫病,智...
    卡卡羅2017閱讀 134,664評論 18 139
  • 定義類并創(chuàng)建實(shí)例 在Python中油啤,類通過 class 關(guān)鍵字定義。以 Person 為例蟀苛,定義一個Person類...
    績重KF閱讀 3,952評論 0 13
  • 你是日夜辛勞的園丁一個 用心澆灌笨拙的樹 享受著桃李滿園的快樂 你是星光匯成的燈火一簇 閃著智慧的光 照耀我們前進(jìn)...
    孤獨(dú)乞丐閱讀 248評論 0 0
  • 最好的愛情益咬,并不是一段波瀾壯闊的史詩,而是一份波瀾不驚的守護(hù)帜平。最好的戀人會小心翼翼地呵護(hù)彼此的感受幽告,就像在這個被各...
    戒定慧子閱讀 431評論 0 0
  • 你好箍邮,你有一個群聊即將解散,請注意叨叙! 很高興陪大家度過了愉快的一周CP之旅锭弊,首先,感謝簡書提供這個機(jī)會讓我們相遇擂错,...
    凌兮兒_閱讀 965評論 13 8