日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Python對象的屬性訪問過程詳解

瀏覽:125日期:2022-08-04 08:32:26

只想回答一個問題: 當編譯器要讀取obj.field時, 發(fā)生了什么?

看似簡單的屬性訪問, 其過程還蠻曲折的. 總共有以下幾個step:

1. 如果obj 本身(一個instance )有這個屬性, 返回. 如果沒有, 執(zhí)行 step 2

2. 如果obj 的class 有這個屬性, 返回. 如果沒有, 執(zhí)行step 3.

3. 如果在obj class 的父類有這個屬性, 返回. 如果沒有, 繼續(xù)執(zhí)行3, 直到訪問完所有的父類. 如果還是沒有, 執(zhí)行step 4.

4. 執(zhí)行obj.__getattr__方法.

通過以下代碼可以驗證:

class A(object): a = ’a’class B(A): b = ’b’class C(B): class_field = ’class field’ def __getattr__(self, f): print(’Method {}.__getattr__ has been called.’.format( self.__class__.__name__)) return fc = C()print c.aprint c.bprint c.class_fieldprint c.c

輸出:

abclass fieldMethod C.__getattr__ has been called.c

PS: python里的attribute與property不同, 當使用了property里, property的解析優(yōu)先級最高. 詳見blog:從attribute到property.

補充知識:深入理解python對象及屬性

類屬性和實例屬性

首先來看看類屬性和類實例的屬性在python中如何存儲,通過__dir__方法來查看對象的屬性

>>> class Test(object): pass>>> test = Test()# 查看類屬性>>> dir(Test)[’__class__’,’__delattr__’,’__dict__’,’__doc__’,’__format__’,’__getattribute__’, ’__hash__’, ’__init__’, ’__module__’, ’__new__’, ’__reduce__’, ’__reduce_ex__’, ’__repr__’, ’__setattr__’, ’__sizeof__’, ’__str__’, ’__subclasshook__’, ’__weakref__’]# 查看實例屬性>>> dir(test)[’__class__’, ’__delattr__’, ’__dict__’, ’__doc__’, ’__format__’, ’__getattribute__’, ’__hash__’, ’__init__’, ’__module__’, ’__new__’, ’__reduce__’, ’__reduce_ex__’, ’__repr__’, ’__setattr__’, ’__sizeof__’, ’__str__’, ’__subclasshook__’, ’__weakref__’]

我們主要看一個屬性__dict__,因為 __dict__保存的對象的屬性,看下面一個例子

>>> class Spring(object):... season = 'the spring of class'... # 查看Spring類保存的屬性>>> Spring.__dict__dict_proxy({’__dict__’: <attribute ’__dict__’ of ’Spring’ objects>, ’season’: ’the spring of class’, ’__module__’: ’__main__’, ’__weakref__’: <attribute ’__weakref__’ of ’Spring’ objects>, ’__doc__’: None})# 通過兩種方法訪問類屬性>>> Spring.__dict__[’season’]’the spring of class’>>> Spring.season’the spring of class’

發(fā)現(xiàn)__dict__有個’season’鍵,這就是這個類的屬性,其值就是類屬性的數(shù)據(jù).

接來看,看看它的實例屬性

