##**特殊屬性**
– __name__ 類、函數、方法等的名字
– __module__ 類定義所在的模塊名
– __class__ 對象或類所屬的類
– __bases__ 類的基類的元組,順序為它們在基類列表中出現的順序
– __doc__ 類、函數的文檔字符串,如果沒有定義則為None
– __mro__ 類的mro,class.mro()返回的結果的保存在__mro__中
– __dict__ 類或實例的屬性,可寫的字典
##**查看屬性**
– __dir__
– 返回類或者對象的所有成員名稱列表。dir()函數就是調用__dir__()。如果提供__dir__(),則返回屬性的列表,否則會盡量從__dict__屬性中收集信息
– dir對于不同類型的對象具有不同的行為
– 對象是模塊,列表包含模塊的屬性名
– 對象是類型或者類對象,列表包含類的屬性名,及它的基類的屬性名
– 否則,列表包含對象的屬性名,它的類的屬性名和類的基類的屬性名
###舉例
a = Cat(‘tom’)
print(dir()) #從這往下類型數量依次遞加
print(dir(Animal))
print(dir(Animal.__dict__))
print(dir(a.__dict__))
##**魔術方法**
– __hash__ 內建函數hash()調用的返回值,返回一個整數。如果定義這個方法該類的實例就可hash
– __hash__方法返回hash的值做為set的key,但是去重,還需要__eq__來判斷是否相等
– hash相等只能說明hash沖突,不能說明兩個對象相等
– 可hash的對象必須提供__hash__方法,沒有提供的話,isinstance(p1,collections.Hashable)一定為False
– __eq__ 對應 == 操作符,判斷兩個對象是否相等,返回bool值
– __bool__ 沒有定義__bool__就找__len__()返回長度,非0為真。如果__len__()也沒有定義,那么所有實例都返回真
###舉例
class A:
def __init__(self):
self.a = ‘a’
self.b = ‘b’
def __hash__(self):
return 123 # hash恒定的值
def __eq__(self, other):
return self.a == other.a #判斷是否相等 如果return False便不相等 return True相等
print(bool(A())) # True # 若定義__len__,return 0 則返回False
print(hash(A()))
print((A(),A()))
print({A(),A()})
s = {A(),A()}
print(s)
###**可視化**
– __repr__ 內建函數repr()對一個對象獲取字符串表達。如果一個類定義__repr__(),但沒有定義__str__,那么在請求該類的實例的“非正式”的字符串表示時也將調用__repr__()
– __str__ str()函數、內建函數format、print()函數調用,需要返回對象的字符串表達
– __bytes__ bytes的時候,返回一個對象的bytes表達,即返回bytes對象
##**運算符重載**
– < : __lt__ <= : __le__ == : __eq__ > : __gt__ >= : __ge__ != : __ne__
– + : __add__ – : __sub__ * : __mul__ / : __truediv__ % : __mod__
– // : __floordiv__ ** : __pow divmod : __divmod__
– += : __iadd__ -= : __isub__ *= : __imul__ /= : __itruediv__ %= : __imod__
– //= : __ifloordiv__ **= : __ipow__
###練習
class A:
def __init__(self,x):
self.x = x
def __sub__(self,other):
return self.x – other.x
def __isub__(self,other):
tmp = self.x – other.x
return A(tmp)
def __str__(self):
return str(self.x)
x = A(5)
y = A(4)
print(x-y,x.__sub__(y))
x -= y
print(x)
##**運算符重載應用場景**
###**容器相關方法**
– __len__ 內建函數len(),返回對象的長度(>=0的整數),其實即使把對象當做容器類型看,就如同list或者dict。bool()函數調用的時候,如果沒有__bool__()方法,則會看__len__()方法是否存在,存在返回非0為真
– __iter__ 迭代容器時,調用,返回一個新的迭代器對象
– __contains__ in成員運算符,沒有實現,就調用__iter__方法遍歷
– __getitem__ 實現self[key]訪問。序列對象,key接受整數為索引,或者切片。對于set和dict,key為hashable。key不存在引發KeyError異常
– __setitem__ 和__getitem__的訪問類似,是設置值的方法
– __missing__ 字典使用__getitem__()調用是,key不存在執行該方法
###購物車用容器相關方法
class Item:
def __init__(self,name,**kwargs):
self.name = name
self.__spec = kwargs
def __repr__(self):
return str(self.name)
class Cart:
def __init__(self):
self.lst = []
def additem(self,item:Item):
self.lst.append(item)
def __add__(self, other):
self.lst.append(other)
return self
def __getitem__(self, index):
if isinstance(index,int):
return self.lst[index]
return None
def __iter__(self):
return iter(self.lst)
def __len__(self):
return len(self.lst)
def __setitem__(self, key, value):
self.lst[key] = value
a = Item(‘audi’,price = 100000,color = ‘black’)
b = Cart()
b.additem(a)
b+’fengtian’+”leike”+”teslia”
print(b[2])
##**可調用對象**
– __call__ 類中第一個該方法,實例就可以像函數一樣調用
– 可調用對象:定義一個類,并實例化得到其實例,將實例像函數一樣調用
###舉例
(1)
classs Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __call__(self,*args,**kwargs):
return “Point({},{})”.format(self.x,self.y)
p = Point(4,5)
print(p)
print(p())
(2)定義一個斐波那契數列的類,方便調用計算第n項
class Fib:
def __init__(self):
self.lst = [0,1,1]
def __call__(self, index):
if index < 0:
raise IndexError(“wrong index”)
if index < len(self.lst):
return self.lst[index]
for i in range(3,index+1):
self.lst.append(self.lst[i-2] + self.lst[i-1])
return self.lst[index]
def __iter__(self):
return iter(self.lst)
def __len__(self):
return len(self.lst)
def __str__(self):
return str(self.lst)
__repr__ = __str__
fib = Fib()
print(fib(100),len(fib))
for x in fib:
print(x)
##**上下文管理**
– 文件IO操作可以對文件對象使用上下文管理,使用with…as語法
– 仿照上面,自己的類也可以實現上下文管理
– 當一個文件同時實現了 __enter__()和__exit__()方法,它就屬于上下文管理對象
– __enter__ 進入與此對象相關的上下文。如果存在該方法,with語法會把該方法的返回值作為綁定到as子句中指定的變量上
– __exit__ 退出與此對象相關的上下文
>實例話對象的時候,并不會調用enter,進入with語句塊調用__enter__方法,然后執行語句體,最后離開with語句塊的時候,調用__exit__方法
###例子
class Point:
def __init__(self):
print(‘init’)
def __enter__(self):
print(‘enter’)
def __exit__(self,exc_type,exc_val,exc_tb):
print(‘exit’)
with Point() as f:
print(‘do something’)
##**上下文管理的安全性及注意點**
– 不管上例子with語句塊中是否是raise拋異常還是sys.exit(),enter和exit還是照常執行得。說明上下文管理很安全
– 如果想要with p as f: 中p和f相等。那么enter返回的要是self對象。
##enter方法和exit方法的參數
– __enter__ 沒有其他參數
– __exit__ 方法有3個參數
– __exit__ (self,exctype,excvalue,traceback),這三個參數都與異常有關
– exc_type 異常類型
– exc_value 異常的值
– traceback 異常的追蹤信息
– __exit__方法返回一個True,則異常會被壓制,正常輸出需要輸出的內容
###**類裝飾器練習**
import time
import datetime
from functools import wraps
class TimeIt:
def __init__(self,fn):
self.fn = fn
wraps(fn)(self)
def __enter__(self):
self.start = datetime.datetime.now()
def __call__(self, *args, **kwargs):
self.start = datetime.datetime.now()
ret = self.fn(*args, **kwargs)
self.delta = (datetime.datetime.now() – self.start).total_seconds()
print(self.delta)
return ret
def __exit__(self, exc_type, exc_val, exc_tb):
self.delta = (datetime.datetime.now() – self.start).total_seconds()
print(self.delta)
@TimeIt #add = TimeIt(add) 此時的add是個對象,所以可以調用add.__doc__
def add(x,y): #類裝飾器用不到enter和exit函數
“””
this is add method
“””
time.sleep(2)
return x + y
print(add(1,2))
print(add.__doc__)
##**上下文應用場景**
– 增強功能
– 在代碼執行的前后增加代碼,以增強其功能。類似裝飾器的功能
– 資源管理
– 打開了資源需要關閉,例如文件對象、網絡連接、數據庫連接等
– 權限驗證
– 在執行代碼之前,做權限的驗證,在__enter__中處理
##contextlib.contextmanager
– 它是一個裝飾器實現上下文管理,裝飾一個函數,而不用像類一樣實現__enter__和__exit__方法。
– 對下面的函數有要求,必須有yield,也就是這個函數必須返回一個生成器,且只有yield一個值
– 如果業務邏輯簡單可以使用函數加裝飾器方式,如果業務復雜,用類的方式加__enter__和__exit__方法方便
###例子
import contextlib
import time
import datetime
@contextlib.contextmanager
def add(x,y):
start = datetime.datetime.now() #相當于__enter__
try:
yield x + y #enter的返回值
finally:
delta = (datetime.datetime.now() – start).total_seconds() #相當于__exit__
print(delta)
with add(4,5) as f:
time.sleep(2)
#raise Exception(‘Error’)
print(f)
##**functools.total_ordering裝飾器**
– __lt__,__le__,__eq__,__gt__,__ge__ 是比較大小必須實現的方法,但是全部寫完太麻煩,所以使用@functools.total_ordering簡化代碼
###例子
from functools import total_ordering
@total_ordering
class Person:
def __init__(self,age):
self._age = _age
@property
def age(self):
return self._age
def __eq__(self,other):
return self._age == other.age
def __lt__(self,other):
return self._age < other.age
p1 = Person(’20’)
p2 = Person(’30’)
if p1 >= p2:
print(‘p1 older’)
else:
print(‘p2 older’)
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/88773