简单装饰器实现斐波那契数列

# coding:utf8
def memo(func):
cache = {}

def wrapp(*args, **kwargs):
if args not in cache:
cache[args] = func(*args)
return cache[args]

return wrapp


# 语法糖实现 等价于fib=memo(fib)
@memo
def fib(n):
if n <= 1:
return 1
return fib(n - 1) + fib(n - 2)


# fib=memo(fib)
print fib(10)

保留原函数属性

# coding:utf8
'''
>>>def f (a=1,b=[1,2,3]):
''' doc for f func'''
g = 100
return lambda k : g +2
>>>f.func_
f.func_closure # 函数闭包 g = f() ; g.__closure__ 访问闭包
f.func_dict
f.func_name
f.func_code
f.func_doc
f.func_defaults #默认参数 (1, [1, 2, 3])
f.func_globals
'''

# ------------------------
# 保留原来函数的属性
# ------------------------
#coding:utf8
def w(func):
def wapper(*args, **kwargs):
''' wapper function '''
print('In wapper')
func(*args, **kwargs)
return wapper

@w
def example():
''' example function'''
print("in example")

print(example.__doc__)
print(example.__name__)
'''
返回值:
wapper function
wapper
函数的属性经过装饰器后属性被修改
'''


# ----------------------
# 简单修改
# ----------------------
#coding:utf8
def w(func):
def wapper(*args, **kwargs):
''' wapper function '''
print('In wapper')
func(*args, **kwargs)
# 保留原来函数的属性
wapper.__name__ = func.__name__
return wapper

@w
def example():
''' example function'''
print("in example")

print(example.__doc__)
print(example.__name__)
'''
返回值:
wapper function
example
已经修改, 此方法过于繁杂
'''

# ----------------------
# 使用functools
# ----------------------
# update_wrapper
#coding:utf8
from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES
'''
其中wraps是调用update_wrapper

WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES 分别对应的是update_wrapper中的第三个参数和第四个参数
'''


def w(func):
def wapper(*args, **kwargs):
''' wapper function '''
print('In wapper')
func(*args, **kwargs)
# 保留原来函数的属性
# update_wrapper(wapper, func, ('__name__', '__doc__'), ('__dict__',))
update_wrapper(wapper, func)
'''
第一个参数是包裹函数 wapper
第二个参数为原函数 example(既是func)
第三个参数为元组 使用原函数的属性替换包裹函数的属性
第四个参数为元组 用于合并(合并原函数和包裹函数的属性而不是替换)
'''


return wapper

@w
def example():
''' example function'''
print("in example")

print(example.__doc__)
print(example.__name__)

print WRAPPER_ASSIGNMENTS # 返回 ('__module__', '__name__', '__doc__') 从此返回值中 第三个参数可以不填写使用默认
print WRAPPER_UPDATES # 返回 ('__dict__',) 从此返回值中 第四个参数可以不填写使用默认
''' '''
'''
返回值:
wapper function
example
已经修改, 此方法过于繁杂
'''


# ----------------------
# 使用functools
# ----------------------
# wraps
#coding:utf8
from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES
'''
其中wraps是调用update_wrapper

WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES 分别对应的是update_wrapper中的第三个参数和第四个参数
'''


def w(func):

'''
1、传入被装饰的函数(必须给定)
2、第二个参数为元组 WRAPPER_ASSIGNMENTS 不传入则使用默认('__module__', '__name__', '__doc__')
3、第三个为参数为元组 WRAPPER_UPDATES 不传入则使用默认('__dict__',)
'''

@wraps(func)
def wapper(*args, **kwargs):
''' wapper function '''
print('In wapper')
func(*args, **kwargs)
# 保留原来函数的属性
# update_wrapper(wapper, func, ('__name__', '__doc__'), ('__dict__',))
# update_wrapper(wapper, func)
'''
第一个参数是包裹函数 wapper
第二个参数为原函数 example(既是func)
第三个参数为元组 使用原函数的属性替换包裹函数的属性
第四个参数为元组 用于合并(合并原函数和包裹函数的属性而不是替换)
'''


return wapper

@w
def example():
''' example function'''
print("in example")

print(example.__doc__)
print(example.__name__)

print WRAPPER_ASSIGNMENTS # 返回 ('__module__', '__name__', '__doc__') 从此返回值中 第三个参数可以不填写使用默认
print WRAPPER_UPDATES # 返回 ('__dict__',) 从此返回值中 第四个参数可以不填写使用默认
''' '''
'''
返回值:
wapper function
example
已经修改, 此方法过于繁杂
'''

带参数的装饰器

# ----------------------
# signature模块
# ----------------------
#coding:utf8
# 检查函数参数的类型

from inspect import signature
# 3python 以后才有此模块

def typeassert(*ty_args, **ty_kwargs):
def decorator(func):
# func --》 a.b 获取函数参数类型映射关系
# d = {'a': int , 'b': str ...}
def wapper(*args, **kwargs):
# 迭代 args中的参数 判断其是否在字典中
# 如果在d字典中则对其值类型进行匹配
# arg in d, isinstance(arg, d[args])
return func(*args, **kwargs)
return wapper
return decorator


def f(a, b, c): pass
sig = signature(f) # 获取f的签名
print(sig.parameters)
'''
返回参数的字典
OrderedDict([('a', <Parameter "a">), ('b', <Parameter "b">), ('c', <Parameter "c">)])
'''

