1. 程式人生 > >Python魔法方法之屬性訪問 ( __getattr__, __getattribute__, __setattr__, __delattr__ )

Python魔法方法之屬性訪問 ( __getattr__, __getattribute__, __setattr__, __delattr__ )

通常情況下,我們在訪問類或者例項物件的時候,會牽扯到一些屬性訪問的魔法方法,主要包括:

① __getattr__(self, name): 訪問不存在的屬性時呼叫

② __getattribute__(self, name):訪問存在的屬性時呼叫(先呼叫該方法,檢視是否存在該屬性,若不存在,接著去呼叫①)

③ __setattr__(self, name, value):設定例項物件的一個新的屬性時呼叫

④ __delattr__(self, name):刪除一個例項物件的屬性時呼叫

為了驗證以上,現列出程式碼如下:

class Test:
    def __getattr__(self, name):
        print('__getattr__')

    def __getattribute__(self, name):
        print('__getattribute__')

    def __setattr__(self, name, value):
        print('__setattr__')

    def __delattr__(self, name):
        print('__delattr__')

>>> t=Test()
>>> t.x
__getattribute__

如上述程式碼所示,x並不是Test類例項t的一個屬性,首先去呼叫 __getattribute__() 方法,得知該屬性並不屬於該例項物件;但是,按照常理,t.x應該列印 __getattribute__ 和__getattr__,但實際情況並非如此,為什麼呢?難道以上Python的規定無效嗎?

不要著急,聽我慢慢道來!

 例項物件屬性尋找的順序如下:

① 首先訪問 __getattribute__() 魔法方法(隱含預設呼叫,無論何種情況,均會呼叫此方法)

② 去例項物件t中查詢是否具備該屬性: t.__dict__ 中查詢,每個類和例項物件都有一個 __dict__ 的屬性

③ 若在 t.__dict__ 中找不到對應的屬性, 則去該例項的類中尋找,即 t.__class__.__dict__

④ 若在例項的類中也招不到該屬性,則去父類中尋找,即 t.__class__.__bases__.__dict__中尋找

⑤ 若以上均無法找到,則會呼叫 __getattr__ 方法,執行內部的命令(若未過載 __getattr__ 方法,則直接報錯:AttributeError)

以上幾個流程,即完成了屬性的尋找。

但是,以上的說法,並不能解釋為什麼執行 t.x 時,不列印 ’__getattr__'  啊?

你看,又急了不是,作為一名程式猿,一定要有耐心 ^_^

問題就出在了步驟的第④步,因為,一旦過載了 __getattribute__() 方法,如果找不到屬性,則必須要手動加入第④步,否則無法進入到 第⑤步 (__getattr__)的。

驗證一下以上說法是否正確:

方法一:採用object(所有類的基類)

class Test:
    def __getattr__(self, name):
        print('__getattr__')

    def __getattribute__(self, name):
        print('__getattribute__')
        object.__getattribute__(self, name)

    def __setattr__(self, name, value):
        print('__setattr__')

    def __delattr__(self, name):
        print('__delattr__')

        
>>> t=Test()
>>> t.x
__getattribute__
__getattr_

方法二:採用 super() 方法

class Test:
    def __getattr__(self, name):
        print('__getattr__')

    def __getattribute__(self, name):
        print('__getattribute__')
        super().__getattribute__(name)

    def __setattr__(self, name, value):
        print('__setattr__')

    def __delattr__(self, name):
        print('__delattr__')

        
>>> t=Test()
>>> t.x
__getattribute__
__getattr__

哈哈,以上介紹完畢,那麼 __setattr__ 和 __delattr__ 方法相對簡單了多了:

class Test:
    def __getattr__(self, name):
        print('__getattr__')

    def __getattribute__(self, name):
        print('__getattribute__')
        object.__getattribute__(self, name)

    def __setattr__(self, name, value):
        print('__setattr__')

    def __delattr__(self, name):
        print('__delattr__')

        
>>> t=Test()
>>> t.x=10
__setattr__
>>> del t.x
__delattr__

對了,再補充一點哈!

class Test:
    def __init__(self):
        self.count = 0
    def __setattr__(self, name, value):
        print('__setattr__')
        self.count += 1

        
>>> t=Test()
__setattr__
Traceback (most recent call last):
  File "<pyshell#364>", line 1, in <module>
    t=Test()
  File "<pyshell#363>", line 3, in __init__
    self.count = 0
  File "<pyshell#363>", line 6, in __setattr__
    self.count += 1
