python高级语法之闭包和装饰器详解
作者:随着风儿去流浪 发布时间:2021-09-19 18:28:55
一、闭包
闭包的形成条件:
1.函数嵌套。
2.内部函数使用了外部函数的变量或者参数。
3.外部函数返回了使用外 部变量的内部函数。
二、一个简单的例子
def func_out(num1):
def inner(num2):
res = num1 + num2
print(res)
return inner
# a = func_out(10)(10)
a = func_out(10)
a(10)
闭包修改外部函数的变量:
在闭包内修改外部函数的变量需要使用nonlocal关键字
def func_out():
# 外部函数的变量
num1 = 10
def func_inner():
# 在闭包内修改外部函数的变量
nonlocal num1
num1 = 20
res = num1 +20
print(res)
print("修改前的变量", num1)
func_inner()
print("修改后的变量", num1)
return func_inner
new_func = func_out()
new_func()
三、装饰器
3.1 简单装饰器
装饰器就是给已有函数增加额外功能的函数,它本质上就是一个闭包函数,也就是说也是一个函数嵌套。装饰器的功能特点:
1.不修改已有函数的源代码
2.不修改已有函数的调用方式
3.给已有函数增加额外的功能
用户在发表评论的时候需要验证用户是否登录,我们首先会想到去修改原来的函数,在函数里面添加一些功能,但是在现在这分工合作的时代,这样的修改很容易出现修改了祖传的代码后,函数出现问题,也影响代码的高效复用。为了能够不重新修改原来的评论的代码,实现高水平的代码复用。
原本的函数及其调用:
def comment():
print("执行祖传代码.....")
print("发表评论")
# 调用评论功能
comment()
自己手写一个实现装饰器功能的函数实现登录验证:
def decorator(func):
def inner():
print('正在验证登录者身份...\n验证成功')
func()
return inner
def comment():
print("执行祖传代码.....")
print("发表评论")
# 调用评论功能
comment = decorator(comment)
comment()
输入结果:
正在验证登录者身份…
验证成功
执行祖传代码…
发表评论
3.1.1 使用装饰器的语法糖
装饰器的语法糖写法:@装饰器名称
如例子可以改写为:
def decorator(func):
def inner():
print('正在验证登录者身份...\n验证成功')
func()
return inner
@decorator
def comment():
print("执行祖传代码.....")
print("发表评论")
# 调用函数
comment()
运行结果:
正在验证登录者身份…
验证成功
执行祖传代码…
发表评论
3.1.2 装饰器的执行时机
先说结论:在使用装饰器语法糖时,会先将该装饰器函数执行一遍。
def decorator(func):
# 测试装饰器的执行时机
print('--remark1----')
def inner():
print('正在验证登录者身份...\n验证成功')
func()
print('----remark2---')
return inner
@decorator
def comment():
print("执行祖传代码.....")
print("发表评论")
输出结果:
–remark1----
----remark2—
3.2 通用装饰器
装饰的函数可能有参数传递,或者有返回值,上面写的例子中,如果依然用上面的方法及逆行装饰器的装饰将会出现问题,那是否有一个通用的装饰器能够装饰任意函数呢?
3.2.1 装饰带有参数的函数
def logging(fn):
def inner(num1,num2):
print('执行了一次计算')
fn(num1,num2)
return inner
# 使用装饰器装饰函数
@logging
def sum_num(a,b):
result = a + b
print(result)
sum_num(1,2)
3.2.2. 装饰带有返回值的函数:
def logging(fn):
def inner(num1,num2):
print('执行了一次计算')
result = fn(num1,num2)
return result
return inner
# 使用装饰器装饰函数
@logging
def sum_num(a,b):
result = a + b
return result
print(sum_num(1,2))
3.2.3 实现通用装饰器
*args
: 用于接收元组参数,可传可不传
**kwargs
: 用于接收字典类型参数,可传可不传
def logging(fn):
def inner(*args, **kwargs):
result = fn(*args, **kwargs)
return result
return inner
@logging
def sum_num(a,b):
result = a + b
return result
3.3 多个装饰器的使用
多个装饰器的过程:由内到外的装饰过程,先执行内部装饰器,再执行外部装饰器。
原理剖析:content = make_div(make_p(content))
分步拆解:content = make_p(content), 内部装饰器完成content=make_p.inner, content = make_div(make_p.inner)
def make_div(func):
print("make_div装饰器执行了")
def inner():
# 在内部函数对已有函数进行装饰
result = "<div>" + func() +"</div>"
return result
return inner
def make_p(func):
print("make_p装饰器执行了")
def inner():
# 在内部函数对已有函数进行装饰
result = "<p>" + func() +"</p>"
return result
return inner
@make_div
@make_p
def content():
return "人生苦短,我用Python"
输出:
make_p装饰器执行了
make_div装饰器执行了<div><p>人生苦短,我用Python</p></div>
3.4 带有参数的装饰器
带有参数的装饰器时机上就是定义了一个函数,让函数接收参数,再函数内部返回该装饰器。
如定义一个能够判断加减的装饰器:
def return_decorator(flag):
def decorator(func):
def inner(a,b):
if flag == '+':
print("正在进行加法运算")
elif flag == '-':
print("正在进行减法运算")
func(a,b)
return inner
return decorator
@return_decorator('+')
def add_num(a,b):
print(a+b)
add_num(1,5)
3.5 类装饰器
使用类装饰已有函数。
class MyDecorator(object):
def __init__(self,func):
self.__func = func
# 实现__call__方法,让对象变成可调用的对象,
# 可调用的对象能够像函数一样被使用。
def __call__(self,*args,**kwargs):
# 对已有参数进行封装
print('--正在进行装饰-----')
self.__func()
@MyDecorator
def show():
print("hello")
# 指向MyDecorator类创建实例对象--> show()==> 对象()
show()
输出:
–正在进行装饰-----
hello
来源:https://blog.csdn.net/weixin_45915507/article/details/116355827


