1.装饰器
装饰器是一个函数,其主要用途是包装另一个函数或类。这种包装的首要目的是光明正大地修改或增强被包装对象的行为。其语法上使用特殊的符号 @ 表示装饰器。
这里摘录廖雪峰老师博客的部分内容!
函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数
def func():
print("hello world")
f = func
f() #咦!通过变量都可以调用函数啊
#函数对象有一个__name__属性,可以拿到函数的名字:
print(func.__name__)
现在,假设我们要增强函数func的功能,在函数调用前后自动打印日志,但又不希望修改func函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
本质上 装饰器 就是一个返回函数的高阶函数
#先来看如下代码
def trace(func):
def callf(*args, **kwargs):
print("Calling %s: %s, %s\n" %
(func.__name__, args, kwargs))
r = func(*args, **kwargs)
print("%s returned %s\n" % (func.__name__, r))
return r
return callf
@trace
def func2(x):
return x * x
print("the func2 value is %d", func2(3))
打印结果如下:
Calling func2: (3,), {}
func2 returned 9
the func2 value is %d 9
其实我的本意是要打印在调用func2函数前后的啊!为什么会打印在之前呢?
其原因是,我在print函数中调用了func2函数,大致意思如下:
调用 print( - - - - - - - - - - - - - ->)
- - - - - - - - - - - - - ||
- - - - - - - - - - -调用func2(3)
- - - - - - - - - - - - -||
但是由于我们编写的装饰器在func2函数前后都执行了打印
- - - - - - - - - - - - - ||
所以函数执行顺序为:
先打印前一句,调用func2函数执行,在打印后一句,然后函数的结果返回给print函数,由print函数打印出结果,所以就有了如上的顺序了。
把@trace放到func2()函数的定义处,相当于执行了语句: func2 = trace(func2 )
2.装饰器传参
如果装饰器本身需要传入参数,那就需要编写一个返回装饰器的更高阶的函数
如下编程:
def log(text):
def trace(func):
def callf(*args, **kwargs):
print("Calling %s %s: %s, %s" %
(text, func.__name__, args, kwargs))
return func(*args, **kwargs)
return callf
return trace
@log('haha')
def now():
print ('666')
now()
#其打印结果如下:
Calling haha now: (), {}
666
3.同时使用多个装饰器
在同时使用多个装饰器时,他们必须出现在函数或者类之前的单独行上。可以同时使用多个装饰器
@foo
@bar
@sqam
def gork():
pass
#在这个例子中,装饰器将按照他们出现的先后顺序应用,结果等同于;
def grok(x):
pass
grok = foo(bar(sqam(grok)))
总结
- 本节我们首先学习了装饰器的作用和目的(正大光明的修改或增强被包装的对象)
- 紧接着学习了如何自己编写一个装饰器,并在自己的代码前后加上打印
- 最后学习了如何使用装饰器传递参数和同时使用多个装饰器的基本方法