AttributeError: 'Test' object has no attribute 'count'

為什麼會出現上述情況呢?我還沒有呼叫__setattr__()呢,只是單純的定義了一個例項而已? @[email protected](咋回事?幻覺嗎)

看報錯資訊很容易明白,這是因為:

① __init__()時,給內部屬性 self.count進行了賦值;

② 賦值預設呼叫 __setattr__() 方法

③ 當呼叫 __setattr__()方法時,首先列印 '__setattr__'字串,而後執行 self.cout += 1操作

④ 當執行 self.cout 加 1 操作時,將會去尋找 count 這個屬性,然而,由於此時 __init__尚未完成,並不存在 count這個屬性,因此導致 'AttributeError' 錯誤

那麼該如何更改呢?可以這樣的:

class Test:
    def __init__(self):
        self.count = 0
    def __setattr__(self, name, value):
        print('__setattr__')
        super().__setattr__(name, value+1)

        
>>> t=Test()
__setattr__
>>> t.count
1

如何,問題解決了吧!

但是以上程式碼雖然解決了報錯的問題,深入體會一下,你會發現,採用此方法只是給 基類object增加了一個屬性 count,而並不是例項的屬性,因此,以上這種寫法避免使用

另外,再次將程式碼改進一下,如下:

class Test:
    def __setattr__(self, name, value):
        self.name = value

        
