Python【第四课】 装饰器
本篇内容
-
什么是装饰器
-
装饰器需要遵循的原则
-
实现装饰器的知识储备
-
高阶函数
-
函数嵌套
-
闭包函数
-
无参函数
- 装饰器示例
1.什么是装饰器
器即函数
装饰即修饰,意指为其他函数添加新功能
装饰器定义:本质就是函数,功能是为其他函数添加新功能
2.装饰器需要遵循的原则
1.不修改被装饰函数的源代码(开放封闭原则)
2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式
3.实现装饰器的知识储备
装饰器=高阶函数+函数嵌套+闭包
4.高阶函数
高阶函数定义:
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
# 接收的参数是一个函数名
def count(func,num): num=func(num) print(num) count(abs,-10) # 输出 # 10
# 返回值是一个函数 def count(): print('输出数字的绝对值方法:') return abs put=count() print(put(-10)) # 输出 # 输出数字的绝对值方法: # 10
高阶函数总结
1.函数接收的参数是一个函数名
作用:在不修改函数源代码的前提下,为函数添加新功能,
不足:会改变函数的调用方式
2.函数的返回值是一个函数名
作用:不修改函数的调用方式
不足:不能添加新功能
5.函数嵌套
之前写过,去看看吧,我觉得写得还挺好的。
函数基础:
http://www.cnblogs.com/40kuai/articles/6374356.html
6.闭包函数
闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)(想想Erlang的外层函数传入一个参数a, 内层函数依旧传入一个参数b, 内层函数使用a和b, 最后返回内层函数
函数是什么
地球人都知道:函数只是一段可执行代码,编译后就“固化”了,每个函数在内存中只有一份实例,得到函数的入口点便可以执行函数了。在函数式编程语言中,函 数是一等公民(First class value:第一类对象,我们不需要像命令式语言中那样借助函数指针,委托操作函数),函数可以作为另一个函数的参数或返回值,可以赋给一个变量。函数可 以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题。如:
>>> def ExFunc(n): sum=n def InsFunc(): return sum+1 return InsFunc >>> myFunc=ExFunc(10) >>> myFunc() 11 >>> myAnotherFunc=ExFunc(20) >>> myAnotherFunc() 21 >>> myFunc() 11 >>> myAnotherFunc() 21 >>>
在这段程序中,函数InsFunc是函数ExFunc的内嵌函数,并且是ExFunc函数的返回值。我们注意到一个问题:内嵌函数InsFunc中 引用到外层函数中的局部变量sum,IronPython会这么处理这个问题呢?先让我们来看看这段代码的运行结果。当我们调用分别由不同的参数调用 ExFunc函数得到的函数时(myFunc(),myAnotherFunc()),得到的结果是隔离的,也就是说每次调用ExFunc函数后都将生成并保存一个新的局部变量sum。其实这里ExFunc函数返回的就是闭包。
引用环境
按照命令式语言的规则,ExFunc函数只是返回了内嵌函数InsFunc的地址,在执行InsFunc函数时将会由于在其作用域内找不到sum变量而出 错。而在函数式语言中,当内嵌函数体内引用到体外的变量时,将会把定义时涉及到的引用环境和函数体打包成一个整体(闭包)返回。现在给出引用环境的定义就 容易理解了:引用环境是指在程序执行中的某个点所有处于活跃状态的约束(一个变量的名字和其所代表的对象之间的联系)所组成的集合。闭包的使用和正常的函 数调用没有区别。
由于闭包把函数和运行时的引用环境打包成为一个新的整体,所以就解决了函数编程中的嵌套所引发的问题。如上述代码段中,当每次调用ExFunc函数 时都将返回一个新的闭包实例,这些实例之间是隔离的,分别包含调用时不同的引用环境现场。不同于函数,闭包在运行时可以有多个实例,不同的引用环境和相同 的函数组合可以产生不同的实例。
6.1 闭包函数定义
python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
>>>def addx(x): >>> def adder(y): return x + y >>> return adder >>> c = addx(8) >>> type(c) <type 'function'> >>> c.__name__ 'adder' >>> c(10) 18
结合这段简单的代码和定义来说明闭包:
如果在一个内部函数里:adder(y)就是这个内部函数,
对在外部作用域(但不是在全局作用域)的变量进行引用:x就是被引用的变量,x在外部作用域addx里面,但不在全局作用域里,
则这个内部函数adder就是一个闭包。
6.2 闭包函数的注意事项
1.闭包中是不能修改外部作用域的局部变量的
>>> def foo(): ... m = 0 ... def foo1(): ... m = 1 ... print m ... ... print m ... foo1() ... print m ... >>> foo() 0 1 0
# 从执行结果可以看出,虽然在闭包里面也定义了一个变量m,但是其不会改变外部函数中的局部变量m。
2.以下这段代码是在python中使用闭包时一段经典的错误代码
def foo(): a = 1 def bar(): a = a + 1 return a return bar
这段程序的本意是要通过在每次调用闭包函数时都对变量a进行递增的操作。但在实际使用时没有把参数传给闭包函数。
其他详细见:http://www.cnblogs.com/JohnABC/p/4076855.html
7.无参函数
无参装饰器=高级函数+函数嵌套
无参装饰器=高级函数+函数嵌套
基本框架
1 #这就是一个实现一个装饰器最基本的架子 2 def timer(func): 3 def wrapper(): 4 func() 5 return wrapper
加上参数
1 def timer(func): 2 def wrapper(*args,**kwargs): 3 func(*args,**kwargs) 4 return wrapper
加上功能
import time def timer(func): def wrapper(*args,**kwargs): start_time=time.time() func(*args,**kwargs) stop_time=time.time() print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time)) return wrapper
加上返回值
import time def timer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('函数[%s],运行时间是[%s]' %(func,stop_time-start_time)) return res return wrapper
使用装饰器
def cal(array): res=0 for i in array: res+=i return res cal=timer(cal) cal(range(10))
语法糖@
@timer #@timer就等同于cal=timer(cal) def cal(array): res=0 for i in array: res+=i return res cal(range(10))
小知识点:
# import functools # @functools.wraps(func) # 被装饰器调用过的函数帮助信息显示为装饰器的帮助信息 # 调入functools模块可以解决该问题
8.装饰器示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
抄袭地址:http://www.cnblogs.com/linhaifeng/articles/6140395.html