>>> s = Spring()# 實例屬性的__dict__是空的>>> s.__dict__{}# 其實是指向的類屬性>>> s.season’the spring of class’# 建立實例屬性>>> s.season = 'the spring of instance'# 這樣,實例屬性里面就不空了。這時候建立的實例屬性和類屬性重名,并且把它覆蓋了>>> s.__dict__{’season’: ’the spring of instance’}>>> s.__dict__[’season’]’the spring of instance’>>> s.season’the spring of instance’# 類屬性沒有受到實例屬性的影響>>> Spring.__dict__[’season’]’the spring of class’>>> Spring.__dict__dict_proxy({’__dict__’: <attribute ’__dict__’ of ’Spring’ objects>, ’season’: ’the spring of class’, ’__module__’: ’__main__’, ’__weakref__’: <attribute ’__weakref__’ of ’Spring’ objects>, ’__doc__’: None})# 如果將實例屬性刪除,又會調用類屬性>>> del s.season>>> s.__dict__{}>>> s.season’the spring of class’# 自定義實例屬性,對類屬性沒有影響>>> s.lang = 'python'>>> s.__dict__{’lang’: ’python’}>>> s.__dict__[’lang’]’python’# 修改類屬性>>> Spring.flower = 'peach'>>> Spring.__dict__dict_proxy({’__module__’: ’__main__’, ’flower’: ’peach’, ’season’: ’the spring of class’, ’__dict__’: <attribute ’__dict__’ of ’Spring’ objects>, ’__weakref__’: <attribute ’__weakref__’ of ’Spring’ objects>, ’__doc__’: None})>>> Spring.__dict__[’flower’]’peach’# 實例中的__dict__并沒有變化>>> s.__dict__{’lang’: ’python’}# 實例中找不到flower屬性,調用類屬性>>> s.flower’peach’

下面看看類中包含方法,__dict__如何發(fā)生變化

# 定義類>>> class Spring(object):... def tree(self, x):... self.x = x... return self.x... # 方法tree在__dict__里面>>> Spring.__dict__dict_proxy({’__dict__’: <attribute ’__dict__’ of ’Spring’ objects>, ’__weakref__’: <attribute ’__weakref__’ of ’Spring’ objects>, ’__module__’: ’__main__’, ’tree’: <function tree at 0xb748fdf4>, ’__doc__’: None})>>> Spring.__dict__[’tree’]<function tree at 0xb748fdf4># 建立實例,但是__dict__中沒有方法 >>> t = Spring()>>> t.__dict__{}# 執(zhí)行方法>>> t.tree('xiangzhangshu')’xiangzhangshu’# 實例方法(t.tree(’xiangzhangshu’))的第一個參數(shù)(self,但沒有寫出來)綁定實例 t,透過 self.x 來設定值,即給 t.__dict__添加屬性值。>>> t.__dict__{’x’: ’xiangzhangshu’}# 如果沒有將x 賦值給 self 的屬性,而是直接 return,結果發(fā)生了變化>>> class Spring(object):... def tree(self, x):... return x>>> s = Spring()>>> s.tree('liushu')’liushu’>>> s.__dict__{}

需要理解python中的一個觀點,一切都是對象,不管是類還是實例,都可以看成是對象,符合object.attribute ,都會有自己的屬性

使用__slots__優(yōu)化內存使用

默認情況下,python在各個實例中為名為__dict__的字典里存儲實例屬性,而字典會消耗大量內存(字典要使用底層散列表提升訪問速度), 通過__slots__類屬性,在元組中存儲實例屬性,不用字典,從而節(jié)省大量內存

# 在類中定義__slots__屬性就是說這個類中所有實例的屬性都在這兒了,如果幾百萬個實例同時活動,能節(jié)省大量內存>>> class Spring(object):... __slots__ = ('tree', 'flower')... # 仔細看看 dir() 的結果,還有__dict__屬性嗎?沒有了,的確沒有了。也就是說__slots__把__dict__擠出去了,它進入了類的屬性。>>> dir(Spring)[’__class__’, ’__delattr__’, ’__doc__’, ’__format__’, ’__getattribute__’, ’__hash__’, ’__init__’, ’__module__’, ’__new__’, ’__reduce__’, ’__reduce_ex__’, ’__repr__’, ’__setattr__’, ’__sizeof__’, ’__slots__’, ’__str__’, ’__subclasshook__’, ’flower’, ’tree’]>>> Spring.__slots__(’tree’, ’flower’)# 實例化>>> t = Spring()>>> t.__slots__(’tree’, ’flower’)# 通過類賦予屬性值>>> Spring.tree = 'liushu'# tree這個屬性是只讀的, 實例不能修改>>> t.tree = 'guangyulan'Traceback (most recent call last): File '<stdin>', line 1, in <module>AttributeError: ’Spring’ object attribute ’tree’ is read-only>>> t.tree’liushu’# 對于用類屬性賦值的屬性,只能用來修改>>> Spring.tree = 'guangyulan'>>> t.tree’guangyulan’# 對于沒有用類屬性賦值的屬性,可以通過實例來修改>>> t.flower = 'haitanghua'>>> t.flower’haitanghua’# 實例屬性的值并沒有傳回到類屬性,你也可以理解為新建立了一個同名的實例屬性>>> Spring.flower<member ’flower’ of ’Spring’ objects># 如果再給類屬性賦值>>> Spring.flower = 'ziteng'>>> t.flower’ziteng’