a = sig.parameters['a']
print(a.name) #参数名
print(a.kind) # 参数类型 POSITIONAL_OR_KEYWORD
print(a.default) # <class 'inspect._empty'> 参数a的默认值

print(sig.bind) # 可以绑定属性类型
''' <bound method Signature.bind of <Signature (a, b, c)>> '''
# 绑定属性
bargs = sig.bind(str, int, int)
print(bargs)
print(bargs.arguments)
'''
<BoundArguments (a=<class 'str'>, b=<class 'int'>, c=<class 'int'>)>
OrderedDict([('a', <class 'str'>), ('b', <class 'int'>), ('c', <class 'int'>)])
'''

print(bargs.arguments['a']) # <class 'str'>
print(bargs.arguments['b']) # <class 'int'>
print(bargs.arguments['c']) # <class 'int'>
bargs.bind_partial() # 某些参数不做类型检查不会报错




# coding:utf8
# 检查函数参数的类型

from inspect import signature


# 3python 以后才有此模块

def typeassert(*ty_args, **ty_kwargs):
def decorator(func):
# func --》 a.b 获取函数参数类型映射关系
# d = {'a': int , 'b': str ...}
sig = signature(func)
btypes = sig.bind_partial(*ty_args, **ty_kwargs).arguments
'''绑定的类型 某些参数不做类型检查不会报错 '''

def wapper(*args, **kwargs):
# 迭代 args中的参数 判断其是否在字典中
# 如果在d字典中则对其值类型进行匹配
# arg in d, isinstance(arg, d[args])
for name, obj in sig.bind(*args, **kwargs).arguments.items():
'''
获得到绑定的参数 类型对其进行迭代
'''

if name in btypes:
if not isinstance(obj, btypes[name]):
raise TypeError("{} must be {}".format(name, btypes[name]))
return func(*args, **kwargs)
return wapper
return decorator


@typeassert(int, str, list)
def f(a, b, c):
print(a, b, c)
f(1, '2', []) # 1 2 []
f(1,2,3)
'''
raise TypeError("{} must be {}".format(name, btypes[name]))
TypeError: b must be <class 'str'>
'''

属性可修改的函数装饰器

# coding:utf8
#
from functools import wraps
import time
import logging
from random import randint

# 统计函数的运行时间 运行时间超时则记录日志
def warm(timeout):
def decorator(func):
def wapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
''' 记录返回值 '''
used = time.time() - start
if used > timeout:
msg = "{}:{} > {}".format(func.__name__, used, timeout) # 哪个函数运行了多长时间 当前timeout
logging.warning(msg)
return res
return wapper
return decorator

@warm(1.5)
def test():
print('In test')
while randint(0,1):
# 百分之50的几率记录睡眠
time.sleep(0.5)
for _ in range(30):
''' 日志中是否有超过1.5秒的函数 '''
test()
'''
In test
WARNING:root:test:1.5000858306884766 > 1.5
In test
'''




# ------------------
# 动态修改tiemout
# -----------------
# coding:utf8
#
import time
import logging
from random import randint

# 统计函数的运行时间 运行时间超时则记录日志
def warm(timeout):
def decorator(func):
def wapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
''' 记录返回值 '''
used = time.time() - start
if used > timeout:
msg = "{}:{} > {}".format(func.__name__, used, timeout) # 哪个函数运行了多长时间 当前timeout
logging.warning(msg)
return res
def setTimeout(k):
nonlocal timeout
timeout = k
wapper.setTimeout = setTimeout # 给函数设置一个属性设置超时的时间
return wapper
return decorator

@warm(1.5)
def test():
print('In test')
while randint(0,1):
# 百分之50的几率记录睡眠
time.sleep(0.5)
for _ in range(5):
''' 日志中是否有超过1.5秒的函数 '''
test()
print("$"*20)
test.setTimeout(1)
for _ in range(5):
test()

'''
In test
In test
In test
In test
In test
WARNING:root:test:2.0001144409179688 > 1.5
$$$$$$$$$$$$$$$$$$$$
In test
In test
In test
WARNING:root:test:1.0000574588775635 > 1
In test
In test
'''


################
# python2 中实现
################
# coding:utf8
#
import time
import logging
from random import randint

# 统计函数的运行时间 运行时间超时则记录日志
def warm(timeout):
timeout = [timeout]
def decorator(func):
def wapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
''' 记录返回值 '''
used = time.time() - start
if used > timeout[0]:
msg = "{}:{} > {}".format(func.__name__, used, timeout[0]) # 哪个函数运行了多长时间 当前timeout
logging.warning(msg)
return res
def setTimeout(k):
# nonlocal timeout
timeout[0] = k
wapper.setTimeout = setTimeout # 给函数设置一个属性设置超时的时间
return wapper
return decorator

@warm(1.5)
def test():
print('In test')
while randint(0,1):
# 百分之50的几率记录睡眠
time.sleep(0.5)
for _ in range(5):
''' 日志中是否有超过1.5秒的函数 '''
test()
print("$"*20)
test.setTimeout(1)
for _ in range(5):
test()

'''
In test
In test
In test
In test
In test
WARNING:root:test:2.0001144409179688 > 1.5
$$$$$$$$$$$$$$$$$$$$
In test
In test
In test
WARNING:root:test:1.0000574588775635 > 1
In test
In test
'''