天天看點

python裝飾器class_python裝飾器進階用法

1.裝飾類

下面,直接來看代碼是如何實作裝飾類的:

defdecorator(aClass):classnewClass:def __init__(self, age):

self.total_display=0

self.wrapped=aClass(age)defdisplay(self):

self.total_display+= 1

print("total display", self.total_display)

self.wrapped.display()returnnewClass

@decorator # 接受一個類參數classBird:def __init__(self, age):

self.age=agedefdisplay(self):print("My age is",self.age)

eagleLord= Bird(5)for i in range(3):

eagleLord.display()

在decorator中,我們傳回了一個新類newClass。在新類中,我們記錄了原來類生成的對象(self.wrapped),并附加了新的屬性total_display,用于記錄調用display的次數。我們也同時更改了display方法。

通過修改,我們的Bird類可以顯示調用display的次數了

2.裝飾器捕捉異常

有一個check類,其中有方法read_value()。由于某些原因,方法read_value有可能抛出異常而使程式崩潰,是以需要對整個方法做try....except處理,如:

沒有捕捉異常之前:

classcheck(object):def __init__(self):pass

defreceive(self):print('receive from exception.')defread_value(self):print('here i will do something')'a' + 1 # 這裡會報異常c=check()

c.read_value()

加了try....except捕捉異常後:

classcheck(object):def __init__(self):pass

defreceive(self):print('receive from exception.')defread_value(self):try:print('here i will do something')'a' + 1

exceptException as e:print(e)

c=check()

c.read_value()

雖然程式不會報出異常,但這樣處理,有些醜陋。來看看裝飾器是如何處理的:

defcatch_exception(func):def wrapper(*args,**kwargs):try:

u= func(*args,**kwargs)returnuexceptException:return 'an exception raised'

returnwrapperclasscheck(object):def __init__(self):pass

defreceive(self):print('receive from exception.')

@catch_exceptiondefread_value(self):print('here i will do something')'a' + 1c=check()

c.read_value()

很好,使用裝飾器,來裝飾函數,這樣使我們的代碼更加pythonic。但是,如果程式報出異常後,調用類中的另外一個方法,那怎麼辦?很簡單,給裝飾器加上一個參數self:

defcatch_exception(func):def wrapper(self,*args,**kwargs):try:

u= func(self,*args,**kwargs)returnuexceptException:

self.receive()return 'an exception raised'

returnwrapperclasscheck(object):def __init__(self):pass

defreceive(self):print('receive from exception.')

@catch_exceptiondefread_value(self):print('here i will do something')'a' + 1c=check()

c.read_value()

有木有感覺,很神奇。

3.裝飾器注意事項

3.1函數的屬性會發生變化

裝飾器動态建立的新函數替換原來的函數,但是,新函數缺少很多原函數的屬性,如docstring和名字。