>>> t=Test()
>>> t.x=1
Traceback (most recent call last):
  File "<pyshell#413>", line 1, in <module>
    t.x=1
  File "<pyshell#411>", line 3, in __setattr__
    self.name = value
  File "<pyshell#411>", line 3, in __setattr__
    self.name = value
  File "<pyshell#411>", line 3, in __setattr__
    self.name = value
  [Previous line repeated 327 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object

居然報錯了,看報錯資訊為 “遞迴錯誤”,我沒用遞迴啊,怎麼會有這個錯誤呢?

其實,原因很簡單:當我們給 t.x 賦值時,呼叫了 __setattr__()方法,進入該方法;該方法中,又來了一次賦值(self.name = value),又會去呼叫 __setattr__() 方法,持續這個死迴圈(子子孫孫無窮盡也,必須要有一代斷子絕孫);

我們知道,系統的資源是有限的,丫的你老是申請資源不釋放,系統哪來的那麼多資源給你自己用?因此,Python直譯器規定,遞迴深度不得超過200(不同版本不一樣),你超過了,不好意思,不帶你玩了!

所以,我們只好改變上述的問題了:

t.x=2
>>> class Test:
    def __setattr__(self, name, value):
        print('__setattr__() been called')
        super().__setattr__(name, value)

>>> t=Test()
>>> t.x=1
__setattr__() been called
>>> t.x=2
__setattr__() been called

OK,至此,關於屬性操作的問題暫時完結吧!

轉載自:http://www.cnblogs.com/Jimmy1988/p/6804095.html

相關推薦

Python魔法方法屬性訪問 ( __getattr__, __getattribute__, __setattr__, __delattr__ )

通常情況下,我們在訪問類或者例項物件的時候,會牽扯到一些屬性訪問的魔法方法,主要包括:① __getattr__(self, name): 訪問不存在的屬性時呼叫② __getattribute__(self, name):訪問存在的屬性時呼叫(先呼叫該方法,檢視是否存在該屬

Python3 魔法方法屬性訪問

獲取 attr super() 父類 有關 self val color def 1、與屬性訪問有關的魔法方法 __getattr__(self,name) 定義當用戶試圖獲取某一不存在的屬性時的行為 __getattribute__(self,name) 定義當該

【Python045-魔法方法屬性訪問

一、屬性的幾種訪問方式 1、類.屬性名 >>> class C: def __init__(self): self.x = 'X-man' >>> c = C() >>> c.x 'X-man'

第045講:魔法方法屬性訪問

目錄 0. 請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式! 測試題 0. 請問以下程式碼的作用是什麼?這樣寫正確嗎?(如果不正確,請改正) 1. 自定義該類的屬性被訪問的行為,你應該重寫哪個魔法方法? 2. 在不上機驗證的情況下,你能推斷以下程式碼分別

python基礎-- 自定義屬性訪問 __setattr__, __getattr__,__getattribute__, __call__

object._getattr_(self, name) 例項instance通過instance.name訪問屬性name,只有當屬性name沒有在例項的__dict__或它構造類的__dict__或基類的__dict__中沒有找到,才會呼叫__getattr__。當屬性name可以通過正常機

python魔法函式__getattr____getattribute__

getattr 在訪問物件的屬性不存在時,呼叫__getattr__,如果沒有定義該魔法函式會報錯 class Test: def __init__(self, name, age): self.name = name self.age = age

Python魔法方法__getattr____getattribute__詳解

在Python中有這兩個魔法方法容易讓人混淆:__getattr__和getattribute。通常我們會定義__getattr__而從來不會定義getattribute,下面我們來看看這兩個的區別。 __getattr__魔法方法 class MyClass: def __init__(self,

python中的魔法方法屬性

這裡介紹一些比較常用的魔法方法: a.何為魔法屬性? 魔法屬性和魔法方法是python內建的一些屬性和方法。代表著特殊意義, 命名時會在前後加兩個下劃線,在執行特定的操作時,系統會自動呼叫 1.__doc__魔法方法:表

pythonpython魔法方法(待填坑)

絕對值 tle init cls -m del __init__ 另一個 trunc 參考博文:http://pyzh.readthedocs.io/en/latest/python-magic-methods-guide.html 參考博文英文原版:http://www

(10)魔法方法屬性、叠代器

方法 ini class nbsp strong 叠代 屬性 tom spa 構造方法 在類中定義構造函數 >>> class a: def __init__(self): self.age=42 >>> f=

python魔法方法詳解

返回 call __init__ and -m 描述 nbsp shift 賦值 文章來源:http://blog.csdn.net/koko66/article/details/42709279 據說,Python 的對象天生擁有一些神奇的方法,它們總被雙下劃線所包圍

python 魔法方法(學習過程的筆記)

但是 pow imp int 異或運算 pre bsp beijing getitem 有小夥伴會問,什麽是python的魔法方法,python的魔法方法有什麽用呢, 它們在面向對象的Python的處處皆是。它們是一些可以讓你對類添加“魔法”的特殊方法。 它們經常是兩個下劃

Python魔法方法

.cn images http bsp img 魔法方法 技術 logs pytho Python魔法方法

python魔術方法裝飾器

裝飾器 描述器 三個魔術方法:__get__()__set__()__delete__()object.__get__(self,實例名,owner) #owner = 屬主 ,instance = 屬主類owner的實例object.__set__(self,實例名,value)object.

Python 魔法方法詳解

自動 PE 轉換 str false oat 乘法 情況下 trace 據說,Python 的對象天生擁有一些神奇的方法,它們總被雙下劃線所包圍,他們是面向對象的 Python 的一切。他們是可以給你的類增加魔力的特殊方法,如果你的對象實現(重載)了這些方法中的某一個,那麽

python魔法方法大全

1、python魔法方法詳解: python魔法方法是可以修改過載的,如果你的物件實現(過載)了這些方法中的某一個,那麼這個方法就會在特殊的情況下被 Python 所呼叫,你可以定義自己想要的行為,而這一切都是自動發生的。Python 的魔術方法非常強大,瞭解正確的方法去使用非常重要! 以下為python

python魔法函式__getitem__

魔法函式會增強python類的型別,獨立存在 class Company: def __init__(self, employees): self.employees = employees def __getitem__(self, item): retu

SCRIPT65535:意外地呼叫了方法屬性訪問 問題解決

SCRIPT65535:意外地呼叫了方法或屬性訪問 瀏覽器環境為IE8,原因在於嘗試操作DOM的非法屬性 第一種情況,操作了一個DOM不該有的屬性 <input type="text" id="test"> 如果要改變這個dom的值應該是修改它的value屬

python 魔法方法詮釋

什麼是Python魔法方法     什麼是魔法方法呢?它們在面向物件的Python的處處皆是。它們是一些可以讓你對類新增“魔法”的特殊方法。 它們經常是兩個下劃線包圍來命名的(比如 init, lt )。但是現在沒有很好的文件來解釋它們。 所有的魔法方法都會在Python的官方

報錯_意外地呼叫了方法屬性訪問

在使用Jquery的append方法時,在 IE8 下報錯 報錯:意外地呼叫了方法或屬性訪問 進行定位發現報錯的位置為:jQuery的 b.appendChild(a) 方法 1、ie對動態app