第六章 补充知识:python 命名空间和作用域。
2018-12-30 15:36:56
用例题来弄清楚这两个概念
文章目录
1.引入:阅读以下代码,思考输出结果的原因。
#第一个程序
a=1
def func():
print(a)
func()
#输出
1
#第二个程序
def func():
a=1
func()
print(a)
#报错:
#print(a)
#NameError: name 'a' is not defined
原因:
第一个代码中a是全局变量,可在局部变量中使用;
但第二个代码a是局部里面定义的变量,只能在函数内部进行访问,而全局命名空间中是没有定义变量a的!
以下代码让你更好的理解全局和局部的同名变量相互独立!!
def func():
a = 0
a+= 3
print('局部变量a: ',a)
return a
a='外部的'
print('全局变量a:',a) #打印全局变量a
func() #调用函数
print('全局变量a: ',a) #再次打印全局变量a
#输出
全局变量a: 外部的
局部变量a: 3
全局变量a: 外部的 #尽管调用了func(),还是没变。
内置命名空间(built-in)–python解释器
当启动python解释器的时候就会生成的名字,如print,input等等
全局命名空间(globals)–自定义写的代码,但不是函数中的代码
程序从上至下依次被加载至内存中
放入了所有自定义的函数名和变量名
局部命名空间(locals)–函数
函数内部定义的名字
当函数调用时才会产生这个名称空间,随着函数执行的结束,这个命名空间就会消失。下图表示了它们三者之间的关系:

在局部: 可以使用内置和全局命名空间里面的名字。
在全局: 可以使用内置命名空间里的名字,但是不能使用局部命名空间的名字。为什么?
还是用刚才引出的例子,因为在函数调用完成之后,变量a已经被回收了。
在内置: 不能使用全局和局部命名空间里的名字。为什么?因为在启动python解释器时候,就已经读取了内置的名字,且不依赖你写的程序和函数。
在找名字的时候只能一层一层往上找,而不能往下找,也即依赖倒置原则。

2.阅读以下代码的输出结果,思考当使用了和内置命名空间中相同的名字会怎么样?
def max(): #定义同名变量
print('in max func')
print(max()) #调用函数
#输出
in max func #使用的是全局命名空间中定义的名字
None
当在全局定义了和内置空间中同名的名字时,会使用全局的名字。正常情况下,会直接使用内置的名字。
当自己有的时候,就不找上级要了。比如某件事情你有权利决定,那么你就不需要再向你的上级请求了。如果没有,就找上级要。
def input():
print('in input now')
def func():
input()
func()
#输出
in input now
下图来解释上述代码:

那么,如何证明如果自己有,就不找上级要了呢?如下代码:
def func():
input=1
print(input)
func()
#输出
1
小知识:
函数的内存地址+()–>行数执行
若只有函数名,则输出的是地址。把上述代码input去掉,输出的是地址。
3.阅读以下代码,为什么第二个函数会报错?
def func1():
a=1
def func2():
print(a) #a能用吗?
func1()
func2()
#输出
NameError: name 'a' is not defined
局部名字空间可以有多个,而多个名字空间是相互独立的,它们之间不共享!
多个函数应该拥有多个独立的局部命名空间。

4.有了命名空间的基础,下面了解作用域的相关知识。
作用域分两种:
全局作用域–内置和全局空间里的名字都属于全局作用域globals()
局部作用域–函数(局部名字空间中的名字)locals()
以下例子:
a=1
def func():
print(a) #可使用a,为全局作用域
a=1
def func():
a+=1 #可行吗?不行,原因在外面!
对于不可变数据类型,在局部可以查看全局作用域的变量,不能直接修改!如果想要修改,需要在程序开始时候添加global声明!!
a=1
def func():
global a
a=2
func()
print(a)
#输出 因为a为全局变量。
2
如果在一个局部(函数)内声明了global变量,那么这个变量在局部的所有操作将对全局有效。
5.globals和locals两种方法。
a=1
b=2
def func():
x='aa'
y='bb'
print(locals())
#func()
print(globals())
print(locals()) #本地的
#输出结果两者完全一样,原因?
a=1
b=2
def func():
x='aa'
y='bb'
print(locals())
print(globals())
func()
#输出,一个局部,另一个还是全局
原因:globals永远打印全局的名字,而locals输出则根据locals的位置来打印。在全局输出全局,在局部就输出局部。
但尽量避免使用global!
可以通过传参和接收返回值来完成需要global才能完成的操作。
a=1
def func(a):
a=2
return a
a=func(a)
print(a)
如果觉得这篇文章对你有小小的帮助的话,记得给文章点个“赞”哦,博主在此感谢!