日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python属性使用教程_Python对象的属性访问过程详解

發布時間:2025/3/19 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python属性使用教程_Python对象的属性访问过程详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

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

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

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

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

4. 執行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 f

c = C()

print c.a

print c.b

print c.class_field

print c.c

輸出:

a

b

class field

Method C.__getattr__ has been called.

c

PS: python里的attribute與property不同, 當使用了property里, property的解析優先級最高. 詳見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': ,

'season': 'the spring of class',

'module': 'main',

'weakref': ,

'doc': None})

通過兩種方法訪問類屬性

>>> Spring.dict['season']

'the spring of class'

>>> Spring.season

'the spring of class'

發現__dict__有個'season'鍵,這就是這個類的屬性,其值就是類屬性的數據.

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

>>> 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': , 'season': 'the spring of class', 'module': 'main', 'weakref': , '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': , 'weakref': , 'doc': None})

>>> Spring.dict['flower']

'peach'

實例中的__dict__并沒有變化

>>> s.dict

{'lang': 'python'}

實例中找不到flower屬性,調用類屬性

>>> s.flower

'peach'

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

# 定義類

>>> class Spring(object):

... def tree(self, x):

... self.x = x

... return self.x

...

# 方法tree在__dict__里面

>>> Spring.__dict__

dict_proxy({'__dict__': ,

'__weakref__': ,

'__module__': '__main__',

'tree': ,

'__doc__': None})

>>> Spring.__dict__['tree']

建立實例,但是__dict__中沒有方法

>>> t = Spring()

>>> t.dict

{}

執行方法

>>> t.tree("xiangzhangshu")

'xiangzhangshu'

實例方法(t.tree('xiangzhangshu'))的第一個參數(self,但沒有寫出來)綁定實例 t,透過 self.x 來設定值,即給 t.__dict__添加屬性值。

>>> t.dict

{'x': 'xiangzhangshu'}

如果沒有將x 賦值給 self 的屬性,而是直接 return,結果發生了變化

>>> class Spring(object):

... def tree(self, x):

... return x

>>> s = Spring()

>>> s.tree("liushu")

'liushu'

>>> s.dict

{}

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

使用__slots__優化內存使用

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

# 在類中定義__slots__屬性就是說這個類中所有實例的屬性都在這兒了,如果幾百萬個實例同時活動,能節省大量內存

>>> 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 "", line 1, in

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

如果再給類屬性賦值

>>> Spring.flower = "ziteng"

>>> t.flower

'ziteng'

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

在類中定義__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,按照本節開頭的例子,是要報錯的。但是,由于在這里使用了__getattr__(self, name) 方法,當發現 x 不存在于對象的__dict__中的時候,就調用了__getattr__,即所謂“攔截成員”。

>>> a = A()

>>> a.x

You use getattr

給對象的屬性賦值時候,調用了__setattr__(self, name, value)方法,這個方法中有一句 self.dict[name] = value,通過這個語句,就將屬性和數據保存到了對象的__dict__中

>>> a.x = 7

You 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.y

you are useing getattribute

Traceback (most recent call last):

File "", line 1, in

File "", line 4, in getattribute

AttributeError: 'B' object has no attribute 'y'

Property函數

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可以將函數封裝為屬性

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

if 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方法將函數封裝為屬性,更優雅

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

使用魔術方法實現:

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] = value

def 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,因為實例的屬性中沒有,所以就去類屬性中找,發現果然有,于是返回其值 “qiwsir”。但是,在找 a.lang的時候,不僅實例屬性中沒有,類屬性中也沒有,于是就調用了__getattr__()方法。在上面的類中,有這個方法,如果沒有__getattr__()方法呢?如果沒有定義這個方法,就會引發 AttributeError,這在前面已經看到了。

以上這篇Python對象的屬性訪問過程詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持菜鳥教程www.piaodoo.com。

總結

以上是生活随笔為你收集整理的python属性使用教程_Python对象的属性访问过程详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。