Python裝飾器代碼詳解
一、理解裝飾器
所有東西都是對象(函數(shù)可以當做對象傳遞)
由于函數(shù)也是一個對象,而且函數(shù)對象可以被賦值給變量,所以,通過變量也能調用該函數(shù)。
def function_one():
print("測試函數(shù)")
#可以將一個函數(shù)賦值給一個變量,比如
foo =function_one #這里沒有在使用小括號,因為我們并不是在調用function_one函數(shù),而是在將它放在foo變量里。
foo()
'''
測試函數(shù)
Process finished with exit code 0
'''
閉包的概念:
1)函數(shù)嵌套
2)內部函數(shù)使用外部函數(shù)的變量
3)外部函數(shù)的返回值為內部函數(shù)
示例:
def outer_function(message):
def inner_function():
print(message)
return inner_function
func = outer_function("你好")
func() #你好
二、裝飾器原型
裝飾器的作用就是 不修改源代碼以及原函數(shù)調用方式的情況下 給原函數(shù)增加新的功能。
#將函數(shù)作為參數(shù)傳給另一個函數(shù)
def decorator_function(original_function):
def wrapper_function():
print('wrapper executed this before {}'.format(original_function.__name__))
original_function()
return wrapper_function
'''
返回wrapper_function而不是wrapper_function();這是因為當你把一對小括號放在后面,這個函數(shù)就會執(zhí)行;
然而如果你不放括號在它后面,那它可以被到處傳遞,并且可以賦值給別的變量而不去執(zhí)行它。
'''
def display():
print('display function ran')
decorator_display = decorator_function(display)
decorator_display()
運行結果:
wrapper executed this before display display function ran Process finished with exit code 0
1、不帶參數(shù)的裝飾器
def decorator_function(original_function):
def wrapper_function():
print('wrapper executed this before {}'.format(original_function.__name__))
original_function()
return wrapper_function
@decorator_function
def display(): #等價于display =decorator_function(display)
print('display function ran')
display()
運行結果:
wrapper executed this before display
display function ranProcess finished with exit code 0
2.帶參數(shù)的被裝飾的函數(shù)
def decorator_function(original_function):
def wrapper_function(*args,**kwargs):
print('wrapper executed this before {}'.format(original_function.__name__))
original_function(*args,**kwargs)
return wrapper_function
@decorator_function
def display():
print('display function ran')
@decorator_function
def display_info(name,age):
print('display_info ran with arguments ({},{})'.format(name,age))
display()
print('='*50)
display_info('Michal',20)
運行結果:
wrapper executed this before display
display function ran
==================================================
wrapper executed this before display_info
display_info ran with arguments (Michal,20)Process finished with exit code 0
運行如下代碼會出現(xiàn)一個問題
def decorator_function(original_function):
def wrapper_function(*args,**kwargs):
print('wrapper executed this before {}'.format(original_function.__name__))
original_function(*args,**kwargs)
return wrapper_function
@decorator_function
def display():
print('display function ran')
@decorator_function
def display_info(name,age):
print('display_info ran with arguments ({},{})'.format(name,age))
display_info = decorator_function(display_info)
print(display_info.__name__)
wrapper_function
Process finished with exit code 0
輸出的應該是display_info,這里的函數(shù)被wrapper_function替代了,重寫了我們函數(shù)的名字和注釋文檔(docstring)。Python中可以使用functools.wraps來解決這個問題。
from functools import wraps
def decorator_function(original_function):
@wraps(original_function)
def wrapper_function(*args,**kwargs):
print('wrapper executed this before {}'.format(original_function.__name__))
original_function(*args,**kwargs)
return wrapper_function
@decorator_function
def display():
print('display function ran')
@decorator_function
def display_info(name,age):
print('display_info ran with arguments ({},{})'.format(name,age))
display_info = decorator_function(display_info)
print(display_info.__name__)
運行結果:
display_info
Process finished with exit code 0
3.帶參數(shù)的裝飾器
在函數(shù)中嵌入裝飾器
from functools import wraps
def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打開logfile,并寫入內容
with open(logfile, 'a') as opened_file:
# 現(xiàn)在將日志打到指定的logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator
@logit()
def myfunc1():
pass
myfunc1()
# Output: myfunc1 was called
# 現(xiàn)在一個叫做 out.log 的文件出現(xiàn)了,里面的內容就是上面的字符串
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2()
# Output: myfunc2 was called
# 現(xiàn)在一個叫做 func2.log 的文件出現(xiàn)了,里面的內容就是上面的字符串
4.使用類作為裝飾器
class myDecorator(object):
def __init__(self, f):
print("inside myDecorator.__init__()")
f() # Prove that function definition has completed
def __call__(self):
print("inside myDecorator.__call__()")
@myDecorator
def aFunction():
print("inside aFunction()")
print("Finished decorating aFunction()")
aFunction()
運行結果:
inside myDecorator.__init__() inside aFunction() Finished decorating aFunction() inside myDecorator.__call__() Process finished with exit code 0
被裝飾后的函數(shù)aFunction()實際上已經是類myDecorator的對象。當再調用aFunction()函數(shù)時,實際上就是調用類myDecorator的對象,因此會調用到類myDecorator的__call__()方法。
因此使用類作為裝飾器裝飾函數(shù)來對函數(shù)添加一些額外的屬性或功能時,一般會在類的__init__()方法中記錄傳入的函數(shù),再在__call__()調用修飾的函數(shù)及其它額外處理。
class entryExit(object):
def __init__(self, f):
self.f = f
def __call__(self):
print("Entering", self.f.__name__)
self.f()
print("Exited", self.f.__name__)
@entryExit
def func1():
print("inside func1()")
@entryExit
def func2():
print("inside func2()")
func1()
func2()
運行結果:
Entering func1
inside func1()
Exited func1
Entering func2
inside func2()
Exited func2Process finished with exit code 0
5.使用對象作為裝飾器
空參:
from functools import wraps
class decorator_class:
def __init__(self):
print('執(zhí)行decorator_class類的__init__()方法')
def __call__(self, original_function):
print('執(zhí)行decorator_class類的__call__()方法')
@wraps(original_function)
def wrapped_function(*args, **kwargs):
print('call method executed this before {}'.format(original_function.__name__))
print('執(zhí)行' + original_function.__name__ + '()')
original_function(*args, **kwargs)
print(original_function.__name__ + '()執(zhí)行完畢')
return wrapped_function
@decorator_class()
def display_info(name,age):
print('display_info ran with arguments ({},{})'.format(name,age))
display_info('Michael',20)
運行結果如下:
執(zhí)行decorator_class類的__init__()方法
執(zhí)行decorator_class類的__call__()方法
call method executed this before display_info
執(zhí)行display_info()
display_info ran with arguments (Michael,20)
display_info()執(zhí)行完畢Process finished with exit code 0
帶參數(shù):
from functools import wraps
class decorator_class:
def __init__(self,arg1, arg2):
print('執(zhí)行decorator_class類的__init__()方法')
self.arg1 =arg1
self.arg2=arg2
def __call__(self, original_function):
print('執(zhí)行decorator_class類的__call__()方法')
@wraps(original_function)
def wrapped_function(*args, **kwargs):
print('執(zhí)行wrapped_function()')
print('call method executed this before {}'.format(original_function.__name__))
print('裝飾器參數(shù):', self.arg1, self.arg2)
print('執(zhí)行' + original_function.__name__ + '()')
original_function(*args, **kwargs)
print(original_function.__name__ + '()執(zhí)行完畢')
return wrapped_function
@decorator_class('Hello', 'World')
def display_info(name,age):
print('display_info ran with arguments ({},{})'.format(name,age))
display_info('Michael',20)
運行結果如下:
執(zhí)行decorator_class類的__init__()方法
執(zhí)行decorator_class類的__call__()方法
執(zhí)行wrapped_function()
call method executed this before display_info
裝飾器參數(shù): Hello World
執(zhí)行display_info()
display_info ran with arguments (Michael,20)
display_info()執(zhí)行完畢Process finished with exit code 0
示例2:
from functools import wraps
class logit(object):
def __init__(self, logfile='out.log'):
self.logfile = logfile
def __call__(self, func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# 打開logfile并寫入
with open(self.logfile, 'a') as opened_file:
# 現(xiàn)在將日志打到指定的文件
opened_file.write(log_string + '\n')
# 現(xiàn)在,發(fā)送一個通知
self.notify()
return func(*args, **kwargs)
return wrapped_function
def notify(self):
# logit只打日志,不做別的
pass
@logit()
def myfunc1():
pass
6.多層裝飾器的嵌套
#裝飾器1
def decorator1(func):
#定義裝飾之后的函數(shù)
def wrapper1():
# 裝飾器1
print('1-----裝飾1之前')
# 調用基本函數(shù)
func()
# 擴展功能2
print('1-----裝飾1之后')
return wrapper1
#裝飾器2
def decorator2(func):
#定義裝飾之后的函數(shù)
def wrapper2():
# 裝飾器2
print('2-----裝飾2之前')
# 調用基本函數(shù)
func()
# 擴展功能2
print('2-----裝飾2之后')
return wrapper2
#基本函數(shù)
@decorator2 # 第二步:test = decorator2(eat) = test2
@decorator1 # 第一步:test = decorator1(eat) = test1
def test():
print('測試')
#調用函數(shù)
test()
運行結果:
2-----裝飾2之前
1-----裝飾1之前
測試
1-----裝飾1之后
2-----裝飾2之后Process finished with exit code 0
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
Python使用sqlite3第三方庫讀寫SQLite數(shù)據(jù)庫的方法步驟
數(shù)據(jù)庫非常重要,程序的數(shù)據(jù)增刪改查需要數(shù)據(jù)庫支持,python處理數(shù)據(jù)庫非常簡單,而且不同類型的數(shù)據(jù)庫處理邏輯方式大同小異,下面這篇文章主要給大家介紹了關于Python使用sqlite3第三方庫讀寫SQLite數(shù)據(jù)庫的方法步驟,需要的朋友可以參考下2022-07-07

