1、名称空间(namepaces)与作用域。
名称空间即存放名字与对象映射/绑定关系的地方。对于x=3,Python会申请内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间中。
del x表示清除该绑定关系
名称空间:是一个非常重要的思想,不是真正的空间,只是虚拟出来的一块空间,
作用是:在不同的空间内存放相同是名字,例如:一班有个同学叫张三,男。二班也有同学叫张三,女。
命名空间分为三类:
(1)内置名称空间
(2)全局名称空间
(3)局部名称空间
(1)三种名称空间用途与存活周期(这里的活动周期是指python运行程序的三个阶段:启动python解释器,加载文件内容到内存,python执行程序)
一、名称空间namespace:用于存放名字的地方,是对栈区的划分。
有了名称空间之后,就可以在栈区中存放相同的名字,
详细的名称空间分为三种:
1、内置名称空间:有一个
存放的名字:存放的是python解释器内置的名字,
举例如下:
>>> print
<built-in function print>
>>> input
<built-in function input>
存活周期:关于python运行程序的三个阶段
开始:python解释器启动。
结束:python解释器关闭。
2、全局名称空间:有一个
存放的名字:运行顶级代码所产生的名字,只要不是函数内定义的和内置的,全为全局名称空间。
顶级:在python解释器里:没有缩进的叫顶级
例如:
示例一:import os
示例二: x = 10
示例三:这里的y和z都是全局命名空间
if 13 > 3:
y = 20
if 3 == 3:
z=30
示例四:func=函数的内存地址,是全局命名空间,a和b数据局部命名空间
def func():
a=111
b=222
存活周期:
开始:python文件执行则开始。
结束:python文件运行完毕后结束。
3、局部名称空间,可以有多个
存放的名字:在调用函数时,运行函数体代码过程中产生的函数内的名字。
示例:func=函数的内存地址,是全局命名空间,a和b数据局部命名空间
def func():
a=111
b=222
存活周期:
开始:在调用函数时存活。
结束:在函数调用完毕后则销毁。
(2)三种名称空间的加载顺序
三种名称空间的加载顺序:
内置名称空间》全局名称空间》局部名称空间
在运行python解释器时:内置名称空间和全局名称空间一定存在。局部名称空间可以在调用函数时在创建。
三种名称空间的销毁顺序:
局部名称空间》全局名称空间》内置名称空间
(3)三种名称空间的查找名字的优先级
三种名称空间的查找优先级:从当前所在位置开始,逐层向上一级查找,
内置名称空间
全局名称空间
局部名称空间
局部名称空间没有去全局名称空空间,全局名称空间没有再去内置名称空间。
查找局部的
input = 333 # 全局的
def func():
input = 444 # 局部的
print(input)
func() # 444
查找全局的
input = 333 # 全局的
def func():
# input = 444 # 局部的
print(input)
func() # 333
查找内置的
# input = 333 # 全局的
def func():
# input = 444 # 局部的
print(input)
func() # <built-in function input> # 内置的
从当前所在位置开始,逐层向上一级查找
# 示范1:名称空间实例:查找顺序
# x = 111
# def func():
# print(x) # 111
# print(y) # 222
# y = 222
# func() # 111
# 示范2:名称空间的“嵌套”关系,是以定义阶段为准,与调用位置无关
x = 1
def func(): # 此处为局部的
print(x) # 嵌套的为全局的x=1
def foo(): # 此处为局部的
x = 222 # 在此处定义个x =222
func()
foo() # 结果为1 重点:名称空间的“嵌套”关系,是以定义阶段为准,与调用位置无关
# 实例3:函数的嵌套定义,从当前位置向上一层进行查找。
input = 111 # 当此处被注释打印<built-in function input>
def f1():
input = 222 # 当此处被注释打印111
def f2():
input = 333 # 当此处被注释打印222
print(input)
f2()
f1() # 输出结果:333
如下图所示:
# 实例4:查找顺序以定义阶段为准
x = 111
def func():
print(x) # 此处的x为局部的,当语法扫描到此处时候,该处的x未定义
x = 222 # 当此处定义了x=222时此处出现的语法逻辑上错误,针对变量需要先定义后使用
func() #报错: UnboundLocalError: local variable 'x' referenced before assignment
# 实例5:
x = 111
def func():
x = 222 # 为避免实例4的错误,应在此处定义x
print(x)
# x = 222
func()
3、作用域:作用范围,对名称空间归类,有两大类(全局和局部)
(1)全局作用域:内置名称空间、全局名称空间
1、全局存活:除非被删除否则在文件执行过程中存活
2、全局有效:被所有函数共享,在任意位置都可以使用。
# 不同函数内的名字独立
def foo():
x = 111
print(x,id(x))
def bar():
x = 222
print(x,id(x))
foo() # 111 140715383776352
bar() # 222 140715383779904
# 全局存活,全局有效
x = 111
def foo():
print(x,id(x))
def bar():
print(x,id(x))
foo() # 111 140715385939040
bar() # 111 140715385939040
(2)局部作用域 :局部名称空间的名字
1、临时存活:函数在调用时临时生成,函数在调用结束后释放
2、局部有效:只能在函数内使用它
def func(x):
def f1():
def f2():
print(x)
LEGB:
# 名称空间分为四个:LEGB为便于记忆 L;local,E:enclosing, G:global,B:built-in
# 局部名称空间分为两类:
# B
# G
def f1():
# E
def f2():
# E:enclosing
def f3():
# L:local
print()
global
# 实例1:修改全局变量
# x = 111
# def func():
# # global x # 修改全局变量
# x = 222
# print(x)
#
# func() # 222
# print(x) # 111
# 实例2:如果想要在局部修改全局的名字的对应的值(这里针对不可变类型,必须使用global),需要使用global修改全局变量
# x = 111
# def func():
# global x # 声明x这个名字时全局的名字,不在早遭新的名字了
# x = 222
# print(x)
#
# func() # 222
# print(x) # 222
# 实例3:针对可变类型
# l = [111,222]
# def func():
# l = 333
# print(l)
#
# func() # 333
# print(l) # [111, 222]
l=[1,2,3]
def func():
global l # 针对不可变类型,有global和无global的效果是一样的
l.append(4)
func()
print(l) # [1, 2, 3, 4]
# 体验一下有无调用的效果
# def func():
# global x
# x = 111
# print(x) # NameError: name 'x' is not defined
def func():
global x
x = 111
func()
print(x) # 111
nonlocal作用
# nonlocal(了解):实例1:修改函数外层函数包含的名字对应的值(不可变类型)
# x = 0
# def f1():
# x = 11
# def f2():
# global x # 修改全局变量也就是说把x=0的值改成了22
# x = 22
# f2()
# print("全局的x变化后查看f1内的x:",x) # f1内的x: 11,发现此处的函数没有变化,如果我想改变它,该如何办?使用nonlocal
# f1()
# print(x) # 22
# nonlocal(了解):实例2
# x = 0
# def f1():
# x = 11
# def f2():
# nonlocal x # 从当前层的外一层开始找,没有就报错,SyntaxError: no binding for nonlocal 'x' found
# x = 22
# f2()
# print("全局的x变化后查看f1内的x:",x) # f1内的x: 22
# f1()
# print(x) # 0
# nonlocal(了解):实例3
x = 0
def f1():
x = [] # 此处如果时可变类型,不用声明了,可以直接修改
def f2():
x.append(3333)
f2()
print("全局的x变化后查看f1内的x:",x) # f1内的x: [3333]
f1()
print(x) # 0
针对名称空间的练习操作:
# 作业要求:下述所有代码画图以及分析代码执行流程
# 1、以定义阶段为准,先画出名称空间的嵌套关系图
# 2、然后找到调用函数的位置,写出函数调用时代码的执行过程,涉及到名字的查找时,参照1中画好
# 的嵌套图,标明查找顺序,一层一层直到找到位置7
# # ===================题目一===================
input=333
def func():
input=444
print(input)
func()
print(input)
# # ===================题目二===================
# def func():
# print(x)
# x=111
#
# func()
从局部开始找x,局部没有去全局找,找到了x=111
# # ===================题目三===================
# x=1
# def func():
# print(x)
#
#
# def foo():
# x=222
# func()
# x = 333
# foo() # 333
# # ===================题目四===================
input=111 # 第四次注释
def f1():
def f2():
# input=444 # 第一次注释
print(input)
# input=222 # 第二次注释
f2()
# input = 333 # 第三次注释
f1()
# 不注释得到的结果:444
# 第一次注释得到的结果:222
# 第二次注释得到的结果:333
# 第三次注释得到的结果:111
# 第四次注释得到的结果:<built-in function input>
# # ===================题目五===================
# x=111
# def func():
# print(x) #
# x=222
#
# func()
#
#
# # ===================题目六===================
# x=111
#
# def foo():
# print(x,)
#
# def bar():
# print(x)
#
# foo()
# bar()
#
# # ===================题目七===================
# x=1
# def func2():
# func1()
#
# x=2
# def func1():
# print(x)
#
# x=3
#
# func2()
#
# # ===================题目八===================
# 1、如下全局变量记录了当前登录用户,编写登录功能,一旦用户登录成功,则将全局变量赋值为当前登录的用户名
# login_user=None
# 2、针对之前编写的查询余额的功能,添加额外的逻辑:如果用户没有登录,则先执行登录功能
# 验证使用locals()和globals()函数的作用,查看名称空间
x = 1
def foo():
x = 2
print("局部名称空间:",x)
# 查看局部名臣空间,结果以字典形式展现
print(locals()) # {'x': 2}
foo()
print("全局名称空间:",x)
# 查看全局名称空间,结果以字典形式展示
print(globals())
# {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000020CA8200970>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/pycharm/oldboy_29/day015/test015/test015_10global和local.py', '__cached__': None, 'x': 1, 'foo': <function foo at 0x0000020CA83495E0>}