如果使用的當,__slots__可以顯著節(jié)省內存,按需要注意一下問題

在類中定義__slots__之后,實例不能再有__slots__所列名稱之外的其他屬性

每個子類都要定義__slots__熟悉,因為解釋器會忽略繼承__slots__屬性

如果不把__werkref__加入__slots__,實例不能作為弱引用的目標

屬性的魔術方法

來看幾個魔術方法

__setattr__(self,name,value):如果要給 name 賦值,就調用這個方法。__getattr__(self,name):如果 name 被訪問,同時它不存在的時候,此方法被調用。__getattribute__(self,name):當 name被訪問時自動被調用(注意:這個僅能用于新式類),無論 name 是否存在,都要被調用。__delattr__(self,name):如果要刪除 name,這個方法就被調用。>>> class A(object):... def __getattr__(self, name):... print 'You use getattr'... def __setattr__(self, name, value):... print 'You use setattr'... self.__dict__[name] = value# a.x,按照本節(jié)開頭的例子,是要報錯的。但是,由于在這里使用了__getattr__(self, name) 方法,當發(fā)現(xiàn) x 不存在于對象的__dict__中的時候,就調用了__getattr__,即所謂“攔截成員”。>>> a = A()>>> a.xYou use getattr# 給對象的屬性賦值時候,調用了__setattr__(self, name, value)方法,這個方法中有一句 self.__dict__[name] = value,通過這個語句,就將屬性和數(shù)據(jù)保存到了對象的__dict__中>>> a.x = 7You use setattr# 測試__getattribute__(self,name)>>> class B(object):... def __getattribute__(self, name):... print 'you are useing getattribute'... return object.__getattribute__(self, name)# 返回的內容用的是 return object.__getattribute__(self, name),而沒有使用 return self.__dict__[name]。因為如果用這樣的方式,就是訪問 self.__dict__,只要訪問這個屬性,就要調用`getattribute``,這樣就導致了無限遞歸# 訪問不存在的成員,可以看到,已經被__getattribute__攔截了,雖然最后還是要報錯的。>>> b = B()>>> b.yyou are useing getattributeTraceback (most recent call last): File '<stdin>', line 1, in <module> File '<stdin>', line 4, in __getattribute__AttributeError: ’B’ object has no attribute ’y’

Property函數(shù)

porperty可以作為裝飾器使用把方法標記為特性

class Vector(object): def __init__(self, x, y): # 使用兩個前導下劃線,把屬性標記為私有 self.__x = float(x) self.__y = float(y) # porperty裝飾器把讀值方法標記為特性 @property def x(self): return self.__x @property def y(self): return self.__y vector = Vector(3,4)print(vector.x, vector.y)

使用property可以將函數(shù)封裝為屬性

class Rectangle(object): ''' the width and length of Rectangle ''' def __init__(self): self.width = 0 self.length = 0 def setSize(self, size): self.width, self.length = size def getSize(self): return self.width, self.lengthif __name__ == '__main__': r = Rectangle() r.width = 3 r.length = 4 print r.getSize() # (3,4) r.setSize( (30, 40) ) print r.width # 30 print r.length # 40

這段代碼可以正常運行,但是屬性的調用方式可以改進,如下:

