今日学习进度:函数相关
1.收集参数
收集参数,就是说只指定一个参数,然后允许调用函数时传入任意数量的参数。
定义收集参数其实也很简单,即使在形参的前面加上星号(*)来表示:
def myfunc(*arg):
print(f"这个参数有{len(arg)}个")
print(f"第二个参数为{arg[1]}")
myfunc(1, 2, 3, 4, 5)
这个参数有5个
第二个参数为2
如果在收集参数后面还需要指定其它参数,那么在调用函数的时候就应该使用关键参数来指定后面的参数:
>>> def myfunc(*args, a, b):
... print(args, a, b)
...
>>> myfunc(1, 2, 3, a=4, b=5)
(1, 2, 3) 4 5
除了可以将多个参数打包为元组,收集参数其实还可以将参数们打包为字典,做法呢,是使用连续的两个星号(**):
>>> def myfunc(**kwargs):
... print(kwargs)
...
对于这种情况,在传递参数的时候就必须要使用关键字参数了,因为字典的元素都是键值对嘛,所以等号(=)左侧是键,右侧是值:
>>> myfunc(a=1, b=2, c=3)
{'a': 1, 'b': 2, 'c': 3}
混合起来使用就更加灵活了:
>>> def myfunc(a, *b, **c):
... print(a, b, c)
...
>>> myfunc(1, 2, 3, 4, x=5, y=6)
1 (2, 3, 4) {'x': 5, 'y': 6}
2.解包参数
一个星号(*)和两个星号(**)不仅可以用在函数定义的时候,在函数调用的时候也有特殊效果,在形参上使用称之为参数的打包,在实参上的使用,则起到了相反的效果,即解包参数:
>>> args = (1, 2, 3, 4)
>>> def myfunc(a, b, c, d):
... print(a, b, c, d)
...
>>> myfunc(*args)
1 2 3 4
那么两个星号(**)对应的是关键字参数:
>>> args = {'a':1, 'b':2, 'c':3, 'd':4}
>>> myfunc(**args)
1 2 3 4
3.局部作用域
如果一个变量定义的位置是在一个函数里面,那么它的作用域就仅限于函数中,我们将它称为局部变量。
>>> def myfunc():
... x = 520
... print(x)
...
>>> myfunc()
520
变量 x 是在函数 myfunc() 中定义的,所以它的作用域仅限于该函数,如果我们尝试在函数的外部访问这个变量,那么就会报错:
>>> print(x)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
print(x)
NameError: name 'x' is not defined
4.全局作用域
如果是在任何函数的外部去定义一个变量,那么它的作用域就是全局的,我们也将其称为全局变量:
>>> x = 880
>>> def myfunc():
... print(x)
...
>>> myfunc()
880
如果在函数中存在一个跟全局变量同名的局部变量,在函数中,局部变量就会覆盖同名的全局变量的值:
>>> x = 880
>>> def myfunc():
... x = 520
... print(x)
...
>>> myfunc()
520
>>> print(x)
880
注意:代码中两个 x 并非同一个变量,只是由于作用域不同,它们同名但并不同样。
5.global语句
通常我们无法在函数内部修改全局变量的值,除非使用 global 语句破除限制:
>>> x = 880
>>> def myfunc():
... global x
... x = 520
... print(x)
...
>>> myfunc()
520
>>> print(x)
520
6、嵌套函数
>>> def funA():
... x = 520
... def funB():
... x = 880
... print("In funB, x =", x)
... print("In funA, x =", x)
在外部函数 funA() 里面嵌套了一个内部函数 funB(),那么这个内部函数是无法被直接调用的:
>>> funB()
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
funB()
NameError: name 'funB' is not defined
想要调用 funB(),必须得通过 funA():
>>> def funA():
... x = 520
... def funB():
... x = 880
... print("In funB, x =", x)
... funB()
... print("In funA, x =", x)
...
>>> funA()
In funB, x = 880
In funA, x = 520
通常我们无法在嵌套函数的内部修改外部函数变量的值,除非使用 nonlocal 语句破除限制:
>>> def funA():
... x = 520
... def funB():
... nonlocal x
... x = 880
... print("In funB, x =", x)
... funB()
... print("In funA, x =", x)
...
>>> funA()
In funB, x = 880
In funA, x = 880
注:只能更改相邻的外部函数
def funa():
x = 520
def funb():
x = 666
def func():
nonlocal x
x = 880
print("In func, x =", x)
func()
print("in funb, x =", x)
funb()
print("in funa, x =", x)
funa()
In func, x = 880
in funb, x = 880
in funa, x = 520
7.LEGB原则
其中:
- L 是 Local,是局部作用域
- E 是 Enclosed,是嵌套函数的外层函数作用域
- G 是 Global,是全局作用域
- B 是 Build-In,也就是内置作用域
从左至右依次覆盖,B最容易被覆盖
>>> str = "1111"
>>> str(520)
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
str(520)
TypeError: 'str' object is not callable
它本来的功能是将参数转换成字符串类型,但由于我们将它作为变量名赋值了,那么 Python 就把它给覆盖了.