天天看點

python之__getattribute__方法 || __getattr__方法 || __setattr__方法 ||__delattr__方法 || __dir__方法

前言

python語言的五個魔術方法,他們都與Python屬性相關,涉及擷取、删除和修改。

__getattribute__方法

源碼如下:

python之__getattribute__方法 || __getattr__方法 || __setattr__方法 ||__delattr__方法 || __dir__方法

實戰演練:

①首先定義一個類并通路類的對象屬性:

class User:

    def __init__(self, name, sex):
        self.name = name
        self.sex = sex


u1 = User(name='li', sex='male')
print(u1.name)      

運作結果:

python之__getattribute__方法 || __getattr__方法 || __setattr__方法 ||__delattr__方法 || __dir__方法

②接着在該類中加入 __getattribute__

class User:

    def __getattribute__(self, item):
        return '無論對象是否存在該屬性,都會傳回此值'

    def __init__(self, name, sex):
        self.name = name
        self.sex = sex


u1 = User(name='li', sex='male')
print(u1.name)
print(u1.age)      

運作結果:【因為User類中的 __getattribute__ 魔方方法重寫了基類object類的方法,是以此時的 __getattribute__

python之__getattribute__方法 || __getattr__方法 || __setattr__方法 ||__delattr__方法 || __dir__方法

__getattribute__

①觸發時間:在通路對象成員屬性的時候觸發,無論對象的成員屬性是否存在。

②作用:對屬性進行一些處理。

③參數:

  • self為目前對象;
  • item是通路屬性名稱的字元串。

④傳回值:對象的屬性值。

【注意】

① __getattribute__方法的是傳回值千萬不能用 self.name

例如:

class User:

    def __getattribute__(self, item):
        return self.name

    def __init__(self, name, sex):
        self.name = name
        self.sex = sex


u1 = User('li', 'male')
print(u1.name)      

運作結果:

python之__getattribute__方法 || __getattr__方法 || __setattr__方法 ||__delattr__方法 || __dir__方法

②可以使用 object.__getattribute__

例如:

class User:

    def __getattribute__(self, item):
        return object.__getattribute__(self, item)

    def __init__(self, name, sex):
        self.name = name
        self.sex = sex


u1 = User('li', 'male')
print(u1.name)      

運作結果:

python之__getattribute__方法 || __getattr__方法 || __setattr__方法 ||__delattr__方法 || __dir__方法

__getattr__方法

  • 觸發時間:在通路不存在的對象屬性的時候觸發。
  • 作用:通路不存在的屬性時候,不會報錯。
  • 參數:self為目前對象,item是通路屬性名稱的字元串。
  • 傳回值:屬性值。

我們舉個簡單例子,就是使用者可能會輸出屬性名稱,那我們都統一傳回name屬性。

class User:

    def __getattr__(self, item):
        return self.name

    def __init__(self, name, sex):
        self.name = name
        self.sex = sex


u1 = User('li', 'male')
print(u1.na2me)

li      

__setattr__方法

  • 觸發時間:添加和修改對象屬性的時候觸發。
  • 作用:限制添加和修改對象屬性的操作。
  • 參數:self為目前對象,key為設定對象屬性名稱, value為設定的值。
  • 傳回值:無。

例如,我們讓使用者可以改name,不能改sex。

__delattr__方法

  • 觸發時間:删除對象屬性的時候觸發。
  • 作用:限制添加和修改對象屬性的操作。
  • 參數:self為目前對象,item為删除對象屬性名稱。
  • 傳回值:無。

例如:我們可以讓使用者删除sex,但是不能删除name。

class User:

    def __delattr__(self, item):
        if item == 'sex':
            pass
        else:
            object.__delattr__(self, item)

    def __init__(self, name, sex):
        self.name = name
        self.sex = sex


u1 = User('li', 'male')
del u1.sex
print(u1.sex)
del u1.name
print(u1.name)

male
AttributeError: 'User' object has no attribute 'name'      

__dir__方法以及Python __dict__與dir()差別

Python下一切皆對象,每個對象都有多個屬性(attribute),Python對屬性有一套統一的管理方案。

​__dict__與dir()​

​的差別:

  1. dir()是一個函數,傳回的是list;
  2. ​__dict__​

    ​是一個字典,鍵為屬性名,值為屬性值;
  3. dir()用來尋找一個對象的所有屬性,包括​

    ​__dict__​

    ​​中的屬性,​

    ​__dict__​

    ​是dir()的子集;

dir()是Python提供的一個API函數,dir()函數會自動尋找一個對象的所有屬性(包括從父類中繼承的屬性)。

一個執行個體的​

​__dict__​

​屬性僅僅是那個執行個體的執行個體屬性的集合,并不包含該執行個體的所有有效屬性。是以如果想擷取一個對象所有有效屬性,應使用dir()。

print dir(A)
'''
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'class_f', 'class_var', 'fun', 'level1', 'level2', 'name', 'num', 'static_f']
'''
a_dict = a.__dict__.keys()
A_dict = A.__dict__.keys()
object_dict = object.__dict__.keys()
print a_dict  
print A_dict  
print object_dict 
'''
['fun', 'level1', 'age', 'name']

['__module__', 'level2', 'num', 'static_f', '__dict__', '__weakref__', '__init__', 'class_f', 'class_var', 'fun', '__doc__']

['__setattr__', '__reduce_ex__', '__new__', '__reduce__', '__str__', '__format__', '__getattribute__', '__class__', '__delattr__', '__subclasshook__', '__repr__', '__hash__', '__sizeof__', '__doc__', '__init__']
'''

#因為每個類都有一個__doc__屬性,是以需要去重,去重後然後比較
print set(dir(a)) == set(a_dict + A_dict + object_dict)  #True      

屬性通路順序

最後,屬性通路的順序如下:

  • __getattribute__
  • 資料描述符
  • 目前對象的屬性
  • 類的屬性
  • 非資料描述符
  • 父類的屬性
  • __getattr__