前言

Python 的函数参数传递相对于 C++来说更加灵活,并且使用也很方便,这里做下简单的总结。

正文

实参和形参

实参:在调用函数时提供的函数参数称为实参。
形参:定义函数时,函数中的变量成为形参。

传递实参

位置实参

这个没什么好说,和其他编程语言用法一样,直接按照位置顺序传递即可。示例如下:实参和形参的位置一一对应,所以参数的顺序很重要。

def fun(name,age):
print("name = ",name,"age = ",age)

fun("Jack",28)

关键字实参

这种用法就和其他编程语言有点区别了,所谓的关键实参是传递给函数的名字-值对。直接在实参中将名称和值对应起来,因此在向函数传递实参时不会混淆,这种用法无需考虑顺序,还清楚的指出了函数调用中各个值的用途,示例如下:

def fun(name,age):
print("name = ",name,"age = ",age)

fun(name="Jack",age=28)

也可以写成

fun(age=28,name="Jack")

其结果都是一样的。

默认参数

这种用法也似曾相识,编写函数时,可给每个形参指定默认值。而在调用函数时 如果如果没有传入实参,那么函数就会默认使用形参值。使用默认值可简化函数调用,还清楚地指出函数的典型用法。
示例如下:

def fun(name,age=20):
print("name = ",name,"age = ",age)

fun("Jack")

这里的函数调用也可以写成:

fun("Jack",28)

当然,还可以按照关键字实参的方式来调用:

fun(name="Jack")

需要注意的是:使用默认参数时,在形参列表中必须先列出没有默认值的参数,再列出有默认值的形参,这让 Python 依然能够正确地解读位置实参。
打个比方, 上面的函数定义不能写成如下形式:

def fun(name="mark",age):
print("name = ",name,"age = ",age)

写成这样会报错:

SyntaxError: non-default argument follows default

这和 C++的函数默认参数用法也是一样的。

传递列表

可以直接向函数传递列表,这种列表包含的可能是名字,数字或更复杂的对象(如字典),将列表传递给函数后,函数就能直接访问其内容。

def fun(names):
for name in names:
print("name = ",name)

names=["Jack","Eric","John"]
fun(names)

输出:

name =  Jack
name = Eric
name = John

函数中修改列表

当向函数中传递列表时,可以直接在函数中对列表进行修改,示例如下:

def fun(names):
for name in names:
print("name = ",name)
names[0]="Sanny"

names=["Jack","Eric","John"]
print("before names = ",names)
fun(names)
print("after names = ",names)

输出:

before names =  ['Jack', 'Eric', 'John']
name = Jack
name = Eric
name = John
after names = ['Sanny', 'Eric', 'John']

可以看到,这里的列表已经发生了变化。

禁止函数修改列表

如果要不想要函数中修改列表内容怎么办呢?可以在传递的时候将列表的副本传递给函数,其实相当于另外开辟了空间,将列表值赋值给新地址后再传递。示例如下:

def fun(names):
for name in names:
print("name = ",name)
names[0]="Sanny"

names=["Jack","Eric","John"]
print("before names = ",names)
fun(names[:])
print("after names = ",names)

这里只是将函数调用方式写成:fun(names[:])
输出如下:

before names =  ['Jack', 'Eric', 'John']
name = Jack
name = Eric
name = John
after names = ['Jack', 'Eric', 'John']

可以看到列表内容并没有发生变化。

注意:虽然想函数传递列表的副本可保留原始列表的内容,但除非有充分的理由需要传递副本,否则还是应该讲原始列表传递给函数,因为让函数使用现成列表可避免花时间和内存创建副本,从而提高效率在处理大型列表时尤其如此。

传递任意参数的实参

有时候,你预先不知道函数需要接受多少个实参,好在Python 允许函数从调用语句中手机任意数量的实参。
示例如下:

def fun(*names):
print("names = ",names)

fun("Jack")
fun("Jack","Eric","John")

输出如下:

names =  ('Jack',)
names = ('Jack', 'Eric', 'John')

可以看到这里函数可以传递任意多的实参。
形参名*names 中的星号让 Python 创建一个名为 names 的空元组,并将收到的所有值都封装到这个元组中,即便函数只传递了一个值也是如此。

然而,还可以给函数传递任意多的列表参数,并且可以直接在函数中对列表参数进行修改。示例如下:

def fun(*names):
print("names = ",names)
names[0][0] = "aaa"


names=["Jack","Eric","John"]
names_2=["mark","kiko"]

fun(names,names_2)
print(" after names = ",names)

输出如下:

names =  (['Jack', 'Eric', 'John'], ['mark', 'kiko'])
after names = ['aaa', 'Eric', 'John']

这里的第一个列表数据已经在函数中被修改了。

结合使用位置实参和任意数量实参

如果要让函数接收不同类型的实参,那么必须在函数定义中将接纳任意数量实参的形参放在最后。Python 先匹配位置实参和关键字实参,再将剩下的实参都收集到最后一个形参中。
示例如下:

def fun(num,*names):
print("num = ",num,"names = ",names)

names=["Jack","Eric","John"]
names_2=["mark","kiko"]

fun(5,names,names_2)

输出:

num =  5 names =  (['Jack', 'Eric', 'John'], ['mark', 'kiko'])

使用任意数量的关键字实参

除了位置实参和任意数实参结合使用,关键字实参也可以和任意数实参集合使用。
有时候,需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息,这种情况下,可将函数编写成能够接受任意数量的键值对—调用语句提供了多少就接受多少。

def fun(first,last,**user_info):
profile={}
profile["first"]=first
profile["last"]=last
for key,value in user_info.items():
profile[key] = value
print("profile = ",profile)

fun("aaa","bbb",name="hello",field = "world")

输出:

profile =  {'first': 'aaa', 'last': 'bbb', 'name': 'hello', 'field': 'world'}

这里的形参**user_info中的两个星号让 Python 创建一个名为user_info的空字典,并将收到的所有键值对都封装到这个字典中。在这个字典中,可以像访问其它字典那样访问user_info中的键值对。

最后

可以看到,Python 的这种函数调用非常灵活,尝试不同的调用会发现可以扩展很多其他的用法,对实际项目中有很大的帮助。