赞
踩
一个标识符的可见的范围,就是这个标识符的作用域。一般常说的事变量的作用域
def foo():
x = 100
print(x) #可以访问到么?
上述代码中的x不可以访问到,会抛出异常(NameError:name ‘x’ is not defind),原因在于函数是一个封装,它会开辟一个作用域,x变量被限制在这个作用域中,所以在函数外部x变量不可见。
Ps:每一个函数都会开辟一个作用域
#局部变量
def fn1():
x = 100 #局部作用域,x为局部变量,适用范围在fn1内
def fn2():
print(x) #无法访问x
print(x) #无法访问x
#全局变量
x = 100 #全局变量,也可在函数外定义
def fn3():
print(x)#可以访问x
fn3()
x = 10
def foo():
print(x)
foo()#正常执行,函数外部的变量在函数内可见
x = 10
def foo():
y = x + 1
foo()#正常执行,x取函数外部可见变量
x = 10
def foo():
x = x + 1
foo()#此处报错!
why???
原因分析:
如何解决这一常见问题?
再此引入global语句
x = 10
def foo():
global x
x += 1
foo()#正常执行
def foo():
global x
x = 10
x += 1
foo()
print(x)#能读取x么?
x=10
,也不会在foo这个局部作用域中定义局部变量x了;一个总结:
x += 1
这种特殊形式产生的错误原因?先引用后赋值,而python是动态语言是复制才算定义(赋值即定义!再次敲黑板),才能被引用。解决办法:在这条语句之前加一条x = 0之类的赋值语句,或使用global关键字告诉foo函数,去全局作用域中找变量定义;def counter():
count = 0
def inc()
count += 1
return count
return inc
foo = counter()
print(foo(),foo()
上例一定报错(原因参照前面一个赋值语句的问题),我们可以使用globle来解决:
def counter():
global count
count = 0
def inc()
global count
count += 1
return count
return inc
foo = counter()
print(foo(),foo()
使用global后就是全局变量,而不是闭包了,而且我们前面也提到尽量不要使用global,所以python3+中提供了nonlocal
定义:将变量标记为 不在本地作用域中定义,二是在上级的某一级局部作用域中定义,但不能是全局作用域中定义。
所以上述例子可以改写为:
def counter():
count = 0
def inc()
nonlocal count
count += 1
return count
return inc
foo = counter()
print(foo(),foo()
如此既可以让内部函数引用外部函数的自由变量(全局变量不可以!),又可以形成闭包。
思考下面的foo函数连续调用两次的执行结果分别是什么?
def foo(x = []):
x.append(1)
print(x)
foo()
foo()
>>[1]
>>[1, 1]
为什么第二次执行的结果是[1,1] ?
foo.__defaults__
属性,它是一个元祖。def foo(x = []):
x.append(1)
print(x)
print(id(foo),foo.__defaults__)
foo()
print(id(foo),foo.__defaults__)
foo()
print(id(foo),foo.__defaults__)
执行结果:
>>2268635878808 ([],)
[1]
>>2268635878808 ([1],)
[1, 1]
>>2268635878808 ([1, 1],)
函数内存地址并没有改变,也就是说foo这个对象没有改变过,调用时,它的__defaults__
属性中使用元组保存的默认值x的默认值是引用类型(不急,慢慢绕),引用类型的元素变动并不是元组的变化;
非引用类型的默认值不存在此效果~
Ps:如果本文解决你的困惑,请给个赞~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。