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=' ')
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=' ')

# 带参装饰器***
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=' ')

# 通过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 datetime
import time

def copyProperties(src): # 包装函数和被包装函数字符文档统一
def copyWrap(dest):
dest.__name__ = src.__name__
dest.__doc__ = src.__doc__
return dest
return copyWrap

def 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 result

print(add(10, 10000))
原文地址:https://www.cnblogs.com/lizitest/p/9614511.html