Python基础之函数:2、globlal与nonlocal和闭包函数、装饰器、语法糖
一、global与nonlocal
1、global
- 在py文件中,一般无法调用函数体内变量名,而global可使函数体代码内的变量名直接在函数体外部调用,条件是在需要调用的代码体中使用global 调用需要的变量名
未使用global情况:
# 在外部绑定一个变量名
name = 'kangkng'
# 定义一个函数体代码
def func():
# 函数体内部重新绑定一个变量名
name = 'zhangzhang'
# 调用函数func
func()
# 这时无法打印函数体内部的变量名
print(name)
------------------------------------------------------------------------ kangkang
使用global情况:
# 在函数体内部使用global时,可在外部直接调用函数内部变量名
name = 'kangkng'
# 定义一个函数体代码
def func():
# 使用global调用变量名
global name
# 函数体内部重新绑定一个变量名
name = 'zhangzhang'
# 调用函数func
func()
# 外py中打印name
print(name)
------------------------------------------------------------------------
zhangzhang
2、nonlocal
- 在函数嵌套使用时,通常在父代码体中无法调用子代码中变量名,
而nonlocal的作用是,可以在父代码中直接调用子代码中的变量名,条件是需要在子代码中使用nonlocal 调用需要的变量名
未使用nonlocal情况:
# 定义一个函数体代码
def outer():
# 绑定一个变量名
name = 'kangkang'
# 代码体内部再次定义一段函数体
def subcoat():
# 内层中绑定变量名
name = 'zhangzhang'
# 在函数外层打印变量名
print(name)
# 调用外层函数体代码
outer()
-----------------------------------------------------------------------
kangkang
使用nonlocal情况:
# 在函数体内部使用global时,可在外部直接调用函数内部变量名
def outer():
# 函数外层绑定一个变量名
name = 'kangkang'
# 代码体内部再次定义一段函数体
def subcoat():
# 在函数体内层使用nonlocal,调用变量名
nonlocal name
# 内层中绑定变量名
name = 'zhangzhang'
# 调用内层函数
subcoat()
# 在函数外层打印变量名
print(name)
# 调用外层函数体代码
outer()
----------------------------------------------------------------------
zhangzhang
二、函数名的多种用法
引言:
函数名就相当于变量名,只不过函数名绑定的是一段函数体代码,在我们使用这个函数名加括号时就可以调用这段代码体,具体由以下几种用法:
1、当做变量名赋值
def func():
print('我是func函数体代码')
res = func
print(res())
------------------------------------------------------------------------
我是func函数体代码
None
2、当作函数的参数
def func():
print('我是func函数体代码')
def func1(a):
print('我是func1函数体代码', a)
a()
func1(func)
------------------------------------------------------------------------
我是func1函数体代码 <function func at 0x000001D0C14D6310>
我是func函数体代码
3、当作函数的返回值
def func():
print('我是func函数体代码')
def func1():
print('我是func1函数体代码')
return func
res = func1()
print(res)
res()
------------------------------------------------------------------------
我是func1函数体代码
<function func at 0x00000218F95B6310>
我是func函数体代码
4、当作容器类型的数据
def spring():
print('我是春季,生机盎然')
def summer():
print('我是夏季,活力四射')
def autumn():
print('我是秋季,翩翩起舞')
def winter():
print('我是冬季,大雪纷飞')
while True:
season_dict = { '1': spring,
'2': summer,
'3': autumn,
'4': winter
}
season_select = input('根据编号,选择您喜欢的季节>>>:').strip()
if season_select in season_dict:
season_dict.get(season_select)()
else:
print('你选择的编号不存在')
------------------------------------------------------------------------
三、闭包函数
1、什么是闭包函数
一个函数的返回值是另外一个函数,返回的函数调用父函数内部的变量,如果返回的函数在外部被执行,就产生了闭包
2、闭包函数需满足的条件
满足以下两个条件的就是闭包函数:
条件一:定义在函数内部的函数
条件二:用到了外部函数空间名称中的名子
3、闭包函数的作用
作用:使函数外部能够调用函数内部放入属性和方法
缺点:闭包操作导致整个函数的内部环境被长久保存,占用大量内存
4、闭包函数的实际应用
1.函数内部变量名在外部被访问
def fun1():
name = 'python'
def inner():
print(name)
return inner
result = fun1()
result()
------------------------------------------------------------------------
python
2.函数体内部函数体代码可以通过外部访问
def fun2():
def inner():
print("执行了内部函数inner")
def all():
return inner
return all
result = fun2()
result()()
------------------------------------------------------------------------
执行了内部函数inner
四、装饰器
当我们需要将一段函数体代码在不改变调用方式和源代码的情况下,需要给这个段代码添加新的功能时,这时候我们就需要给这段代码安装一个装饰器,装饰器是指将这段代码封装在闭包函数内,来达到既能满足上述条件,又能增加新的功能的条件
概念
- 在不修改被装饰对象源代码和调用方式的情况下给被装饰的对象添加新的功能
本质
- 并不是一门新的技术,而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的效果
口诀
- 对修改封闭,对扩展开放
1、装饰器推导流程
1、首先定义一段函数体代码,当我们给这段函数传入指定的参数时,他就会暂停一秒,然后运行,使它在运行结束后,能够统计它的运行时间
import time
def index(a, b):
time.sleep(1)
print(index,a, b)
2、通常,我们只需要在这段代码运行前打印一个时间戳,运行后再次打印一个时间戳,在这段代码运行结束后通过前后时间的插值就能统计出这段代码的运行时间,但这种办法使用起来比较麻烦且只能使用一次
方法一:
import time
def index(a, b):
start = time.time()
time.sleep(1)
print(index, a, b)
end = time.time()
print(end - start)
index(1,2)
方式二:
import time
def index(a, b):
time.sleep(1)
print(index, a, b)
start = time.time()
index(1,2)
end = time.time()
print(end - start)
3、通过上述方法的方式二,我们可以得出将函数名包裹在统计时间功能代码内,这样在调用时相对便捷,进一步思考,若将这段代码使用函数封包,那样在调用时就可以更为便捷,在以后统计该代码时,只需要调用封包这段代码的函数名就可以直接统计这段代码的运行时间
import time
def index(a, b):
time.sleep(1)
print(index, a, b)
def time_():
start = time.time()
index()
end = time.time()
print(end - start)
time_()
------------------------------------------------------------------------
Traceback (most recent call last):
File "D:/pytcharm项目文件路径/38/11.py", line 297, in <module>
time_()
File "D:/pytcharm项目文件路径/38/11.py", line 293, in time_
index()
TypeError: index() missing 2 required positional arguments: 'a' and 'b'
4、虽然这种方式可以行得通,但只能针对没有参数的函数体代码,若这段代码需要传参者无法运行,并直接报错。再次进一步思考,只需要将封包的这段函数设置为有参函数就可解决这个问题
import time
def index(a, b):
time.sleep(1)
print(index, a, b)
def core(a,b):
start = time.time()
index(a, b)
end = time.time()
print(end - start)
core(1, 2)
------------------------------------------------------------------------
<function index at 0x000001F4A0026310> 1 2
1.0047826766967773
5、由上推导可看出,虽然此功能可以更为便捷的统计代码执行时间,但若是源代码的参数需要修改则封包它的参数也需要修改,这时我们可联想到将参数修改为可变长参数,就不会出现这个问题
import time
def index(a, b):
time.sleep(1)
print(index, a, b)
def core(*args,**kwargs):
start = time.time()
index(*args, **kwargs)
end = time.time()
print(end - start)
core(1,2)
------------------------------------------------------------------------
<function index at 0x000002ECDD4E6310> 1 2
1.004744529724121
6、这样无论源代码参数如何修改,我们都可以进行传参,虽然这个问题解决了,但考虑使用的广泛性,若有其他函数体也需要用到这个功能时,还需要重新修改封包内代码,这时,我们可以使用闭包的方式来满足这个条件
import time
def index(a, b):
time.sleep(1)
print(index, a, b)
def func(x, y, z):
time.sleep(2)
print(func, x, y, z)
def outer(index):
def core(*args, **kwargs):
start = time.time()
index(*args, **kwargs)
end = time.time()
print(end - start)
return core
res = outer(func)
res(1, 2, 3)
------------------------------------------------------------------------
<function func at 0x0000018C23686670> 1 2 3
2.00856614112854
7、通过将源代码函数名放至闭包函数参数内,就可以达到可以调动任何函数体代码都可以执行此功能的方法,但并未满足闭包函数的条件,源代码的调用方式改变了,这时我们可以通过将原函数体代码赋值的方式来达到调用方式和源代码都未改变的情况下来增加此功能
import time
def index(a, b):
time.sleep(1)
print(index, a, b)
def func(x, y, z):
time.sleep(2)
print(func, x, y, z)
def outer(index):
def core(*args, **kwargs):
start = time.time()
index(*args, **kwargs)
end = time.time()
print(end - start)
return core
index = outer(index)
index(1,2)
func = outer(func)
func(1, 2, 3)
------------------------------------------------------------------------
<function outer.<locals>.core at 0x0000026C17F58280> 1 2
1.004807710647583
<function outer.<locals>.core at 0x0000026C17F58940> 1 2 3
2.0077626705169678
8、虽然上述推导过程都已满足装饰器条件,但是考虑到源代码有返回值的情况,我们没有并没有获取,这时在进一步推导,可在装饰器函数内部调用源代码函数名的位置设置一个变量名用于接收返回值,传给装饰器底层return用于接收即可解决这个问题
import time
def index(a, b):
time.sleep(1)
print(index, a, b)
return 'index'
def func(x, y, z):
time.sleep(2)
print(func, x, y, z)
return 'func'
def outer(index):
def core(*args, **kwargs):
start = time.time()
res = index(*args, **kwargs)
end = time.time()
print(end - start)
return res
return core
index = outer(index)
res = index(1,2)
print(res)
func = outer(func)
res = func(1, 2, 3)
print(res)
------------------------------------------------------------------------
<function outer.<locals>.core at 0x0000020C50A78280> 1 2
1.0050580501556396
index
<function outer.<locals>.core at 0x0000020C50A78940> 1 2 3
2.0094454288482666
func
2、装饰器语法糖
什么是装饰器语法糖
当我们使用装饰器调用被装饰的函数体代码时,总是需要在调用前通过赋值的方式来调用,这样的方式相对比较麻烦,这时我们就可以用到装饰器语法糖来节省时间和代码
语法糖的使用方法和条件
用法:在源代码函数体上方使用@加装饰器函数名条件:源代码需在装饰器下方
具体用法
import time
def outer(index):
def core(*args, **kwargs):
start = time.time()
res = index(*args, **kwargs)
end = time.time()
print(end - start)
return res
return core
@outer
def index(a, b):
time.sleep(1)
print(index, a, b)
return 'index'
index(1,2)
3、装饰器模板
def outer(func):
def inner(*args, **kwargs):
# 执行被装饰对象之前可以做的额外操作
res = func(*args, **kwargs)
# 执行被装饰对象之后可以做的额外操作
return res
return inner
Python基础之函数:2、globlal与nonlocal和闭包函数、装饰器、语法糖的更多相关文章
- Fluent_Python_Part3函数即对象,07-closure-decoration,闭包与装饰器
第7章 函数装饰器和闭包 装饰器用于在源码中"标记"函数,动态地增强函数的行为. 了解装饰器前提是理解闭包. 闭包除了在装饰器中有用以外,还是回调式编程和函数式编程风格的基础. 1 ...
- Python编程四大神兽:迭代器、生成器、闭包和装饰器
生成器 生成器是生成一个值的特殊函数,它具有这样一个特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程序 ...
- python装饰器 语法糖
简介: 装饰器(Decorators)是 Python 的一个重要部分.简单地说:他们是修改其他函数的功能的函数. 比如说我们写flask,路由就是用装饰器定义的.如果写权限控制,那么权限控制一般也是 ...
- python 装饰器(语法糖)
def login(func): def testlogin(): for i in range(3): _username="abc" ...
- Python记录9:函数4:名称空间作用域+闭包函数+装饰器
''' 一: 名称空间namespaces 名称空间就是存放名字与值绑定关系的内存空间 二: 名称空间分为三种 内置名称空间: 1. 特点: 存放是python解释器自 ...
- python_函数名的应用、闭包、装饰器
0.动态传参内容补充: 0.1 单纯运行如下函数不会报错. def func1(*args,**kwargs): pass func1() 0.2 *的魔性用法 * 在函数定义的时候,代表聚合. *在 ...
- python基础知识13---函数对象、函数嵌套、名称空间与作用域、装饰器
阅读目录 一 函数对象 二 函数嵌套 三 名称空间与作用域 四 闭包函数 五 装饰器 六 练习题 一 函数对象 1 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 ...
- 《python基础教程(第二版)》学习笔记 函数(第6章)
<python基础教程(第二版)>学习笔记 函数(第6章) 创建函数:def function_name(params): block return values 记录函数:def f ...
- 一文搞懂Python函数(匿名函数、嵌套函数、闭包、装饰器)!
Python函数定义.匿名函数.嵌套函数.闭包.装饰器 目录 Python函数定义.匿名函数.嵌套函数.闭包.装饰器 函数核心理解 1. 函数定义 2. 嵌套函数 2.1 作用 2.2 函数变量作用域 ...
随机推荐
- windows10/11高性能模式开启
大部分用户windows10和11高性能模式都被隐藏了 并且没有隐藏选项我们如何开启呢如下 win+R如下 打开运行-输入cmd进入后输入代码如下 powercfg -SETACTIVE 8c5e7f ...
- CF-1675D. Vertical Paths
题意:每次可以选择一条路径,要求这条路径中每个点都是上一个点的子节点,求最少需要几条路径将所有点走完 思路:将每个点有没有子节点判断出来,因为只有没有子节点的点需要新增一条路,所以需要路径的最小数目就 ...
- Html飞机大战(三):定义状态
好家伙, 1.为飞机大战定义状态 1.开始 START 有一个飞机大战LOGO &天空 2.开始时 STRATING 有一个飞机加载的界面&天空 3.运行时 RUNNING 我方飞机& ...
- STC15 串口通信
串口1选择定时器2产生波特率 串口1相关寄存器 1.选择串口1所放的管脚 2.串口1配置步骤 3.选择串口工作模式 4.确定定时器2工作速度 代码配置 void Uart1_Tim2_Config(i ...
- KingbaseES 行列转换函数
关键字: 行专列,列转行, pivot, unpivot 行列转换是在数据分析中经常用到的一项功能,KingbaseES从V8R6C3B0071版本开始通过扩展插件(kdb_utils_func ...
- Gitea 1.17.1 正式发布 | 08 累积更新
Gitea 1.17.1 已正式发布.在这个小的版本更新中我们合并了 35 个 PR,没有包含功能性的更改,但我们强烈建议用户升级到此版本以获得重要的修复补丁. 致谢:感谢报告问题的安全研究人员,同时 ...
- vivo 全球商城:电商平台通用取货码设计
vivo官网商城开发团队 - Zhou Longjian 一.背景 随着O2O线上线下业务的不断扩展,电商平台也在逐步完善交易侧相关的产品功能.在最近的需求版本中,业务方为进一步提升用户的使用体验,规 ...
- 云原生之旅 - 3)Terraform - Create and Maintain Infrastructure as Code
前言 工欲善其事,必先利其器.本篇文章我们介绍下 Terraform,为后续创建各种云资源做准备,比如Kubernetes 关键词:IaC, Infrastructure as Code, Terra ...
- PAT乙级 1024 科学计数法
思路 1.尝试失败:一开始想打算把结果直接存在一个字符串中,后来发现当指数大于0的时候还需要分别考虑两种情况,工程量巨大,尝试失败,于是借鉴了其他大佬思路,写出了ac代码 2.ac思路:首先取指数的绝 ...
- 2016 ZCTF note3:一种新解法
2016 ZCTF note3:一种新解法 最近在学习unlink做到了这道题,网上有两种做法:一种是利用edit功能读入id时整数溢出使索引为-1,一种是设置块大小为0使得写入时利用整数溢出漏洞可以 ...