Python--魔法方法(部分)

1、__call__

如果在類中實現了 __call__ 方法,那麼實例對象也將成爲一個可調用對象

什麼是可調用對象?

可調用對象:但凡是可以把一對括號()應用到某個對象身上都可稱之爲可調用對象,判斷對象是否爲可調用對象可以用函數 callable

這個魔法方法可以讓類的實例行爲表現的像函數一樣

示例:
 

class Demo:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __call__(self):
        self.x, self.y = self.y, self.x
        return self.x, self.y
demo = Demo(1, 2)  # 創建實例
res = demo()  # 實例可以象函數那樣執行,並傳入x y值,修改對象的x y
print(res)  # (2, 1)

 

2、__getattr__

動態返回一個屬性,當調用不存在的屬性時,Python會試圖調用__getattr__(self,'key')來獲取屬性,並且返回key。

class Student(object):
    def __getattr__(self, item):
        return item


x = Student()
print(x.age)  # age
print(x.name)  # name

 

3、__getattribute__

當每次調用屬性時,python會無條件進入__getattribute__中,不論屬性存在與否,這就是與__getattr__的區別

必須特別小心 __getattribute__ 方法,因爲 Python 在查找類的方法名稱時也將對其進行調用

class Student(object):
    def __getattr__(self, item):
        return "__getattr__ run...", item
    def __getattribute__(self, item):
        return "__getattribute__ run...", item

x = Student()
print(x.age)  # ('__getattribute__ run...', 'age')
print(x.name)  # ('__getattribute__ run...', 'name')

__getattribute__與__getattr__區別:

每次實例訪問屬性,都會經過__getattribute__函數。而當屬性不存在時,仍然需要訪問__getattribute__,不過接着要訪問__getattr__。這就好像是一個異常處理函數。

示例:
 

class Student(object):
    age = 18

    def __getattr__(self, item):
        print("not exist", item)
        return "__getattr__ run...", item
    def __getattribute__(self, item):
        # 此處爲了讓其找到屬性後調用object的默認__getattribute__進行返回
        # 否則會引發超過最大遞歸次數的異常
        print("__getattribute__ run...")
        return object.__getattribute__(self, item)

x = Student()
print(x.age)
print("-" * 40)
print(x.name)

結果如下:

__getattribute__ run...
18
----------------------------------------
__getattribute__ run...
not exist name
('__getattr__ run...', 'name')

 

4、__setattr__

__setattr__會攔截所有屬性的賦值語句。如果定義了這個方法,self.arrt = value 就會變成self,__setattr__("attr", value)。需要注意,當在__setattr__方法內對屬性進行賦值時,不可使用self.attr = value,因爲他會再次調用self,__setattr__("attr", value),則會形成無窮遞歸循環,最後導致堆棧溢出異常。應該通過對屬性字典做索引運算來賦值任何實例屬性,也就是使用self.__dict__['name'] = value.

class Demo(dict):

    def __getattr__(self, key):
        # 繼承dict類
        return self[key]

    def __setattr__(self, key, value):
        # 改變賦值行爲
        self[key] = value

x = Demo()
x.age = 100
print(x.age)

 

5、__dict__

返回對象具有的屬性與方法。對於類,是返回其全部屬性與方法,對於類實例,只返回定義好的屬性

ps:__dict__是dir()函數的子集,dir函數會自動尋找該對象的屬性與方法(包括從父類中繼承的屬性)

示例

class Demo():
    a = 1
    b = 2
    def __init__(self):
        self.name = 'cc'
        self.__dict__['age'] = 18
    def demo(self):
        pass
    
print(Demo.__dict__)  # 可以打印出全部屬性與方法地址
d = Demo()
print(d.__dict__)  # 只能打印self的屬性
print(dir(d))

{'__module__': '__main__', 'a': 1, 'b': 2, '__init__': <function Demo.__init__ at 0x1038a1700>, 'demo': <function Demo.demo at 0x1038a18b0>, '__dict__': <attribute '__dict__' of 'Demo' objects>, '__weakref__': <attribute '__weakref__' of 'Demo' objects>, '__doc__': None}


{'name': 'cc', 'age': 18}


['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'age', 'b', 'demo', 'name']
 

 

6、__SLOTS__

允許類可以獲得的屬性,不能動態的添加其他的屬性

示例

class Demo():
    __slots__ = ('age', 'name')


d = Demo()
d.age = 18
print(d.age)
d.name = "xx"
print(d.name)
d.id=1
print(d.id) # 異常

 

 

7、__setitem__

攔截所有字典類型的賦值,需要init方法配合使用,避免出現超出最大遞歸深度

class Demo():
    def __init__(self):
        self.dict = dict()

    def __setitem__(self, key, value):
        print(key+"...")
        self.dict[key] = value

    def __getitem__(self, key):
        print('調用getitem')
        return self.dict[key]

d = Demo()
d["name"] = "xx"

 

8、__contains__

判斷操作的時候會自動調用這個函數。

class Demo():
    def __init__(self, list):
        self.list = list

    def __contains__(self, item):
        print("contains run...")
        return item in self.list

d = Demo([1,2,3])
res = d.__contains__(1)
print(res) # 因爲__contains__定義返回的是一個表達式,所以此處返回ture

if 2 in d:
    pass

結果

contains run...
True
contains run...

 

9、__iter__和__next__

一個類,實現了__iter__,那麼就認爲它有迭代能力,通常此函數必須返回一個實現了__next__的對象,如果自己實現了,你可以返回self,這個返回值不是必須的;

注意,如果只實現了__iter__,那麼它是迭代對象,只有同時實現了__iter____next__纔是迭代器。

自定義可迭代對象示例

class Myiterator(object):
    def __init__(self, mylist):
        self.my_list = mylist
        self.current_index = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.current_index < len(self.my_list):
            self.current_index += 1
            return self.my_list[self.current_index - 1]
        else:
            raise StopIteration

class MyList(object):
    def __init__(self):
        self.my_list = list()
    def append_item(self, item):
        self.my_list.append(item)
    def __iter__(self):
        my_iterator = Myiterator(self.my_list)
        return my_iterator

m = MyList()
m.append_item(1)
m.append_item(2)

for item in m:
    print(item) 

結果爲1,2

 

自定義迭代器示例

class Myiterator(object):
    def __init__(self, mylist):
        self.my_list = mylist
        self.current_index = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.current_index < len(self.my_list):
            self.current_index += 1
            return self.my_list[self.current_index - 1]
        else:
            raise StopIteration


m = Myiterator([1,2,3])
print(next(m))
print(next(m))

結果也爲1,2

 

tips:python可以在魔法方法中調用內置方法

舉個簡單的例子

class Demo(object):
    def __init__(self):
        self.a = [1,2,3]
    def __len__(self):
        return len(self.a)

d = Demo()
print(len(d)) # 3

 

如果對你有幫助,可否在文章右側點個贊再走呢~~

 

本文爲原創,轉載請註明出處

 

python 如何避免大量的if else

python complex函數

python避坑篇

python部分高級用法

python開發手冊

python內置函數(下)

python內置屬性,函數

python異常處理

python lambda函數​​​​​​​

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章