python系列17讲 - 函数参数如args、kwargs等一次搞明白!
❝
介绍Python 实参和参数的区别,如关键字参数、默认参数、可变参数、本地及全局参数等。
在这篇文章中我们将详细讲讲函数参数相关知识。
我们将学习以下内容:
实参和参数的区别位置和关键字参数默认参数可变长度参数(*args 和 **kwargs)容器解包成函数参数本地与全局参数参数传递(通过值还是通过引用?)实参和参数
参数是定义函数时在括号内定义或使用的变量实参是调用函数时为这些参数传递的值代码:
def print_name(name): # name 是参数print(name)
print_name(Alex) # Alex 是实参结果:
Alex
位置和关键字参数
我们可以将参数作为位置参数或关键字参数传递。
关键字参数的一些好处可以是:
我们可以通过它们的名字来调用参数,以使其更清楚它们代表什么我们可以重新排列参数位置,使它们最易读代码:
def foo(a, b, c):print(a, b, c)
# 位置参数foo(1, 2, 3)
# 关键字实参foo(a=1, b=2, c=3)
foo(c=3, b=2, a=1) # 可以打乱顺序# 混合使用foo(1, b=2, c=3)
# 混合使用时,关键字实参必须出现在位置实参之前# foo(1, b=2, 3) # ❌# foo(1, b=2, a=3) # ❌ 冲突结果:
1 2 3
1 2 3
1 2 3
1 2 3
默认参数
函数可以有带有预定义值的默认参数。该参数可以省略,然后将默认值传递给函数,或者该参数可以与不同的值一起使用。请注意,默认参数必须定义在非默认参数之后。
代码:
def foo(a, b, c, d=4):print(a, b, c, d)
foo(1, 2, 3, 4)
foo(1, b=2, c=3, d=100)
# ❌ 不允许默认参数在非默认参数之前# def foo(a, b=2, c, d=4):# print(a, b, c, d)结果:
1 2 3 4
1 2 3 100
可变参数(*args 和 **kwargs)
如果用一个星号 (*) 标记参数,则可以将任意数量的位置参数传递给函数(通常称为 *args)。如果用两个星号 (**) 标记参数,则可以将任意数量的关键字参数传递给此函数(通常称为 **kwargs)。代码:
def foo(a, b, *args, **kwargs):print(a, b)
for arg inargs:
print(arg)
for kwarg inkwargs:
print(kwarg, kwargs[kwarg])
# 1,2:位置参数,3,4,5:args参数,6,7:kwargs参数foo(1, 2, 3, 4, 5, six=6, seven=7)
print()
# *args和**kwargs是可变的,也可以省略。foo(1, 2, three=3)
结果:
1 2
3
4
5
six 6
seven 7
1 2
three 3
强制关键字参数
有时您希望一些参数必须是关键字参数,不能是位置参数。
您可以通过两种方法实现:
在函数参数列表中写入*,则之后的所有参数都必须作为关键字参数传递。
在可变参数后面定义参数一定是关键字参数。
代码:
# ✅方法一: 用*号分割def foo(a, b, *, c, d):print(a, b, c, d)
foo(1, 2, c=3, d=4)
# foo(1, 2, 3, 4) # ❌:c,d是不可省略的关键字参数# ✅方法二: 在*args或**kwargs之后定义def foo(*args, last): for arg inargs:
print(arg)
print(last)
foo(8, 9, 10, last=50)
结果:
1 2 3 4
8
9
10
50
参数解包
如果列表的长度与函数参数的数量相匹配,则可以将列表或元组解压缩为带有一个星号 (*) 的参数。同理,字典可以解压成带有两个星号(**)的参数,长度和键与函数参数匹配。代码:
def foo(a, b, c):print(a, b, c)
my_list = [4, 5, 6] # 列表或者元组foo(*my_list) # 参数拆包my_dict = {"a": 1, "b": 2, "c": 3} # 字典foo(**my_dict)
# my_dict = {a: 1, b: 2, d: 3} # ❌ 关键字参数不匹配结果:
4 5 6
1 2 3
局部变量和全局变量
全局变量可以在函数体中访问,但要修改它们。我们首先必须使用global声明,以便改变全局变量。
代码:
def foo1(): print("打印全局变量:", number) # number函数内没有定义,生成一个局部变量,值和全局变量一样 # number = 1 # ❌ 不允许修改未声明的全局变量def foo2(): global number # 声明全局变量,修改才有效 number = 3 print("打印函数内全局变量:", number)
number = 0print("打印全局变量:", number)
foo1()
print("执行完foo1函数后,打印全局变量:", number)
foo2() # 修改全局变量print("执行完foo2函数后,打印全局变量:", number)
结果:
打印全局变量:0
打印全局变量:0
执行完foo1函数后,打印全局变量:0
打印函数内全局变量:3
执行完foo2函数后,打印全局变量:3
如果我们不写 global var_name 并为与全局变量同名的变量分配一个新值, 这将在函数内创建一个局部变量。全局变量保持不变。
参数传递
Python 使用一种称为“Call-by-Object”或“Call-by-Object-Reference”的机制。必须考虑以下规则:
传入的参数其实是一个对象的引用(但是引用是按值传递的)可变和不可变数据类型之间的区别这意味着:
可变对象(例如列表、字典)可以在方法内更改。但是如果在方法中重新绑定引用,外部引用仍然会指向原来的对象。不可变对象(例如 int、string)不能在方法内更改。但是可变对象中包含的不可变对象可以在方法中重新分配。1. 不可变对象(例如 int、string)不能在方法内更改
代码:
def foo(x): x = 5 # x是不可变对象。var = 10print(f"函数执行前:var={var}")
foo(var) # 执行foo函数,参数var会被更改为5print(f"函数执行后:var={var}")
结果:
函数执行前:var=10
函数执行后:var=10
2. 可变对象(例如列表、字典)可以在方法内更改。
代码:
def foo(列表): 列表.append(4)
A = [1, 2, 3]
print(f函数执行前: A = {A})
foo(A)
print(f函数执行后: A = {A})
结果:
函数执行前: A = [1, 2, 3]
函数执行后: A = [1, 2, 3, 4]
3. 可变对象中包含的不可变对象可以在方法中重新分配
代码:
def foo(a_list): a_list[0] = -100 a_list[2] = "Paul"my_list = [1, 2, "Max"]
print(f函数执行前: my_list = {my_list})
foo(my_list)
print(f函数执行后: my_list = {my_list})
结果:
函数执行前: my_list = [1, 2, Max]
函数执行后: my_list = [-100, 2, Paul]
4. 参数传递的是对象的引用
❝函数内,重新绑定引用,外部引用仍然会指向原来的对象。
代码:
def foo(a_list): a_list = [50, 60, 70] # 重新定义了a_list,为局部变量。 a_list.append(50)
my_list = [1, 2, 3]
print(f函数执行前: my_list = {my_list})
foo(my_list)
print(f函数执行后: my_list = {my_list})
结果:
函数执行前: my_list = [1, 2, 3]
函数执行后: my_list = [1, 2, 3]
❝小心使用可变类型的 += 和 = 操作。+=不会重新定义变量,而=会重新定义变量。也就是说,+=是对变量进行追加,而=是重新定义变量。
代码:
def foo(a_list): a_list += [4, 5] #⚠️ 改变了传入的参数,不是局部变量。def bar(a_list): a_list = a_list + [4, 5] #⚠️ 重新定义了传入的参数,是局部变量。my_list = [1, 2, 3]
print(ffoo函数执行前: my_list = {my_list})
foo(my_list)
print(ffoo函数执行后: my_list = {my_list})
my_list = [1, 2, 3]
print(fbar函数执行前: my_list = {my_list})
bar(my_list)
print(fbar函数执行后: my_list = {my_list})
结果:
foo函数执行前: my_list = [1, 2, 3]
foo函数执行后: my_list = [1, 2, 3, 4, 5]
bar函数执行前: my_list = [1, 2, 3]
bar函数执行后: my_list = [1, 2, 3]
PythonTip出品,Happy coding!