1.golbal关键字
2.闭包概念
3.默认值作用域
4.不修改默认值的两个方法
5.变量名解析规则LEGB
6.函数销毁
1.golbal关键字
使用global关键字的变量,将函数定义时的变量声明为使用外部全局作用域中定义的变量
在内部作用域为一个外部作用域的变量赋值,不是在内部作用域定义一个新变量,改变量作用域还是全局的
>>> x = 5
>>> def foo():
... x += 1
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'x' referenced before assignment
>>> def foo():
... global x
... x += 1
... print(x)
>>> foo()
6
>>> y = 10
>>> def foo():
... global y
... y = 99
... y += 1
... print(y)
>>> foo()
100
2.闭包
自由变量:未在本地作用域中定义的变量。
闭包:这仅仅是一个概念,出现函数嵌套时,内层函数引用到了外层函数的自由变量,就形成了闭包
注意:使用nonlocal关键字,将变量标记为不在本地作用域中定义,而在上级的某一级作用域中定义,但不能在全局作用域中定义
>>> def counter():
... count=0
... def inc():
... count += 1
... return count
... return inc
>>> foo = counter()
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in inc
UnboundLocalError: local variable 'count' referenced before assignment
>>> def counter():
... count = 0
... def inc():
... nonlocal count
... count += 1
... return count
... return inc
>>> foo = counter()
>>> type(foo)
<class 'function'>
>>> foo()
1
>>> foo()
2
变量在全局作用域中定义,使用nonlocal声明时会报错
>>> a = 100
>>> def fun():
... nonlocal a
... a += 1
... print(a)
File "<stdin>", line 2
SyntaxError: no binding for nonlocal 'a' found
3.默认值作用域
python把函数的默认值放在了函数对象的属性中,这个属性会伴随函数对象的生命周期
属性defaults属性中使用元组保存所有位置参数默认值
属性kwdefaults中使用字典保存所有keyword-only参数的默认值
3.1__defaults__属性
>>> def foo(xyz=1):
... print(xyz)
...
>>> foo()
1
>>> print(foo.__defaults__)
(1,)
>>> def foo(xyz=[]):
... xyz.append(1)
... print(xyz)
...
>>> foo()
[1]
>>> foo()
[1, 1]
>>> print(xyz)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'xyz' is not defined
>>> print(foo.__defaults__)
([1, 1],)
>>> def fn(xyz=[],m=123,n='abc'):
... xyz.append(1)
... print(xyz)
...
>>> print(id(foo),foo.__defaults__)
139713265391504 ([1, 1],)
>>> foo()
[1, 1, 1]
>>> print(id(foo),foo.__defaults__)
139713265391504 ([1, 1, 1],)
>>> foo()
[1, 1, 1, 1]
>>> print(id(foo),foo.__defaults__)
139713265391504 ([1, 1, 1, 1],)
函数地址并没有变,就是说foo这个函数对象没有变过,函数调用时defaults属性中使用元组保存默认值xyz默认值的引用类型,引用类型的元素变动,并不是元组的变化
3.2非引用类型却省值
>>> def foo(xyz,m=123,n='abc'):
... m=456
... n='def'
... print(xyz)
...
>>> print(foo.__defaults__)
(123, 'abc')
>>> foo('stone')
stone
>>> print(foo.__defaults__)
(123, 'abc')
属性defaults中使用元组保存所有位置参数默认值,它不会因为在函数体内改变了局部变量的值而发生改变
3.3__kwdefaults__属性
>>> def foo(xyz,m=123,*,n='abc',t=[1,2]):
... m=456
... n='def'
... t.append(300)
... print(xyz,m,n,t)
...
>>> print(foo.__defaults__,foo.__kwdefaults__)
(123,) {'n': 'abc', 't': [1, 2]}
>>> foo('stone')
stone 456 def [1, 2, 300]
>>> print(foo.__defaults__,foo.__kwdefaults__)
(123,) {'n': 'abc', 't': [1, 2, 300]}
3.4"+"和"+="的区别
>>> def foo(a=[]):
... a += [5]
...
>>> print(foo.__defaults__)
([],)
>>> foo()
>>> foo()
>>> print(foo.__defaults__)
([5, 5],)
>>> def foo(a=[]):
... a = a + [5]
...
>>> print(foo.__defaults__)
([],)
>>> foo()
>>> foo()
>>> print(foo.__defaults__)
([],)
+号表示两个列表合并并且返回一个全新的列表
+=表示,就地修改前一个列表,在其后追加后一个列表,就是列表的extend方法
4.不修改默认值的两个方法
当使用可变类型作为默认值时,就可能会修改默认值,如何做到不修改,或者按需修改呢?
4.1函数体内不改变默认值
>>> def foo(xyz=[],u='abc',z=123):
... print(id(xyz))
... xyz=xyz[:]
... print(id(xyz))
>>> foo()
140619548344576
140619548344704
>>> def foo(xyz=[],u='abc',z=123):
... xyz=xyz[:]
... xyz.append(1)
... print(xyz)
>>> print(foo.__defaults__)
([], 'abc', 123)
>>> foo()
[1]
>>> print(foo.__defaults__)
([], 'abc', 123)
>>> foo()
[1]
>>> print(foo.__defaults__)
([], 'abc', 123)
>>> foo([10,8])
[10, 8, 1]
>>> print(foo.__defaults__)
([], 'abc', 123)
4.2传入不可变类型默认值
如果使用缺省值None就创建一个列表
如果传入一个列表,就修改这个列表
>>> def foo(xyz=None,u='abc',z=123):
... if xyz is None:
... xyz = []
... xyz.append(1)
... print(xyz)
>>> foo()
[1]
>>> print(foo.__defaults__)
(None, 'abc', 123)
>>> foo()
[1]
>>> print(foo.__defaults__)
(None, 'abc', 123)
>>> foo([10,8])
[10, 8, 1]
>>> print(foo.__defaults__)
(None, 'abc', 123)
5.变量名解析规则LEGB
Local,本地作用域、局部作用域的local命名空间。函数调用时创建,调用结束消亡
Enclosing,Python2.2时引入了嵌套函数,实现了闭包,这个就是嵌套函数的外部函数的命名空间
Global,全局作用域,即一个模块空间。模块被import时创建,解释器退出时消亡
Build-in,内置模块的命名空间,生命周期从python解释器启动时创建到解释器退出时消亡。例如:print(open),print和open都是内置的变量
6.函数销毁
6.1全局函数销毁
重新定义同名函数
del语句删除函数对象
程序结束时
>>> def foo(xyz=[],u='abc',z=123):
... xyz.append(1)
... return xyz
...
>>> print(foo(),id(foo),foo.__defaults__)
[1] 2200919120344 ([1], 'abc', 123)
>>> def foo(xyz=[],u='abc',z=123):
... xyz.append(1)
... return xyz
>>> print(foo(),id(foo),foo.__defaults__)
[1] 2200919120208 ([1], 'abc', 123)
>>> del foo
>>> print(foo(),id(foo),foo.__defaults__)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
6.2局部函数销毁
重新在上级作用域定义同名函数
del语句删除函数名称,函数对象的引用计数减1
上级作用域销毁时
>>> def foo(xyz=[],u='abc',z=123):
... xyz.append(1)
... def inner(a=10):
... pass
... print(inner)
... def inner(a=100):
... pirnt(xyz)
... print(inner)
... return inner
>>> bar=foo()
<function foo.<locals>.inner at 0x000001C0BE8A9950>
<function foo.<locals>.inner at 0x000001C0BE8A9A60>
>>> print(id(foo),id(bar),foo.__defaults__,bar.__defaults__)
1927342103000 1927342103136 ([1], 'abc', 123) (100,)
>>> del bar
>>> print(id(foo),id(bar),foo.__defaults__,bar.__defaults__)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined
网友评论