博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python闭包与装饰器
阅读量:4315 次
发布时间:2019-06-06

本文共 2327 字,大约阅读时间需要 7 分钟。

https://www.cnblogs.com/evablogs/p/6697219.html

 

有关闭包和装饰器的知识点的理解着实花了我不少时间,整理笔记更是无从下手,但还是将从网上搜索学习的点滴记录下来以便后期的一个补充学习。

闭包(wrapper)

闭包通俗地解释就是通过调用了函数A,函数A返回了函数B,返回的函数B就是所谓的闭包,在调用函数A的时候传递的参数就是自由变量,该自由变量是被函数A引用的,在函数A的生命周期结束后仍然存在,这句话是至今能让我比较能理解的解释。

例如:

1
2
3
4
5
6
7
8
>>>
def 
func1(name):                             
#定义一个函数func1
           
def 
func2(age):                      
#函数func2()是在func1调用的时候产生的一个闭包,且引用了自由变量name
                 
print 
name,age
           
return 
func2                         
#函数调用完毕返回函数func2
 
>>> a
=
func1(
'Lily'
)                             
#调用函数func1,且传递参数‘Lily’,将结果赋给a
>>> a(
24
)                                       
#上一步的结果是返回函数func2,这时再将参数24赋给函数func1,调用函数func2
Lily 
24

闭包不能修改外部作用域的局部变量:

1
2
3
4
5
6
7
8
>>> 
def 
a():
    
x
=
1                                 
#局部变量x的值为1
    
def 
b():
        
x
=
0                         
#在闭包内对x的值进行重新赋值
    
return 
x
 
>>> a()
1                                           
#结果是x的值没有改变

使用闭包的好处呢一个就是在闭包运行之后,保存当前的运行环境,另一个是通过外部作用域的变量可以返回不同的值。

装饰器

装饰器是闭包的使用场景之一,装饰器其实也就是闭包的应用,只是区别的是装饰器传递的参数是函数。装饰器是将函数作为参数传递给一个函数,并对其进行加工处理即装饰返回一个新的函数,装饰器能保证在不改变已有的函数的结构,调用该函数返回一个新的函数,极大地提高了效率。

使用标识符@将装饰器应用在函数上,只需要在函数的定义前加上@和装饰器的名称,即@decorator

1
2
3
@decorator                                  
#解释器将会解释成:func=decorator(func),即将函数func作为参数传递给函数decorator,然后再返回新的函数赋值给func
def 
func():
      
pass

 多个decorator使用:

1
2
3
4
@decorator1                                 
#func=decorator2(decorator1(func))
@decorator2                                 
#func=decorator1(func)
def 
func():
     
pass

 再来一个打印调用函数前log日志的无参数的装饰器例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> 
def 
log(f):
     
def 
wrapper(
*
args):
           
print 
'call %s()' 
%
(f.__name__)
           
return 
f(
*
args)
     
return 
wrapper
 
>>> @log
def 
func():
     
print 
'hello,world'
 
      
>>> func()
call func()
hello,world

 带参数的装饰器:

带参数的装饰器比不带参数的装饰器还要复杂一点,需要编写一个返回decorator的高阶函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> 
def 
log(text):                                                   
#3层嵌套的函数
    
def 
decorator(f):                                            
#返回decorator函数
        
def 
wrapper(
*
args):
            
print 
'%s %s()' 
%
(text,f.__name__)           
#将log的参数excute传递过来赋给text
            
return 
f(
*
args)
        
return 
wrapper
    
return 
decorator                                            
#先执行log('excute')函数,返回decorator函数,再调用返回wrapper函数,最后返回一个新的func函数
>>> @log(
'excute'
)
def 
func():
     
print 
'hello,world'
 
      
>>> func()
excute func()
hello,world
>>>
1
2
>>> now.__name__                           
#函数的name属性,通过decorator装饰器调用执行之后返回wrapper函数,所以函数名由func变成了wrapper
'wrapper'

所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

不需要编写wrapper.__name__ = f.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

1
2
3
4
5
6
7
8
9
10
import 
functools
 
def 
log(text):
    
def 
decorator(f):
        
@functools
.wraps(f)
        
def 
wrapper(
*
args, 
*
*
kw):
            
print
(
'%s %s():' 
% 
(text, f.__name__))
            
return 
f(
*
args, 
*
*
kw)
        
return 
wrapper
    
return 
decorator

转载于:https://www.cnblogs.com/yuer20180726/p/10790358.html

你可能感兴趣的文章
sk_buff Structure
查看>>
oracle的级联更新、删除
查看>>
多浏览器开发需要注意的问题之一
查看>>
Maven配置
查看>>
HttpServletRequest /HttpServletResponse
查看>>
SAM4E单片机之旅——24、使用DSP库求向量数量积
查看>>
从远程库克隆库
查看>>
codeforces Unusual Product
查看>>
hdu4348 - To the moon 可持久化线段树 区间修改 离线处理
查看>>
springMVC中一个class中的多个方法
查看>>
Linux系统安装出错后出现grub rescue的修复方法
查看>>
线段树模板整理
查看>>
[教程][6月4日更新]VMware 8.02虚拟机安装MAC lion 10.7.3教程 附送原版提取镜像InstallESD.iso!...
查看>>
[iOS问题归总]iPhone上传项目遇到的问题
查看>>
Python天天美味(总) --转
查看>>
Spring Framework tutorial
查看>>
【VS开发】win7下让程序默认以管理员身份运行
查看>>
【机器学习】Learning to Rank 简介
查看>>
Unity 使用实体类
查看>>
【转】通过文件锁实现,程序开始运行时,先判断文件是否存在,若存在则表明该程序已经在运行了,如果不存在就用open函数创建该文件,程序退出时关闭文件并删除文件...
查看>>