class Rectangle(object): ''' the width and length of Rectangle ''' def __init__(self): self.width = 0 self.length = 0 def setSize(self, size): self.width, self.length = size def getSize(self): return self.width, self.length # 使用property方法將函數(shù)封裝為屬性,更優(yōu)雅 size = property(getSize, setSize)if __name__ == '__main__': r = Rectangle() r.width = 3 r.length = 4 print r.size # (30, 40) r.size = 30, 40 print r.width # 30 print r.length # 40

使用魔術方法實現(xiàn):

class NewRectangle(object): def __init__(self): self.width = 0 self.length = 0 def __setattr__(self, name, value): if name == ’size’: self.width, self, length = value else: self.__dict__[name] = valuedef __getattr__(self, name): if name == ’size’: return self.width, self.length else: raise AttrubuteErrir if __name__ == '__main__': r = Rectangle() r.width = 3 r.length = 4 print r.size # (30, 40) r.size = 30, 40 print r.width # 30 print r.length # 40

屬性的獲取順序

最后我們來看看熟悉的獲得順序:通過實例獲取其屬性,如果在__dict__中有相應的屬性,就直接返回其結果;如果沒有,會到類屬性中找。

看下面一個例子:

class A(object): author = 'qiwsir' def __getattr__(self, name): if name != 'author': return 'from starter to master.'if __name__ == '__main__': a = A() print a.author # qiwsir print a.lang # from starter to master.

當 a = A() 后,并沒有為實例建立任何屬性,或者說實例的__dict__是空的。但是如果要查看 a.author,因為實例的屬性中沒有,所以就去類屬性中找,發(fā)現(xiàn)果然有,于是返回其值 “qiwsir”。但是,在找 a.lang的時候,不僅實例屬性中沒有,類屬性中也沒有,于是就調用了__getattr__()方法。在上面的類中,有這個方法,如果沒有__getattr__()方法呢?如果沒有定義這個方法,就會引發(fā) AttributeError,這在前面已經看到了。

