python 裝飾器


# 裝飾器 - @ - 拿到內層函數的引用 - 直接使用內層函數
# 加強加法函數,輸出被調用過及調用的參數
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))
相關文章
相關標籤/搜索