Jean's Blog

一个专注软件测试开发技术的个人博客

0%

Python函数的5类参数使用详解

Python五类参数:

  • 位置参数
  • 关键字参数
  • 默认参数
  • 可变位置参数
  • 可变关键字参数

五类参数

定义函数f,只有一个参数a,a既可能为位置参数,也可能为关键字参数,这取决于调用函数f的传参。

1
2
def f(a):
print(f'a:{a}')

位置参数

如下调用函数f,a就是位置参数,英文positional argument,并且a被赋值为1:

1
2
>>> f(1)
a:1

关键字参数

下面调用函数f,a就是关键字参数,英文keyword argument,a同样被赋值为1:

1
2
>>> f(a=1)
a:1

默认参数

函数f如下,有一个默认值0,那么,a就是默认参数,且默认值为0

1
2
3
>>> def f(a=0):
... print(f'a:{a}')
...

对于以上函数,就有两种不同的调用方式:

1.按照a的默认值调用

1
2
>>> f()
a:0

2.默认参数a值为1

1
2
>>> f(1)
a:1

可变位置参数和可变关键字参数

f函数定义如下:

1
2
def f(a, *b, **c):
print(f'a:{a}, b:{b}, c:{c}')

函数f的参数稍显复杂,但也是最常用的函数参数定义结构。

  • 出现一个星号的参数b,这是可变位置参数
  • 带两个星号的参数c,这是可变关键字参数

可变表示函数被赋值的变量个数是变化的。

如下调用函数f:

1
2
>>> f(1,2,3,w=4,h=5)
a:1, b:(2, 3), c:{'w': 4, 'h': 5}

参数b被传递2个值,参数c也被传递2个值。可变位置参数b被解析为元组,可变关键字参数c被解析为字典。

接下来在调用函数f:

1
2
>>> f(1,2,w=4)
a:1, b:(2,), c:{'w': 4}

参数b被传递1个值,参数c被传递1个值。

所以,称带星号的变量为可变的。

查看参数

借助Python的inspect模块查看参数的类型。

  1. 首先,导入inspect模块

    1
    >>> from inspect import signature
  1. 函数f定义,如下:

    1
    2
    3
    >>> def f(a, *b):
    ... print(f'a:{a}, b:{b}')
    ...
  1. 查看参数类型

    1
    2
    3
    4
    5
    >>> for name, val in signature(f).parameters.items():
    ... print(name,val.kind)
    ...
    a POSITIONAL_OR_KEYWORD
    b VAR_POSITIONAL

看到,参数a既可能是位置参数,也可能是关键字参数。参数b为可变位置参数。

函数f定义如下:

1
2
3
>>> def f(*, a, **b):
... print(f'a:{a}, b:{b}')
...

查看参数类型

1
2
3
4
5
>>> for name, val in signature(f).parameters.items():
... print(name,val.kind)
...
a KEYWORD_ONLY
b VAR_KEYWORD

看到参数a只可能为KEYWORD_ONLY关键字参数。因为参数a前面有个星号,星号后面的参数a只可能是关键字参数,而不可能是位置参数。

如下,不能这样调用函数f:

1
2
3
4
>>> f(1, b=2, c=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given

传递规则

Python强大多变,原因之一在于函数参数的多样化。下面,介绍Python中五类参数的传递赋值规则。

要求开发者遵守更多的约束规则。如果不了解这些规则,函数调用时,可能会出现各种各样的调用异常。

常见的有以下六类:

序号 异常说明 描述
1 SyntaxError: positional argument follows keyword argument 位置参数位于关键字参数后面
2 TypeError: f() missing 1 required keyword-only argument: ‘b’ 必须传递的关键字参数缺失
3 SyntaxError: keyword argument repeated 关键字参数重复
4 TypeError: f() missing 1 required positional argument: ‘b’ 必须传递的位置参数缺失
5 TypeError: f() got an unexpected keyword argument ‘a’ 没有这个关键字参数
6 TypeError: f() takes 0 positional arguments but 1 was given 不需要位置参数但却传递 1 个

下面总结,6个主要的参数使用规则:

规则1:不带默认的位置参数缺一不可

函数调用时,根据函数定义的参数位置来传递参数,是最常见的参数类型。

1
2
3
4
5
>>> def f(a):
... return a
...
>>> f(1) # 这样传递值,参数a为位置参数
1

如下带有两个参数,传值时必须两个都赋值。

1
2
3
4
5
6
7
>>> def f(a, b):
... pass
...
>>> f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() missing 1 required positional argument: 'b'

规则2:关键字参数必须在位置参数右边

在调用f时,通过键—值方式为函数形参传值。

1
2
3
4
5
>>> def f(a):
... print(f'a:{a}')
...
>>> f(a=1)
a:1

参数a变为关键字参数。

但是,下面调用,就会出现:位置参数位于关键字参数后面的异常。

1
2
3
4
5
6
7
8
>>> def f(a, b):
... pass
...
>>> f(a=1, 20)
File "<stdin>", line 1
f(a=1, 20)
^
SyntaxError: positional argument follows keyword argument

如下调用是可以的

1
2
>>> f(20, b=1)
>>>

规则3:对同一个形参不能重复传值

下面方式调用也是会报异常

1
2
3
4
5
6
>>> def f(a, **b):
... pass
...
>>> f(1, width=20, width=30)
File "<stdin>", line 1
SyntaxError: keyword argument repeated: width

规则4:默认参数的定义应该在位置形参右面

在定义函数时,可以为形参提供默认值。

对于有默认值的形参,调用函数时,如果为该参数传值,则使用传入的值,否则使用默认值。

如下b是默认参数

1
2
3
>>> def f(a, b=1):
... print(f'a:{a}, b:{b}')
...

默认参数通过应该定义成不可变类型。

规则5:可变位置参数不能传入关键字参数

如下定义的参数a为可变位置参数:

1
2
3
>>> def f(*a):
... print(a)
...

调用方法:

1
2
3
4
>>> f(1)
(1,)
>>> f(1,2,3)
(1, 2, 3)

但是,不能这么调用:

1
2
3
4
>>> f(a=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() got an unexpected keyword argument 'a'

规则6:可变关键字参数不能传入位置参数

如下,a是可变关键字参数:

1
2
3
>>> def f(**a):
... print(a)
...

调用方法

1
2
3
4
>>> f(a=1)
{'a': 1}
>>> f(a=1, b=2, width=3)
{'a': 1, 'b': 2, 'width': 3}

但是,不能这么调用:

1
2
3
4
>>> f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given