在實際應用中, 我們如果要把業務函式增強, 但是我們并不想在業務函式中加入非業務的侵入式代碼, 我們應該把業務功能函式和增強功能函式分開. 所以就出現了以下函式寫法.
def add(x, y):
return x + y
def logger(fn):
print('begin') # 增強的輸出
x = fn(4, 5)
print('end') # 增強的功能
return x
print(logger(add))
但是這個寫法會破壞了函式的封裝, 所有的引數應該以傳參的方式傳進函式所以以下加入了可變引數的改進
def add(x, y):
return x + y
def logger(fn, *args, **kwargs):
print('begin') # 增強的輸出
x = fn(*args, **kwargs)
print('end') # 增強的功能
return x
print(logger(add, 5, y=60))
但是這個形式不好看, 所以我們需要把引數和函式需要分開, 就使用了一個柯里化的寫法
def add(x, y):
return x + y
def logger(fn):
def wrapper(*args, **kwargs):
print('begin') # 增強的輸出
x = fn(*args, **kwargs)
print('end') # 增強的功能
return x
return wrapper
print(logger(add)(5, y=60))
#也可以換一種寫法
#add = logger(add)
#print(add(x=5, y=10)
因為python中會有大量的這種寫法出現, 所以python就提供了一個語法糖—裝飾器
裝飾器(無參)
def logger(fn):
def wrapper(*args, **kwargs):
print('begin') # 增強的輸出
x = fn(*args, **kwargs)
print('end') # 增強的功能
return x
return wrapper
@logger # 等價于add = logger(add)
def add(x, y):
return x + y
print(add(45, 40))
無參裝飾器的增強功能完善(1)
import datetime
import time
def logger(fn):
def wrapper(*args, **kwargs):
# before功能的增強
print("args = {}, kwargs = {}".format(args, kwargs))
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
# after功能的增強
duration = datetime.datetime.now() - start
print("function {} took {}s.".format(fn.__name__, duration.total_seconds()))
return ret
return wrapper
# add1 = logger(add1)
# print(add1(5, 10))
@logger # add = logger(add)
def add(x, y):
print("==== call add ====")
time.sleep(2)
return x + y
print(add(4, y=7))
Python里面的檔案字串是在函式陳述句塊的第一行, 且習慣是多行的文本, 所以多使用三引號.
def logger(fn):
def wrapper(*args, **kwargs):
"""I am wrapper"""
print('begin')
ret = fn(*args, **kwargs)
print('end')
return ret
return wrapper
@logger # add = logger(add)
def add(x, y):
"""This is a function for add"""
return x + y
print("name = {}, doc = {}".format(add.__name__, add.__doc__))
但是又因為裝飾器的原因, 呼叫不了add函式內的檔案字串. 所以提供了一個函式, 被封裝函式屬性=copy=>包裝函式屬性
def copy_properties(src, dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
def logger(fn):
def wrapper(*args, **kwargs):
"""I am wrapper"""
print('begin')
x = fn(*args, **kwargs)
print('end')
return x
copy_properties(fn, wrapper)
return wrapper
@logger # add = logger(add)
def add(x, y):
"""
This is a function for add"""
return x + y
print("name = {}, doc = {}".format(add.__name__, add.__doc__))
因為以上寫法是可以改裝成裝飾器的, 所以就引出了一個帶參裝飾器
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
return dst
return _copy
def logger(fn):
@copy_properties(fn) # wrapper = wrapper(fn)(wrapper)
def wrapper(*args, **kwargs):
"""I am wrapper"""
print('begin')
x = fn(*args, **kwargs)
print('end')
return x
return wrapper
@logger # add = logger(add)
def add(x, y):
"""This is a function for add"""
return x + y
print("name = {}, doc = {}".format(add.__name__, add.__doc__))
然后又引出了一需求: 獲取函式的執行時長, 對時長超過閾值的函式記錄一下
import datetime
import time
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
return dst
return _copy
def logger(duration):
def _logger(fn):
@copy_properties(fn)
def wrapper(*args, **kwargs):
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
delta = (datetime.datetime.now() - start).total_seconds()
print('so slow') if delta > duration else print('so fast')
return ret
return wrapper
return _logger
@logger(5) # add = logger(5)(add)
def add(x, y):
time.sleep(3)
return x + y
print(add(5, 6))
將記錄的功能提取出來, 這樣就可以通過外部提供的函式來靈活地控制輸出
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
dst.__qualname__ = src.__qualname__
return dst # 原函式需要回傳繼續往下執行
return _copy
def logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))):
def _logger(fn):
@copy_properties(fn)
def wrap(*args, **kwargs):
start = datetime.datetime.now()
time.sleep(5)
ret = fn(*args, **kwargs)
delta = (datetime.datetime.now() - start).total_seconds()
if delta > duration:
func(fn.__name__, duration)
return ret
return wrap
return _logger
# add1 = logger(add1)
# print(add1(5, 10))
@logger(3) # add = logger(50)(add)
def add(x, y):
print("==== call add ====")
time.sleep(2)
return x + y
print(add(4, y=7))
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/231000.html
標籤:python
