Python学习笔记--装饰器

Python学习笔记--装饰器

当你要提升自己颜值的时候该如何做? 可以整容,但是能不能在不修改本身器官下来提升颜值?
答案就是装饰器

def add(x,y):
print("I am working now")
return x+y

  • 你编写了一段程序,但是你觉得功能不够,例如你希望在运行add的时候,增加一段解释性的输出.就可以这样子.

    def deco(func):
    print("The value is ")
    return func
    print(deco(add(3,9)))

  • 输出是
    I am working now
    The value is
    12

  • 这样就做到了在没有改写代码的情况下增加了功能.可能你觉得这个例子有点简单,我们在看一个复杂点的.


  • 需求1:在执行add()方法的时候增加类型检查.

    def requires_int(decorated):
    def inner(args, **kwargs):
    kwargs_value=[i for i in kwargs.values()]
    for arg in list(args)+kwargs_value:
    print(arg)
    if not isinstance(arg,int):
    raise TypeError('%s only accepts integers as arguments'%decorated.name)
    return decorated(
    args,**kwargs)
    return inner

    def add(x,y):
    """ Return the sum of x and y"""
    return x+y

    add=requires_int(add)
    add('3',5)

    TypeError: add only accepts integers as arguments

  • 但是有人疑问,写的太麻烦了,不如直接在代码上加一个类型检查. 但是如果再增加一个需求呢?


需求二:计算程序运行事件.

def addTime(decorated):
def inner(x,y):
start=time.clock()
decorated(x,y)
end=time.clock()
addTime=(end-start)*1000
print("Time used",addTime)
return decorated(x,y)
return inner
add=addTime(add)
Time used 0.03699999999999884

  • 如果再有新需求,再写一个装饰器就可以了.是不是很方便?

并且,两个装饰器还可以一起用.像这样

add=addTime(add)
add=requires_int(add)
add(4,8)

但是这样写感觉好麻烦,每次都要赋值一次,没关系,python为你专门准备了语法糖.其实可以这样写

@addTime
@requires_int
def add(x,y):
""" Return the sum of x and y"""
time.sleep(0.7)
return x+y

感觉有点眼熟,Django的login_required()不就是这样写的吗.不仅是这样,Flask的路由也是装饰器写的@route.

需要注意的是,如果多个装饰器,运行顺序是从下到上.

瞬间觉得装饰器好有用,不好好学习不行了.


让我们再来学习一个实例. 需求3如果我们要写一个注册表装饰器.#每次运行一个函数,都会有记录这个函数#.

registers=[]
def register(decorated):
registers.append(decorated)
return decorated

@register
def foo():
return 3

@register
def bar():
return 5

for i in registers:
print(i())

最后输出3,5. 但是有点问题是,我觉得应该不同的函数的register应该分开.这应该怎么办呢

答案是写一个装饰器类

class Register(object):
def init(self):
self._functions=[]#定义一个列表来装被装饰的函数

def register(self,decorated):#装饰函数
self._functions.append(decorated)
return decorated

def run_all_function(self, args, **kwargs):
return_values=[]
for func in self._functions:
return_values.append(func(
args, **kwargs))
return return_values

a=Register()
b=Register()

@a.register
def foo(x=5):
return x

@b.register
def bar(x=4):
return x

@a.register
@b.register
def baz(x=7):
return x

print(a.run_all_function())
print(b.run_all_function())

[5, 7]
[4, 7]

这样就可以做到互相不影响,每一个register都是不同实例,数值不会混乱,是不是特别方便?

让我们总结一下今天的学习.

装饰器可以在不修改代码下增加功能
装饰器可以叠加
装饰器可以写成一个类

posted @ 2017-03-09 16:16  MaxProAim  阅读(215)  评论(0)    收藏  举报