重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
内置语法糖 格式优美 逼格较高
成都创新互联公司坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站制作、成都网站建设、外贸营销网站建设、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的鹿寨网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
在代码中使用洽到好处的装饰器瞬间让代码优美很多
写起来也很简单 无参的装饰器参数是要装饰的函数 有参装饰器参数是需要的参数 最后返回的是内部函数!
装饰器是通过装饰器函数修改原函数的一些功能而不需要修改原函数,在很多场景可以用到它,比如① 执行某个测试用例之前,判断是否需要登录或者执行某些特定操作;② 统计某个函数的执行时间;③ 判断输入合法性等。合理使用装饰器可以极大地提高程序的可读性以及运行效率。本文将介绍Python装饰器的使用方法。
python装饰器可以定义如下:
输出:
python解释器将test_decorator函数作为参数传递给my_decorator函数,并指向了内部函数 wrapper(),内部函数 wrapper() 又会调用原函数 test_decorator(),所以decorator()的执行会先打印'this is wrapper',然后打印'hello world', test_decorator()执行完成后,打印 'bye' ,*args和**kwargs,表示接受任意数量和类型的参数。
装饰器 my_decorator() 把真正需要执行的函数 test_decorator() 包裹在其中,并且改变了它的行为,但是原函数 test_decorator() 不变。
一般使用如下形式使用装饰器:
@my_decorator就相当于 decorator = my_decorator(test_decorator) 语句。
内置装饰器@functools.wrap可用于保留原函数的元信息(将原函数的元信息,拷贝到对应的装饰器函数里)。先来看看没有使用functools的情况:
输出:
从上面的输出可以看出test_decorator() 函数被装饰以后元信息被wrapper() 函数取代了,可以使用@functools.wrap装饰器保留原函数的元信息:
输出:
装饰器可以接受自定义参数。比如定义一个参数来设置装饰器内部函数的执行次数:
输出:
Python 支持多个装饰器嵌套:
装饰的过程:
顺序从里到外:
test_decorator('hello world') 执行顺序和装饰的过程相反。
输出:
类也可以作为装饰器,类装饰器主要依赖__call__()方法,是python中所有能被调用的对象具有的内置方法(python魔术方法),每当调用一个类的实例时,__call__()就会被执行一次。
下面的类装饰器实现统计函数执行次数:
输出:
下面介绍两种装饰器使用场景
统计函数执行所花费的时间
输出:
在使用某些web服务时,需要先判断用户是否登录,如果没有登录就跳转到登录页面或者提示用户登录:
--THE END--
可以的,
装饰器分为可带参数和不可带参数的两种;但是如果带参数,则带参数装饰器的“参数”及“return”必须也是一个装饰器
具体可以参考一下下面的例子:
def deco1(func):
def w(x,*args,**kw):
print "this is deco1"
return x + " decorator"
return w
def deco2(deco):
print "this is deco2"
return deco
@deco2(deco1)
def func(x):
return x
print func("Hello")
装饰器(decorator)是Python中的高级语法。装饰的意思就是动态扩展被装饰对象的功能。装饰器可以用于装饰函数、方法和类。
一 嵌套函数
# 定义一个外层函数def foo(): # 定义了一个内部函数 def bar(): print("hello world")
函数bar是一个定义在foo函数内部的函数。
Python中的函数是支持嵌套的,也就是可以在一个函数内部再定义一个函数。
然后,我们还知道函数是可以当作变量的,于是我们就可以在foo函数中把定义的这个bar函数返回。就像下面这样:
# 定义一个外层函数def foo(): # 定义了一个内层函数 def bar(): print("hello world") return
barfunc = foo()func() # func -- bar,这里执行func其实就相当于执行了在foo函数内部定义的bar函数
二 闭包形态1
# 闭包形态1def foo(): name = "Andy" # 外部函数的局部变量 # 定义了一个内部函数 def bar():
print(name) # 虽然bar函数中没有定义name变量,但是它可以访问外部函数的局部变量name return barfunc =
foo()func() # func -- bar -- 除了是一个函数,还包含一个值(它外层函数的局部变量)的引用
三 闭包形态2
# 闭包形态2def foo(name): # 给一个函数传参也相当于给函数定义了一个局部变量 # 定义了一个内部函数 def bar():
print(name) # 内部函数同样可以获取到传到外部函数的变量(参数) return barfunc = foo("Andy") #
把“Andy”当成参数传入foo函数 -- 其内部定义的bar函数也能拿到这个“Andy”func() # func -- bar --
除了是一个函数,还包含一个值(它外层函数的参数)的引用
四 装饰器形态1
# 还是定义一个外层函数def foo(name): # 我接收的参数是一个函数名 # 定义了一个内部函数 def bar():
print("这是新功能。。。") # 新功能 name() # 函数名加()就相当于执行-- 我传进来原函数的函数名,这里就相当于执行了原函数
return bar# 定义一个被装饰的函数def f1(): print("hello world.") # 用foo函数装饰f1函数f1 =
foo(f1)# 不改变f1的调用方式f1() # -- 此时函数已经扩展了新功能
五 装饰器形态2
# 还是定义一个外层函数def foo(name): # 接收的参数是一个函数名 # 定义了一个内部函数 def bar():
print("这是新功能。。。") # 新功能 name() # 函数名加()就相当于执行-- 传进来原函数的函数名,这里就相当于执行了原函数
return bar# 定义一个被装饰的函数# 用foo函数装饰f1函数@foo # 使用f1 =
foo(f1)语法装饰的话稍显啰嗦,Python就提供了@语法,让装饰过程更简便def f1(): print("hello world.") #
不改变f1的调用方式f1() # -- 此时函数已经扩展了新功能。
首先十分不推荐这种做法, 会令程序难以维护.
其次, 多个装饰器是按照装饰器的顺序进行执行的.
如果你编写过装饰器, 你就应该知道, 其实装饰器就是把函数的名字传入进去, 在执行函数之前, 进行一些提前的处理.
例如下面这段代码, 自定义的装饰器
def add_schedid(handler_func):
"""
@handler_func: 请求处理函数
"""
@functools.wraps(handler_func)
def wrapper(self, *args, **kwargs):
"""
wrapper
"""
# handler_func就是所装饰的函数,可以在这里做一些真正函数执行前所需的处理,
handler_func(self, *args, **kwargs)
return wrapper
装饰器本身就是一个函数, 将所装饰的函数, 作为一个参数传进来, 然后在执行这个函数之前, 进行一个处理,这就是装饰器. 所以和正常函数执行顺序是一样的..
1. 函数带多个参数
# 普通的装饰器, 打印函数的运行时间
def decrator(func):
def wrap(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print('运行时间为', end_time-start_time)
return res
return wrap
2. 装饰器带有多个参数
当装饰器带有多个参数的时候, 装饰器函数就需要多加一层嵌套:
比如:
def decrator(*dargs, **dkargs):
def wrapper(func):
def _wrapper(*args, **kargs):
print ("装饰器参数:", dargs, dkargs)
print ("函数参数:", args, kargs)
return func(*args, **kargs)
return _wrapper
return wrapper
为什么被装饰函数体可以传入内层呢?
装饰器函数有多个参数, 需要以
@decrator(1, a=2)
的方式使用, 这时候decrator是已经执行的(因为加了括号), 可以粗略的理解为加载被装饰函数的上的是wrapper, 所以这和普通的装饰器并无差别.
又如flask源码中的:
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.
"""
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
flask的蓝图route源码中的装饰器, 最内层直接返回return f 并没有多加一层处理的函数, 在无需对被装饰函数进行过多处理的时候这是较为方便的做法. route源码中只是对装饰器参数进行了处理.