猜你喜欢
- 1、登录接口登录后返回对应token封装:import jsonimport requestsfrom util.operation_jso
- 示例如下:<script> //函数: 反复执行的代码块 //全局只有一个对
- 我们知道numpy.ndarray.reshape()是用来改变numpy数组的形状的,但是它的参数会有一些特殊的用法,这里我们进一步说明一
- 在MongoDB中的ObjectID,可以理解为是一个不会重复的ID,这里有个链接https://www.aspxhome.com/arti
- Pytorch数据类型与转换(torch.tensor,torch.FloatTensor)之前遇到转为tensor转化为浮点型的问题,今天
- mysql 8.0.25 解压版安装教程,供大家参考,具体内容如下1、下载(官方推荐的是下载安装版本,但是解压版更便捷),下载地址2、解压,
- 一、关于Python操作数据库的概述Python所有的数据库接口程序都在一定程度上遵守 Python DB-API 规范。DB-API定义了
- python中字典可以一键多值,也就是意味着一个键可以对应多个值。例:#encoding=utf-8print '中国'#字
- 在实际的工作和学习中,许多人的SQL Server 2005数据库日志文件可能会发生损坏,例如硬件故障、计算机非正常重启或关机等等。在SQL
- 1. 前言由于近期有任务需要,要写一个能够处理Excel的脚本,实现的功能是,在A表格上其中一列,对字符串进行分组和排序,然后根据排序好的A
- join toString该两种方法会将数组元素的类型转换为字符串var arr = [1, [2, [3, [4, 5]]], 6];co
- 下面两个函数的使用和FIND_IN_SET一样,使用时只需要把FIND_IN_SET换成FIND_PART_IN_SET或FIND_ALL_
- 1.匿名函数介绍匿名函数指一类无须定义标识符的函数或子程序。Python用lambda语法定义匿名函数,只需用表达式而无需申明。在pytho
- public static char doVerify(String id) { char pszSrc[]=id.toCharArray(
- 目录Memcache缓存第一步:安装Memcached第二步:启动Memcached第三步:pip安装python-memcached第四步
- Chrome的CSS支持程度 :Green / √ means current support.Orange / Δ means that
- 需求最近公司干活,收到一个需求,说是让手动将数据库查出来的信息复制粘贴到excel中,在用excel中写好的公式将指定的两列数据用updat
- 第一种 使用pygame模块 pygame.mixer.init() pygame.mixer.music.load
- 一、初始化CounterCounter支持3种形式的初始化,比如提供一个数组,一个字典,或单独键值对“=”式赋值。具体初始化的代码如下所示:
- 简单的小练习,实现将一个指定列表中的数值进行转化,对于其中的非负数不作处理,对于负数需要转化为制定的数值,很简单就不多说了,下面是具体的实现