装饰器的作用——
在不改变函数原代码、调用方式的条件下,对函数增添额外的功能。
装饰器的组成:
高阶函数
函数嵌套
高阶函数:
什么是函数?
函数是对代码段的封装,函数是可执行的,执行函数就是
运行函数中封装的代码段。
通过内置方法,可以看到函数是可调用的!
>>> def foo():
... print('hello,world')
...
>>> callable(foo)
True
函数到底是什么?
‘function’???
>>> print(foo)
<function foo at 0x0051C660>
很明确,其实函数就是一个内存地址,函数名就是类似于内存地址的指针,对调用函数就是运行对应的内存地址!
什么是变量:
>>> name = 'alben'
>>> mingzi = 'alben
如图所示,变量命名就是把一个内存地址赋值到变量名(内存调用)
Python的内存回收:
当一个内存地址的所有调用都被del的时候,该内存被释放,否则将随着程序的运行永远占用。
那么变量与内存有没有区别呢?
答案是没有——
>>> def foo():
... print('Hello,World')
...
>>> abc = foo
>>> print(abc)
<function foo at 0x0047C660>
>>> print(foo)
<function foo at 0x0047C660>
>>>
高阶函数:
把一个A函数的函数名作为实参传递给B函数,B函数就是高阶函数
举例:
import time
def foo():
time.sleep(3)
l1 = [i * 2 for i in range(1000)]
print(len(l1))
def calc_time(func):
start_time = time.time()
func()
end_time = time.time()
print('The Func %s run time is %d' %(func,(end_time-start_time)))
calc_time(foo)
通过calc_time函数,可以计算函数foo的运行耗时。
but:
虽然函数我们实现了不改变函数foo的原代码情况下,增加了一个计算运行时间的功能,这是不可取的!
函数嵌套:
在一个函数的内部定义另一个函数,这个行为就是函数嵌套
def foo():
def inner():
print("This is inner func")
这个就是函数嵌套!
通过函数嵌套+高阶函数实现对现有函数功能的增加!
伪代码:
import time
def foo():
time.sleep(3)
l1 = [i * 2 for i in range(1000)]
print(len(l1))
def calc_time(func):
def inner():
start_time = time.time()
func()
end_time = time.time()
print('the Func %s run time is %d ' %(func,(end_time-start_time)))
return inner
1、定义了一个函数calc_time,该函数是高阶函数,要求传入另一个函数的函数名
2、函数calc_time内进行了函数套嵌,内嵌了另一个函数inner,
3、函数calc_time的return值就是内嵌函数inner
分析函数inner!
1、记录和执行时间(start_time)
2、执行了那个被当做实参传递进calc_time的函数
3、记录了执行完成时间(end_time)
4、计算了被传入函数的执行时间!
内嵌函数inner是不能直接在解释器中运行的!会出现如下报错!
Traceback (most recent call last):
File "D:/实现自动化运维/高阶函数.py", line 21, in <module>
inner()
NameError: name 'inner' is not defined
但是,函数calc_time的return就是内嵌函数的函数名!,所以我们只需要把calc_time的返回值赋值到一个变量,对这个变量执行以下就是执行内嵌函数inner了。
def foo():
time.sleep(3)
l1 = [i * 2 for i in range(1000)]
print(len(l1))
def calc_time(func):
def inner():
start_time = time.time()
func()
end_time = time.time()
print('the Func %s run time is %d ' %(func,(end_time-start_time)))
return inner
abc = calc_time(foo)
abc()
结果:
1000
the Func <function foo at 0x0049B660> run time is 3
我们已经实现了不改变函数foo源代码的条件下增加了新的功能(计算时间),
but!调用方式改变了!!
有一个折中的方案:
foo = calc_time(foo)
foo()
这样!简直prefect!
装饰器的雏形就出来了,python解释器给我们提供了一个语法糖!“@”来实现这个功能!
代码:
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
- import time
- def calc_time(func):
- def inner():
- start_time = time.time()
- func()
- end_time = time.time()
- print('the Func %s run time is %d ' %(func,(end_time-start_time)))
- return inner
- @calc_time
- def foo():
- time.sleep(3)
- l1 = [i * 2 for i in range(1000)]
- print(len(l1))
- foo()
在pycharm的Debug中,可以清晰的看到代码的执行顺序如下:
2-9-3-8-14-4-5-11-12-13-6-7
这就是最简单的装饰器!
下面,思考一个问题!就是如果被装饰的函数带有参数,那怎么办!
有一个推算斐波那契数列的函数:
def foo(a,b,x):
if type(a) and type(b) == int:
l1 = [a,b]
while True:
c = l1[-1] + l1[-2]
l1.append(c)
if c >x :break
else:
print("please give two int")
print (l1)
现在想要通过上面的装饰器calc_time来对这个函数进行装饰,试一下:
@calc_time
def foo(a,b,x):
if type(a) and type(b) == int:
l1 = [a,b]
time.sleep(1)
while True:
c = l1[-1] + l1[-2]
l1.append(c)
if c > x : break
else:
print("please give two int")
print(l1)
foo(1,2,1000)
运行结果:
"C:UsersIE-LAB DadeAppDataLocalProgramsPythonPython36-32python.exe" D:/实现自动化运维/高阶函数.py
Traceback (most recent call last):
File "D:/实现自动化运维/高阶函数.py", line 26, in <module>
foo(1,2,1000)
TypeError: inner() takes 0 positional arguments but 3 were given
Process finished with exit code 1
不用我提示了把,只需要把装饰器内部套嵌的函数加上可变参数就可以了!
def calc_time(func):
def inner(*args,**kwargs):
start_time = time.time()
func(*args,**kwargs)
end_time = time.time()
print('the Func %s run time is %d ' % (func, (end_time - start_time)))
return inner
好了,我相信白痴看了这个都能理解装饰器了吧!