Python 变量作用域的一些问题

python 变量作用域

写程序遇到一些坑,特此记录

  1. 作用域的定义

作用域就是一个 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。

在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。

  1. python 中变量的存储方式

python一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身。

也就是说,python中的变量本质是都是指针,指向堆栈中对应的数据块

  1. 测试
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的列表原理也是类似的

简单记录一下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值