Python中的函数参数类型

位置参数

又叫顺序参数,在未指定参数名时,必须严格按照顺序来传递参数!(很简单)


默认参数

在函数定义的时候,如果给某个参数提供一个默认值,这个参数就变成了默认参数,不再是位置参数了。在调用函数时,既可以给默认参数传递一个自定义的值,也可以使用默认的值

默认参数必须定义在位置参数的后面

重点,默认参数默认值为 None 的情况

参考:Python 函数动态参数值设为 None 的意义

先看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 测试
def func(a=[]):
a.append("A")
return a

print(func())
print(func())
print(func())

# 输出
['A']
['A', 'A']
['A', 'A', 'A']

# 而不是
['A']
['A']
['A']

为什么会这样?

因为 Python 函数体在被读入内存的时候,默认参数 a 指向的空列表对象就会被创建,并放在内存里了。因为默认参数 a 本身也是一个变量,保存了指向对象 [] 的地址。每次调用该函数,就往指向 a 的列表里添加一个 Aa 是没有变的,它始终保存着指向列表的地址,变的是列表内的数据!详细测试请移步博客:刘江的博客:默认参数设置为 None 的情况

若想要输出:

1
2
3
['A']
['A']
['A']

则代码可以改为:

1
2
3
4
5
6
7
8
9
10
def func(a=None):
# 注意下面的if语句
if a is None:
a = []
a.append("A")
return a

print(func())
print(func())
print(func())

动态参数

传入参数的个数是动态的(即数量不固定的),可以是 0 个、 1 个、 2 个、 更多个 甚至 任意个 ,在不需要的时候,完全可以将动态参数当作空气而忽略它的存在。 Python 中的动态参数有两种,分别是 *args**kwargs ,这里的关键是一个星号 * 和两个星号 ** 的区别,而不是 argskwargs 在名字上的区别,实际上可以使用 *any**whatever 的任何命名方式,但就如 self 一样,使用 *args**kwagrs 已经形成了一种不成文的规定,我们应当(最好)遵守它

  • *args 的作用

将传入的实际参数转换(打包)成一个元组后再传递给形式参数(一个列表当作一个参数)

1
2
3
4
5
6
7
8
9
10
11
12
# 测试
def func(*args):
print(args)

func(1, 2, 3)
func([1, 2, 3])
func(1, 2, 3, [1, 2, 3])

# 输出
(1, 2, 3)
([1, 2, 3],)
(1, 2, 3, [1, 2, 3])

可以很清晰地看到, args 的值是一个元组。接下来看看其中 * 的作用:

1
2
3
4
5
6
7
8
9
10
11
12
# 测试
def func(*args):
print(*args)

func(1, 2, 3)
func([1, 2, 3])
func(1, 2, 3, [1, 2, 3])

# 输出
1 2 3
[1, 2, 3]
1 2 3 [1, 2, 3]

至此,已经发现, *args 作为形参,其中起作用的就是 * 号(就像前面说的, args 可以换为任何其它字符串,但我们最好遵守这种命名习惯),它起到打包和解包的作用

既然 * 可以起到解包的作用,那么对于可迭代对象(如字符串、元组、列表)自然便可以起到拆分的效果(但只能拆分 1 层)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 测试
print(*'abc')
print(*(1, 2, 3))
print(*[1, 2, 3])
print(*(1, 2, 3, [1, 2, 3]))
print(*[1, 2, 3, (1, 2, 3)])

# 输出
a b c
1 2 3
1 2 3
1 2 3 [1, 2, 3]
1 2 3 (1, 2, 3)
  • **kwargs 的作用

将传入的实际参数(键-值对参数)转换(打包)成一个字典后再传递给形式参数

1
2
3
4
5
6
7
8
9
10
11
12
13
# 测试
def func(**kwargs):
print(kwargs)
print(**kwargs)

func(a=1, b=2, c=3)
func(a=1, b=2, c=[1, 2])
func(a=1, b=2, c=(1, 2))

# 输出
{'a': 1, 'b': 2, 'c': 3}
{'a': 1, 'b': 2, 'c': [1, 2]}
{'a': 1, 'b': 2, 'c': (1, 2)}

同样地,查看 ** 的功能(几乎同 * 理,故以下只进行简单测试):

1
2
3
4
5
6
7
8
# 测试
def func(A, B, C):
print(A, B, C)

func(**{'A': 1, 'B': 2, 'C': 3})

# 输出
1 2 3

注意:直接使用 A, B, C = **{'A': 1, 'B': 2, 'C': 3}print(**{'A': 1, 'B': 2, 'C': 3}) 是错误的!

*** 只有在传参时才起作用,即使 print(*(1, 2, 3)) 有效,但 a, b, c = *(1, 2, 3) 是无效的!

  • 混合参数、万能参数 *args + **kwargs 的作用

要注意一点, *args 必须写在 **kwargs 的前面

当位置参数、默认参数、动态参数混合使用时,要注意默认参数是否被动态参数赋值!

详见刘江的博客教程:混合使用时默认参数被覆盖的问题


参考文章(很实用)

刘江的博客教程: Python 教程

Python 动态参数的使用