python 变量作用域
写程序遇到一些坑,特此记录
- 作用域的定义
作用域就是一个 Python 程序可以直接访问命名空间的正文区域。
在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种,分别是:
有四种作用域:
L(Local):最内层,包含局部变量,比如一个函数/方法内部。
E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A
里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
G(Global):当前脚本的最外层,比如当前模块的全局变量。 B(Built-in): 包含了内建的变量/关键字等。,最后被搜索
规则顺序: L –> E –> G –>gt; B。在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
- python 中变量的存储方式
python一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身。
也就是说,python中的变量本质是都是指针,指向堆栈中对应的数据块
- 测试
def func():
a=1
print('func: '+str(id(a)))
print('func: '+str(a))
if __name__=='__main__':
x=1
print('main_first: '+str(id(x)))
func()
print('main: '+str(id(x)))
print('main_last: '+str(x))
所得结果:
main_first: 1586161584
func: 1586161584
func: 1
main: 1586161584
main_last: 1
func()函数中,a为局部变量,main()函数中,x为全局变量,
由于两者的值相同,所以id号相同,地址是一样的
但是两者是互不影响的
def func():
a=1
print('func_first: '+str(id(a)))
print('func_first: '+str(a))
a = 2
print('func_last: ' + str(id(a)))
print('func_last: ' + str(a))
if __name__=='__main__':
x=1
print('main_first: '+str(id(x)))
func()
print('main_last: '+str(id(x)))
print('main: '+str(x))
所得结果为:
main_first: 1586161584
func_first: 1586161584
func_first: 1
func_last: 1586161600
func_last: 2
main_last: 1586161584
main: 1
可以看到,全局变量x并没有因为局部变量a的改变而改变,改变的只是a的地址
普通变量如此,列表又如何呢?
def func():
a=[1]
print('func_first: '+str(id(a)))
print('func_first: '+str(a))
if __name__=='__main__':
x=[1]
print('main_first: '+str(id(x)))
func()
print('main_last: '+str(id(x)))
print('main: '+str(x))
所得结果为:
main_first: 56005512
func_first: 56062120
func_first: [1]
main_last: 56005512
main: [1]
可以看到两者又是不同的了,a和x是两个完全不同的列表,只是内部的值相同,占用的是不同的内存块
是因为变量名称的影响吗?
def func():
x=[1]
print('func_first: '+str(id(x)))
print('func_first: '+str(x))
if __name__=='__main__':
x=[1]
print('main_first: '+str(id(x)))
func()
print('main_last: '+str(id(x)))
print('main: '+str(x))
所得结果为:
main_first: 51549064
func_first: 51605672
func_first: [1]
main_last: 51549064
main: [1]
结果还是一样的
接下来,在func()函数中直接调用全局变量列表x
def func():
print('func_first: '+str(id(x)))
print('func_first: '+str(x))
if __name__=='__main__':
x=[1]
print('main_first: '+str(id(x)))
func()
print('main_last: '+str(id(x)))
print('main: '+str(x))
所得结果为:
main_first: 50828168
func_first: 50828168
func_first: [1]
main_last: 50828168
main: [1]
确实是一样的
接下来,在fun()函数中对列表x进行操作
def func():
print('func_first: '+str(id(x)))
print('func_first: '+str(x))
x.append(2)
print('func_last: ' + str(id(x)))
print('func_last: ' + str(x))
if __name__=='__main__':
x=[1]
print('main_first: '+str(id(x)))
func()
print('main_last: '+str(id(x)))
print('main: '+str(x))
所得结果为:
main_first: 55939944
func_first: 55939944
func_first: [1]
func_last: 55939944
func_last: [1, 2]
main_last: 55939944
main: [1, 2]
熟悉C语言的同学对这个应该就很熟悉了
往函数中传入指针变量,虽然指针变量是局部变量,但是指向的数组和全局变量指针指向的数组是同一个
因此,在函数中通过局部变量指针改变的数组的值,在退出函数后,对全局变量的数组依旧是有效的
python的列表原理也是类似的
简单记录一下