python __setattr__、__getattr__、__getattribute__全面詳解

智慧先行者發表於2017-10-29

一、屬性引用函式

hasattr(obj,name[,default])
getattr(obj,name)
setattr(obj,name,value)
delattr(obj,name)

 

二、屬性引用過載


def __setattr__(self,key,value): 
  1.攔截所有屬性的賦值語句。
  2.self.attr=value 相當於 self.__setattr__("attr",value)。
  3.如果在__setattr__中對任何self屬性賦值,都會再呼叫__setattr__,導致無窮遞迴迴圈。只能self.__dict__["attr"]=value 。

 

def __getattribute__(self, key): 
  1.攔截所有的屬性獲取,包括未定義的屬性,self.__dict__,等點號運算。
  2.所有的屬性先在__getattribute__中沒有找到,就會丟擲AttributeError,__getattr__接收這個錯誤,此時進入__getattr__中繼續尋找。
  3.如果__getattribute__沒有丟擲AttributeError,將不會呼叫__getattr__。


def __getattr__(self, key): 
  攔截self.attr運算。當在__dict__中未找到該屬性時,在類屬性中也沒有找到該屬性,並且在繼承樹中也沒有找到該屬性,就會呼叫這個方法。


def __delattr__(self,key): 刪除屬性

 

三、示例

class Square:  # 正方形

    def __init__(self, l):
        self.length = l  # 邊長

    def __getattr__(self, key):
        if key == "area":
            return "__getattr__被呼叫了,為了area"


sq = Square(10)
print(sq.length)  # 10
print(sq.area)  # __getattr__被呼叫了,為了area

 

class Square:  # 正方形

    def __init__(self, l):
        pass

    def __getattr__(self, key):
        print("__getattr__被呼叫了")
        if key == "length":
            return 1111

    def __getattribute__(self, key123):
        print("__getattribute__被呼叫了")
        # return 123456
        raise AttributeError


sq = Square(10)
print(sq.length)
# __getattribute__被呼叫了
# __getattr__被呼叫了
# 1111

 

class Square:  # 正方形

    def __init__(self,l):
        pass

    def __getattr__(self, key):
        print("__getattr__被呼叫了")
        raise AttributeError("1111111")

    def __getattribute__(self, key123):
        print("__getattribute__被呼叫了")
        return 123456
        # raise AttributeError


sq = Square(10)
print(sq.length)
# __getattribute__被呼叫了
# 123456

 

 

class Square:  # 正方形

    def __init__(self, l):
        self.length = l  # 邊長

    def __setattr__(self, key, value):
        print("呼叫__setattr__", "key=", key)
        if key == "perimeter":
            self.__dict__["length"] = value / 4
            self.__dict__["perimeter"] = value
        if key == "length":
            self.__dict__["length"] = value
            self.__dict__["perimeter"] = value * 4

    def __getattr__(self, key):
        print("呼叫__getattr__ ,", "key =", key)
        if key == "area":
            return 960

    def __getattribute__(self, key123):
        print("呼叫__getattribute__ ,", "key123 =", key123)
        return object.__getattribute__(self, key123)


sq = Square(10)
# 呼叫__setattr__
# 呼叫__getattribute__ , key123 = __dict__      此時執行self.__dict__["length"] = value
# 呼叫__getattribute__ , key123 = __dict__      此時執行self.__dict__["perimeter"] = value * 4


print(sq.length)
# 呼叫__getattribute__ , key123 = length      此時執行self.length = l  # 邊長

print(sq.perimeter)
# 呼叫__getattribute__ , key123 = perimeter
# 40

print(sq.area)
# 呼叫__getattribute__ , key123 = area
# 呼叫__getattr__ , key = area
# 960

 

相關文章