以上這篇Python對象的屬性訪問過程詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: Python 編程
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲免费专区| 精品中国亚洲| 美女久久一区| 亚洲一区二区三区高清不卡| 日韩中文字幕| 日韩视频1区| 婷婷五月色综合香五月| 国产日韩欧美一区二区三区在线观看 | 影院欧美亚洲| 亚洲开心激情| 久久影院一区二区三区| 国产一区二区三区亚洲综合| 黑人精品一区| 美女网站久久| 日韩av一区二区在线影视| 国产乱子精品一区二区在线观看 | 日韩黄色av| 国产成人黄色| 蜜桃久久久久久久| 婷婷激情久久| 日韩美女精品| 精品丝袜在线| 亚洲婷婷丁香| 亚洲天堂资源| 日韩在线观看中文字幕| 精品高清久久| 91精品国产乱码久久久久久久| 久久电影一区| 91欧美极品| 性欧美69xoxoxoxo| 国产精品网址| 久热综合在线亚洲精品| 捆绑调教日本一区二区三区| 亚洲一二三区视频| 欧美日韩水蜜桃| 麻豆精品在线| 亚欧成人精品| 久久久国产精品入口麻豆| 日韩精品一二三区| 久久精品欧美一区| 久久99国产精品视频| 中文字幕乱码亚洲无线精品一区| 日韩在线综合| 日韩在线麻豆| 国产精品日本| 1024精品一区二区三区| 日韩免费av| 久久毛片亚洲| 你懂的国产精品永久在线| 午夜在线精品偷拍| 亚洲欧洲一区二区天堂久久| 免费福利视频一区二区三区| 国产一区二区三区成人欧美日韩在线观看| 蜜臀va亚洲va欧美va天堂| 蜜桃tv一区二区三区| 欧美日韩国产高清| 国产韩日影视精品| 欧美亚洲国产一区| 精品视频91| 久久三级中文| 色爱综合网欧美| 国产黄大片在线观看| 日本久久综合| 免费日韩一区二区三区| 精品一区二区男人吃奶| 欧美一级二区| 久久99蜜桃| 久久久久久自在自线| 日韩av免费| 麻豆亚洲精品| 日韩一区二区三免费高清在线观看| 亚洲天堂日韩在线| 国产美女亚洲精品7777| 国产精品久久乐| 日韩欧美一区二区三区免费观看| 亚洲精品中文字幕乱码| 在线视频免费在线观看一区二区| 国产精品美女久久久| 蜜桃视频在线观看一区| 国产毛片精品久久| sm捆绑调教国产免费网站在线观看| 久久久久久久久99精品大| 亚洲天堂日韩在线| 福利一区二区免费视频| 亚洲免费黄色| 国产精品激情| 中文欧美日韩| 国产精品调教视频| 狠狠躁少妇一区二区三区| 亚洲免费影视| 精品久久99| 综合色就爱涩涩涩综合婷婷| 精品国产欧美日韩| 亚洲成人一区| 国产精品99一区二区三| 日本不卡一区二区三区| 欧美肉体xxxx裸体137大胆| 国产精品s色| 婷婷亚洲精品| 99视频精品| 国产成人77亚洲精品www| 日韩在线黄色| 视频一区欧美精品| 久久精品国产精品亚洲毛片| 久久香蕉精品| 99热国内精品| 老鸭窝一区二区久久精品| 日韩高清不卡一区| 黄色欧美日韩| 99国产精品免费视频观看| 久久成人av| 麻豆精品久久久| 国产精品久久久久久久久久白浆| 亚洲伊人影院| 午夜一区在线| 亚洲综合小说| 水蜜桃久久夜色精品一区的特点| 欧美午夜精品一区二区三区电影| 久久99影视| 久久国产电影| 欧美 日韩 国产精品免费观看| 久久午夜精品| 国产精品婷婷| 中文字幕日本一区二区| 亚洲制服欧美另类| 日本不卡高清视频| 欧美日本二区| 精品免费av一区二区三区| 激情不卡一区二区三区视频在线| 亚洲欧美日本国产| 国产精品视频一区二区三区四蜜臂| 日韩在线成人| 欧美经典一区| 国精品产品一区| 久久精品1区| 人人精品人人爱| 日韩超碰人人爽人人做人人添| 国产欧美一区二区三区米奇| 久久三级毛片| 亚洲一级高清| 日韩精品视频网站| 精品成人18| 国产视频亚洲| 欧美aa在线视频| 精品在线播放| 日本一区福利在线| 精品一区视频| 亚洲综合丁香| 欧美久久一区二区三区| 日韩一区二区在线免费| 免费高清在线一区| 精品久久不卡| 婷婷综合一区| 久久精品1区| 亚洲精品伊人| 午夜在线播放视频欧美| 久久精品国产99国产| 国产视频久久| 精品久久久网| 亚洲精品伦理| av高清一区| 国产精品一卡| 99tv成人| 欧美日韩a区| 午夜久久tv| 91一区二区三区四区| 亚洲精品观看| 国产二区精品| 四季av一区二区凹凸精品| 日本在线视频一区二区| 欧美三级精品| 日韩综合在线| 精品欧美视频| 国产精品成人自拍| 日韩精品成人| 亚洲免费资源| 中文字幕日本一区二区| 日韩一区二区免费看| 精品三级在线观看视频| 国产伦理一区| 国产精品网址| 国产精品免费大片| 国产探花一区在线观看| 欧美亚洲一区二区三区| 奇米亚洲欧美| 清纯唯美亚洲综合一区| 欧美影院精品| 国产极品一区| 国产成人精品免费视| 欧美日韩国产观看视频| 久久精品高清| 亚洲一区国产| 日韩一区二区三区四区五区| 亚洲日韩视频| 91成人精品观看| 另类欧美日韩国产在线| 国产精品成久久久久| 亚州av一区| 欧美黑人做爰爽爽爽| 国产精品久久观看|