# 裝飾器 - @ - 拿到內層函數的引用 - 直接使用內層函數
# 加強加法函數,輸出被調用過及調用的參數
def add(x, y):
print("call fun {}, {}+{}".format(add.__name__, x, y)) # 輸出到控制檯
return x + y
print(add(4, 5))
def add(x, y, file=None):
print("call fun {}, {}+{}".format(add.__name__, x, y), file = file) # 輸出到文件
return x + y
print(add(4, 5))
# print 耦合過高
# print 不屬於加法業務
# print 叫侵入式代碼
# 1 嵌套方式,避免侵入式代碼
print('------------------------')
def add(x, y):
return x + y
def logger(fn):
print('begin')
x = fn(4, 5)
print('end')
return x
print(logger(add))
# 2
def add1(x, y):
return x + y
def add2(x, y, z):
return x + y + z
def add3(x, y, *args, z, **kwargs):
return x + y + z
def logger(fn, *args, **kwargs): # 位置參數*args元組, 關鍵字參數**kwargs字典
print('begin')
x = fn(*args, **kwargs)
print('end')
return x
print(logger(add1, 4, 5))
print(logger(add2, 4, 5, 6))
print(logger(add3, 4, z=5, y=6))
# 3 柯里化
def add1(x, y):
return x + y
def add2(x, y, z):
return x + y + z
def add3(x, y, *args, z, **kwargs):
return x + y + z
def logger(fn):
def _logger(*args, **kwargs):
print('begin')
x = fn(*args, **kwargs)
print('end')
return x
return _logger
foo = logger(add1)
print(foo(10, 10))
print(logger(add1)(10, 100))
add1 = logger(add1)
print(add1(10, 1000))
# 裝飾器 @ ***
def logger(fn):
def _logger(*args, **kwargs):
print('begin')
x = fn(*args, **kwargs)
print('end')
return x
return _logger # 返回內層函數的引用**
@logger # 等價於add1 = logger(add1)
def add1(x, y):
return x + y
print(add1(10, 10000))
# 裝飾器
# 無參裝飾器
# 它是一個函數
# 有一個函數做爲它的形參
# 返回值也是一個函數
# 能夠使用@functionname方式,簡化調用
# 裝飾器是高階函數,即傳入函數,又返回函數
import datetime
import time
def logger(fn):
def wrap(*args, **kwargs):
# before 功能加強
print('args={}, kwargs={}'.format(args, kwargs))
start = datetime.datetime.now()
result = fn(*args, **kwargs)
# after 功能加強
duration = datetime.datetime.now() - start
print('function {} took {}s.'.format(fn.__name__, duration.total_seconds()))
return result
return wrap # 返回內層函數的引用**
@logger # 等價於 add = logger(add)
def add(x, y):
print('call add')
time.sleep(2)
return x + y
print(add(10, 10000))
# 裝飾器理解 - 避免侵入式
# 裝飾器函數 > 前置功能加強 > 被加強函數 > 後置功能加強
# 裝飾器函數能夠隨意更換
# 文檔字符串
# 在函數語句塊的第一行,且吸管式多行文本,使用三引號
# 慣例是首字母大寫,第一行寫概述,空一行,第三行寫詳細描述
# 能夠使用特殊屬性__doc__訪問這個文檔
def add(x, y):
"""
This is a function
:param x:
:param y:
:return:
"""
result = x + y
return result
print(add(10, 10))
print(add.__name__, add.__doc__, sep='\n')
print('----------------------------------')
# 文檔字符串和裝飾器
# 解決被裝函數的文檔字符串沒法顯示問題
import datetime
import time
def copyProperties(src, dest): # 包裝函數和被包裝函數字符文檔統一
dest.__name__ = src.__name__
dest.__doc__ = src.__doc__
def logger(fn):
def wrap(*args, **kwargs):
"""
This is wrapper
"""
# before 功能加強
print('args={}, kwargs={}'.format(args, kwargs))
start = datetime.datetime.now()
result = fn(*args, **kwargs)
# after 功能增
duration = datetime.datetime.now() - start
print('function {} took {}s.'.format(fn.__name__, duration.total_seconds()))
return result
copyProperties(fn, wrap)
return wrap # 返回內層函數的引用**
@logger # add = logger(add)
def add(x, y):
"""
This is a function
:param x:
:param y:
:return:
"""
result = x + y
return result
print(add(10, 10000))
print(add.__name__, add.__doc__, sep='\n')
# 帶參裝飾器***
import datetime
import time
def copyProperties(src): # 包裝函數和被包裝函數字符文檔統一
def copyWrap(dest):
dest.__name__ = src.__name__
dest.__doc__ = src.__doc__
return dest
return copyWrap
def logger(fn):
# @copyProperties(fn)
# 1 先不看@符號,返回copyWrap
# 2 @copyProperties(fn) 將其下面的函數(logWrap)做爲參數,再拿到logWrap對象
@copyProperties(fn) # wrap = copyWrap(logger.wrap) 帶參裝飾器***
def logWrap(*args, **kwargs):
"""
This is wrapper
"""
# before 功能加強
print('args={}, kwargs={}'.format(args, kwargs))
start = datetime.datetime.now()
result = fn(*args, **kwargs)
# after 功能增
duration = datetime.datetime.now() - start
print('function {} took {}s.'.format(fn.__name__, duration.total_seconds()))
return result
return logWrap # 返回內層函數的引用**
@logger # add = logger(add)
def add(x, y):
"""
This is a function
:param x:
:param y:
:return:
"""
result = x + y
return result
print(add(10, 10000))
print(add.__name__, add.__doc__, sep='\n')
# 經過copyProperties函數將被包裝函數的屬性覆蓋掉包裝函數
# 凡是被裝飾的函數都須要複製這些屬性,這個函數很通用
# 能夠將複製屬性的函數構建成裝飾器函數,帶參裝飾器
# 過濾執行時間過長的函數**
import datetime
import time
def logger(time):
def __logger(fn):
def wrap(*args, **kwargs):
# before 功能加強
start = datetime.datetime.now()
result = fn(*args, **kwargs)
# after 功能加強
duration = (datetime.datetime.now() - start).total_seconds()
if duration > time:
print('function {} took too long time -> {}s.'.format(fn.__name__, duration))
return result
return wrap # 返回內層函數的引用**
return __logger
@logger(3) # 等價於 add = logger(3)(add),其中logger(3)返回的是__logger
def add(x, y):
print('call add')
time.sleep(5)
return x + y
print(add(4, 5))
# 過濾執行時間在必定範圍內的函數**
import datetime
import time
def logger(time1, time2):
def __logger(fn):
def wrap(*args, **kwargs):
# before 功能加強
start = datetime.datetime.now()
result = fn(*args, **kwargs)
# after 功能加強
duration = (datetime.datetime.now() - start).total_seconds()
if duration > time1 and duration < time2:
print('function {} took too long time -> {}s.'.format(fn.__name__, duration))
return result
return wrap # 返回內層函數的引用**
return __logger
@logger(3, 10) # 等價於 add = logger(3)(add),其中logger(3)返回的是__logger
def add(x, y):
print('call add')
time.sleep(6)
return x + y
print(add(4, 5))
# 帶參裝飾器
# 它是一個函數
# 函數做爲它的形參
# 返回值是一個不帶參的裝飾器函數
# 使用@functionname(參數列表)方式調用
# 能夠看到在裝飾器外層又加了一層函數
# 實踐:替換print,以便輸出到其餘存儲***import datetimeimport timedef copyProperties(src): # 包裝函數和被包裝函數字符文檔統一 def copyWrap(dest): dest.__name__ = src.__name__ dest.__doc__ = src.__doc__ return dest return copyWrapdef logger(duration, func=lambda name, delta:print('function {} took too long time -> {}s.'.format(name, delta))): def __logger(fn): # @copyProperties(fn) # 1 先不看@符號,返回copyWrap # 2 @copyProperties(fn) 將其下面的函數(logWrap)做爲參數,再拿到logWrap對象 @copyProperties(fn) # wrap = copyWrap(logger.wrap) 帶參裝飾器*** def logWrap(*args, **kwargs): """ This is wrapper """ # before 功能加強 start = datetime.datetime.now() result = fn(*args, **kwargs) # after 功能增 delta = (datetime.datetime.now() - start).total_seconds() if delta > duration: func(fn.__name__, delta) return result return logWrap # 返回內層函數的引用** return __logger@logger(3) # add = logger(add)def add(x, y): """ This is a function :param x: :param y: :return: """ time.sleep(5) result = x + y return resultprint(add(10, 10000))