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 lambda函數