Python函数——命名空间与闭包
前言
执行以下代码
def my_test():
x = 1
y = x+1 print(x) 》》
Traceback (most recent call last):
File "C:/Users/jingjing/PycharmProjects/py3Project/路飞/第二模块/函数练习/斐波那契.py", line 36, in <module>
print(x)
NameError: name 'x' is not defined
x在函数里面定义了,为什么会报错?
python解释器如何执行
"""
从python解释器开始执行之后,就在内存中开辟了一个空间 每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。 但是当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。 等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中。函数中的变量只能在函数的内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。
"""
结论:“存放变量与值的关系”的空间——叫做命名空间
代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间
命名空间与作用域
命名空间的本质:存放变量与值的绑定关系
- 全局命名空间:创建的存储“变量名与值的关系”的空间叫做全局命名空间
- 局部命名空间:在函数的运行中开辟的临时的空间叫做局部命名空间
- 内置命名空间:内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
三种命名空间之间的加载与取值顺序:
加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
使用:全局不能使用局部的,局部的可以使用全局的。
作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
globals方法:查看全局作用域的名字【print(globals())】
locals方法:查看局部作用域的名字【print(locals())】
def func():
a = 12
b = 20
print(locals())
print(globals()) func()
global关键字,在函数内部修改全局变量的值(在多人协作开发时慎用)
a = 10
print('原始值',a)
def func():
global a
a = 20
print('函数修改值', a) func()
print('最终值',a) """
原始值 10
函数修改值 20
最终值 20 全局变量被修改
""" a = 10
print('原始值',a)
def func():
a = 20
print('函数修改值', a) func()
print('最终值',a) """
原始值 10
函数修改值 20
最终值 10 全局变量没有修改
"""
nonlocal关键字:在嵌套函数中,让内部函数中的变量在上一层函数中生效,外部必须有变量定义
a = 1
print('原始值',a)
def f1():
a = 2
print('进入f1内的打印', a)
def f2():
a = 5
def f3():
nonlocal a # 修改局部的(当用nonlocal时),global a 修改全局的
a = 100
print('f3内的打印',a)
f3()
print('离开f2内的打印', a) # nonlocal修改的值只对上一层函数(存在变量a被修改)的范围内有影响 ,此处只对f2有效
f2()
print('离开f1内的打印', a)
f1()
print('最终值', a) # nonlocal修改的值不影响全局的值 """
原始值 1
进入f1内的打印 2
f3内的打印 100
离开f2内的打印 100
离开f1内的打印 2
最终值 1
""" a = 1
print('原始值',a)
def f1():
a = 2
print('进入f1内的打印', a)
def f2():
# a = 5 取消修改,nonlocal会对f1有影响
def f3():
nonlocal a # 修改局部的(当用nonlocal时),global a 修改全局的
a = 100
print('f3内的打印',a)
f3()
print('离开f2内的打印', a) # nonlocal修改的值只对上一层函数(存在变量a被修改)的范围内有影响,此处对f2和f1有效,因为a在f1中被修改,在f2中没有变化
f2()
print('离开f1内的打印', a)
f1()
print('最终值', a) # nonlocal修改的值不影响全局的值 """
原始值 1
进入f1内的打印 2
f3内的打印 100
离开f2内的打印 100
离开f1内的打印 100
最终值 1 """
函数作用域查找顺序
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
- locals 是函数内的名字空间,包括局部变量和形参
- enclosing 外部嵌套函数的名字空间
- globals 全局变量,函数定义所在模块的名字空间
- builtins 内置模块的名字空间
level = 'L0'
n = 22
def func():
level = 'L1'
n = 33
print(locals()) def outer():
n = 44
level = 'L2'
print(locals(), n) def inner():
level = 'L3'
print(locals(),n) # 此外打印的n是多少?
inner()
outer() """
问题:在inner()里的打印的n的值是多少?44 取邻近函数outer中n=44
{'n': 33, 'level': 'L1'}
{'level': 'L2', 'n': 44} 44
{'level': 'L3', 'n': 44} 44
"""
func()
闭包
函数名的本质:就是函数的内存地址
def func():
print('func')
a = func
print(a)
"""
<function func at 0x0000000002357B70> # a指向了函数的内存地址
"""
函数名可以作为函数的返回值
def func():
print("func")
def func2():
print('func2')
return '返回func2'
return func2 # 函数名作为返回值 func2 = func() # 返回func2地址
print(func2)
print(func2())
"""
func
<function func.<locals>.func2 at 0x0000000002567840>
func2
返回func2
"""
闭包的定义:内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数
# 闭包的常用形式:
def func():
name = 'eva'
def inner():
"""闭包函数"""
print(name)
print(inner.__closure__) # 输出的__closure__有cell元素 :是闭包函数
return inner f = func()
f()
"""
(<cell at 0x0000000000510C48: str object at 0x0000000002558B90>,)
eva
"""
判断闭包函数的方法:__closure__
#输出的__closure__有cell元素 :是闭包函数
def func():
name = 'eva'
def inner():
print(name)
print(inner.__closure__)
return inner f = func()
f() #输出的__closure__为None :不是闭包函数,因为name为全局变量
name = 'egon'
def func2():
def inner():
print(name)
print(inner.__closure__)
return inner f2 = func2()
f2()
闭包获取网络应用
from urllib.request import urlopen def outer():
url = "http://www.xiaohua100.cn/index.html"
def inner():
return urlopen(url).read()
return inner a = outer()
content = a()
print(content)
总结
作用域:小范围的可以用大范围的,但是大范围的不能用小范围的
范围从大到小(图)
如果在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有的,就用上上级的,以此类推
如果都没有,报错
函数作用域查找顺序:
LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> builtins
函数名的本质:
就是一个变量,保存了函数所在的内存地址
闭包:
内部函数包含对外部作用域而非全局作用域名字的引用,该内部函数称为闭包函数
Python函数——命名空间与闭包的更多相关文章
- python 函数名 、闭包 装饰器 day13
1,函数名的使用. 函数名是函数的名字,本质就是变量,特殊的变量.函数名()加括号就是执行此函数. 1,单独打印函数名就是此函数的内存地址. def func1(): print(555) print ...
- python函数作用域,闭包,装饰器
第一:函数作用域: L:local 函数内部作用域 E:enclosing 函数内部与内嵌函数之间(闭包) G:global 全局作用域 B:build_in ...
- python函数对象和闭包
关于函数对象和闭包 闭包(closure)是函数式编程的重要的语法结构.不同的语言实现闭包的方式不同.Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看 ...
- Python函数进阶:闭包、装饰器、生成器、协程
返回目录 本篇索引 (1)闭包 (2)装饰器 (3)生成器 (4)协程 (1)闭包 闭包(closure)是很多现代编程语言都有的特点,像C++.Java.JavaScript等都实现或部分实现了闭包 ...
- python基础(7)-函数&命名空间&作用域&闭包
函数 动态参数 *args def sum(*args): ''' 任何参数都会被args以元组的方式接收 ''' print(type(args)) # result:<class 'tupl ...
- Python之命名空间、闭包、装饰器
一.命名空间 1. 命名空间 命名空间是一个字典,key是变量名(包括函数.模块.变量等),value是变量的值. 2. 命名空间的种类和查找顺序 - 局部命名空间:当前函数 - 全局命名空间:当前模 ...
- python 函数进阶与闭包
函数的命名空间和作用域 引言 现在有个问题,函数里面的变量,在函数外面能直接引用么? def func1(): m = 1 print(m) print(m) #这行报的错 报错了: NameErro ...
- python 函数名,闭包
1.函数名字的应用 函数名是什么? 函数名是函数的名字,本质:变量,特殊变量 函数名+() ———>执行此函数: 2.函数名的赋值: def func2(): print(44) f = fun ...
- python函数知识七 闭包、装饰器一(入门)、装饰器二(进阶)
21.闭包 闭包:在嵌套函数内,使用非全局变量(且不使用本层变量) 闭包的作用:1.保证数据的安全性(纯洁度).2.装饰器使用 .__closure__判断是否是闭包 def func(): a = ...
随机推荐
- 根据文件夹更改样本文件名小程序.py
#按照文件名设置标签并将其插入文件名中import osimport shutil#获取目标文件夹的路径a= r'C:\Users\yy\Desktop\tianchi大赛\guangdong_rou ...
- Discuz!开发之HTML转Discuz代码(bbcode)函数html2bbcode()
定义文件:\source\function\function_editor.php函数定义: function html2bbcode($text) { $text = strip_tags($tex ...
- Python人工智能之路 - 第三篇 : PyAudio 实现录音 自动化交互实现问答
Python 很强大其原因就是因为它庞大的三方库 , 资源是非常的丰富 , 当然也不会缺少关于音频的库 关于音频, PyAudio 这个库, 可以实现开启麦克风录音, 可以播放音频文件等等,此刻我们不 ...
- 281. Zigzag Iterator z字型遍历
[抄题]: Given two 1d vectors, implement an iterator to return their elements alternately. Example: Inp ...
- ABP框架初始化数据(自定义)
找到目录:AbpFramework.EntityFramework>Migrations>SeedData,这目录下创建类:DefaultDataCreator.cs using Syst ...
- vue 需求 data中的数据之间的调用
我遇到过这种情况 就是在我的data中 会有数据调用data中的其他数据 如图 我的alertInfoType需要拿到screeningCondition中type的值 用过vue的都知道 我是不 ...
- linux 安装mysql相关和openjdk
新装的centos 6.9虚拟机 修改yum 服务器源 cd /etc/yum.repos.d/ rename repo repo.bak_$(date +%F) * 阿里的yum库 https:/ ...
- NPOI 导入为table 处理excel 格式问题
ICell cell = row.GetCell(j); if (!cell.isDbNullOrNull()) { switch (cell.CellType) { case CellType.Bl ...
- spring入门--spring入门案例
spring是一个框架,这个框架可以干很多很多的事情.感觉特别吊.但是,对于初学者来说,很难理解spring到底是干什么的.我刚开始的时候也不懂,后来就跟着敲,在后来虽然懂了,但是依然说不明白它到底是 ...
- rsync 定时备份<crontab+backrsync.sh> 简陋版
数据需要定时的备份至其它的目录中,但是备份之前检查检查一下是否有rsync正在运行,曾经因为数据过大,导致有很多rsync进程在跑,然后服务器有出现卡死的现象.最终写了一条bash,先检查一下是否有这 ...