Python培训
400-996-5531
写代码要遵循开发封闭原则,虽然这个原则是用于面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
封闭:已实现的功能代码块,已经写好的函数不要更改
开放:对扩展开放,
而这正好可以用装饰器来实现。
Python 装饰器用于修改函数。
装饰器本质上是一个函数,它将被装饰的函数作为参数,然后用其返回的函数来替换那个被装饰的函数。
1,最基本的装饰器
>>> def outer(func):
def inner():
print("change~"+func())
ret = func() # 1
return ret +"~1"
return inner
>>> def foo():
return "foo"
>>> foo = outer(foo) #2
>>> foo()
change~foo
'foo~1'
# 下面语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约#翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种#语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加#程序的可读性,从而减少程序代码出错的机会。
#只有CPU的微代码不是语法糖,其余代码包括机器语言都是语法糖
>>> @outer
def foo():
return "foo"
>>> foo()
change~foo
'foo~1'
请仔细看这个装饰器示例。首先,定义了一个带单个参数 func 的名为 outer 的函数。然后在 outer 内部定义了一个内嵌函数 inner。inner 函数将打印一行字符 串 ,用来直观的告诉读者这里对要修改的函数进行了修改(change~foo)。并 在 #1 处获取其返回值。在每次 outer 被调用时,func 的值可能都会不同,但不论 func 是什么函数,都将调用它。最后,inner 返回 func() 的返回值加"~ 1"。在 #2 处可以看到,当调用赋值给 foo 的返回函数时,得到的是一行文本输出和返回值 'foo~1',而非期望的调用foo 的返回值 "foo"。
我们可以说等号左边的foo是原foo的装饰版 ,outer将函数foo装修一新了。
2,注册装饰器
_functions= {}
def register(f):
global _functions
_functions[f.__name__] = f
return f
@register
def foo():
return "bar"
在这个例子中,函数被注册并存储在一个字典里,以便后续可以根据函数名字提取函数。
3,被装饰函数带一个固定参数的装饰器
import time
def decorator(fun): def wrapper(name): start = time.time() fun(name) runtime = time.time()-start
print (runtime)
return wrapper
@decorator
def do_something(name):
for i in range(1000000):
pass print("play game "+ name)
do_something("san guo sha")
结果如下:
play game san guo sha
0.109375
实现很简单, 就是给wrapper函数加入相同的参数
4,被装饰函数带二个固定参数的装饰器
import time
def decorator(fun):
def wrapper(name1,name2):
start = time.time()
fun(name1,name2)
runtime = time.time()-start
print (runtime)
return wrapper
@decorator
def do_something(name1,name2):
for i in range(1000000):
pass
print ("play game "+name1+" & "+name2)
do_something("san guo sha","game2")
结果如下:
play game san guo sha & game2
0.109375
import time
def decorator(fun):
def wrapper(*args, **kwargs):
start = time.time()
fun(*args, **kwargs)
runtime = time.time()-start
print (runtime)
return wrapper
@decorator
def do_something(name):
for i inrange(1000000):
pass
print ("play game " + name)
@decorator
def do_something2(user, name):
for i inrange(1000000):
pass
print (user+" play game " + name)
do_something("san guo sha")
do_something2("wang xiao er","san guo sha")
结果如下:
play game san guo sha
0.109375
wang xiao er play game san guo sha
0.125
import time
defdecorator(max):
def_decorator(fun):
defwrapper(*args, **kwargs):
start = time.time()
for i inrange(max):
fun(*args, **kwargs)
runtime = time.time()-start
print (runtime)
return wrapper
return _decorator
@decorator(2)
def do_something(name):
for i inrange(1000000):
pass
print ("play game " + name)
do_something("san guo sha")
运行结果如下:
play game san guo sha
play game san guo sha
0.25
等同于下面
import time
defdecorator(max):
def_decorator(fun):
defwrapper(*args, **kwargs):
start = time.time()
for i inrange(max):
fun(*args, **kwargs)
runtime = time.time()-start
print (runtime)
return wrapper
return _decorator
def do_something(name):
for i inrange(1000000):
pass
print ("play game " + name)
#@decorator(2)
do_something= decorator(2)(do_something)
do_something("san guo sha")
play game san guo sha
play game san guo sha
0.265625
7. 一个函数可以被多个装饰器装饰
def d1(func):
def inner(*args,**kwargs):
# 验证1
return func(*args,**kwargs)
return inner
def (func):
def inner(*args,**kwargs):
# 验证1
return func(*args,**kwargs)
return inner
@d1
@d2
def f(arg1,arg2,arg3):
print ('f')
f(1,2,3)
运行结果如下:
f
相当于:
def d1(func):
def inner(*args,**kwargs):
# 验证1
return func(*args,**kwargs)
return inner
def (func):
def inner(*args,**kwargs):
# 验证1
return func(*args,**kwargs)
return inner
def f(arg1,arg2,arg3):
print ('f')
f = d1(d2(f))
f(1,2,3)
运行结果如下:
f
另外形式:
@f1(arg)
@f2 def func(): pass
相当于
def func(): pass func = f1(arg)(f2(func))
8. 类也可以装饰:就像装饰函数一样
@f1(arg)
@f2 class Foo: pass
大致相当于
class Foo: pass Foo = f1(arg)(f2(Foo))
装饰器表达式的计算规则与函数装饰器的计算规则相同。然后将结果绑定到类名。
填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!
Copyright © 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有
Tedu.cn All Rights Reserved