python3.8引入了仅位置参数
def f(positional_argument, /, positional_or_keyword_argument, *, c):
pass
#positional_argument 位置参数
#positional_or_keyword_argument 位置参数和关键字参数
#keyword_argument 关键字参数
位置参数(positional) 和 关键字参数(keyword)
函数定义时确定了五种参数, 但可以简化为两种基本类型, 其余的都可以在此基础上进行引申:
基本类型:
- 位置参数(positional): 传参时前面不带 "变量名=", 顺序不可变, 按顺序赋给相应的局部变量。
- 关键字参数(keyword): 传参时前面加上 "变量名=", 顺序可变, 按名称赋给同名的局部变量。
引申五种参数
-
仅位置参数(positional-only):
在/
之前定义的参数, 传参时不带变量名。这个在 python 3.8 中可以自己定义, 不过内置函数早已经使用这种方法了, 可参考help()
输出的内部函数说明。 -
位置或关键字参数(positional_or_keyword):
在/
后面和*
号前面定义的参数, 即我们自定义函数时最常用的。 传参时可以把它当作位置参数或关键字参数看待, 可以带变量名也可以不带。 这就是我们自定义的函数与内置函数的区别之处了, 这一点最迷惑人。 -
仅关键字参数(keyword-only):
在*
后面定义的参数(或在*args
后面定义, ... 类似于*args
)。 传参时必需带变量名。 -
集合位置参数(var_positional):
即函数定义时采用*args
指定的参数. 我们一般都把它理解为"可变参数", 实际上理解为"集合位置参数"最精确. 传参时不能带变量名.注意: 根据"关键字参数不能在位置参数前面"的原则,
*args
会将之前的参数全部转化为 位置参数, 之后的参数全部转化为 关键字参数 -
集合关键字参数(var_keyword):
即函数定义时采用**args
指定的参数。它可以接受我们传入的任意个数的关键字参数。 传参时必须带变量名。
注意: 传递参数时, "关键字参数不能在位置参数前面", 否则就会报错。 根据这条原则, 那么上述顺序也应该是
parameter
定义的顺序了。
另外根据定义时是否有默认参数, 又可分为两种修饰类型, 它们不影响参数的基本类型定义:
- 必需参数: 定义时没有默认值的参数, 调用时不可省略.
- 可选参数: 定义时有默认值的参数, 调用时可省略.
集合位置参数和集合关键字参数的比较
集合位置参数(VAR_POSITIONAL)
通过一个*
前缀来声明,如果看到一个*xxx
的函数参数声明,那一定是属于VAR_POSITIONAL
类型的,如同语义,这种类型的参数只能通过位置POSITIONAL
传参调用,不支持关键字KEYWORD
传参,在函数内部,VAR_POSITIONAL
类型的参数以一个元组(tuple)显示,有一点需要注意的,VAR_POSITIONAL
类型可以不传任何参数调用也不会报错,而且只允许存在一个。以下是一个简单的例子:
def f(*b):
print(b)
# 不传参数不会报错,参数值是一个空元祖
f() # 结果是 ()
# 可以传入任意个位置参数调用
f(1, 2.0, '3', True) #结果是 (1, 2.0, '3', True)
集合关键字参数(VAR_KEYWORD)
VAR_KEYWORD
类型的参数通过**
前缀来声明。这种类型的参数只能通过关键字KEYWORD
调用,但可以接收任意个关键字参数,甚至是0个参数,在函数内部以一个字典(dict)显示。VAR_KEYWORD
类型的参数只允许有一个,只允许在函数的最后声名。以下是简单的例子:
def f(**d):
print(d)
# 不传参数不会报错,参数值是一个空字典
f() # 结果是 {}
# 可以传入任意个关键字参数调用
f(a=1, b=2.0, c='3', d=True) # 结果是 {'a': 1, 'b': 2.0, 'c': '3', 'd': True}
默认参数
- VAR类型不允许设置默认参数 POSITIONAL_ONLY、POSITIONAL_OR_KEYWORD和KEYWORD_ONLY可以自定义默认参数,而VAR_POSITIONAL和VAR_KEYWORD不允许自定义默认参数的,因为VAR_POSITIONAL的默认参数是tuple()空元祖,而VAR_KEYWORD的默认参数是dict()空字典。
- 默认参数的位置 POSITIONAL_OR_KEYWORD类型的默认参数一定要放在后面,否则会报错,KEYWORD_ONLY虽然没有强制要求,因为都是用关键字传参,谁先谁后都无所谓,但最好还是尽可能地放在后面吧。
- 默认参数绝对不能设置为可变类型(比如list, dict, set),如果你在函数内改变了默认参数,下次再调用时它就不再是默认值了。
/
和*
在参数中的使用的语法
def name(positional_or_keyword_parameters, *, keyword_only_parameters):
def name(positional_only_parameters, /, positional_or_keyword_parameters,*, keyword_only_parameters):
- 在
/
左边的参数被视为仅位置参数 - 如果函数定义中
/
没有指定,则函数中所有参数都不是仅位置参数 - 仅位置参数的可选值的逻辑与位置-关键字参数的逻辑相同。
- 一旦使用默认值指定了仅位置参数,下面的仅位置参数和位置-关键字参数也需要具有默认值。
- 没有默认值的仅位置参数在调用的时候必需给值。
因此下列属于有效函数定义:
def name(p1, p2, /, p_or_kw, *, kw):
def name(p1, p2=None, /, p_or_kw=None, *, kw):
def name(p1, p2=None, /, *, kw):
def name(p1, p2=None, /):
def name(p1, p2, /, p_or_kw):
def name(p1, p2, /):
def name(p_or_kw, *, kw):
def name(*, kw):
下面属于无效定义
def name(p1, p2=None, /, p_or_kw, *, kw):
def name(p1=None, p2, /, p_or_kw=None, *, kw):
def name(p1=None, p2, /):
函数参数使用举例说明
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
# a, b 是 仅位置参数;c, d 是 位置或关键字参数; e, f 是 仅关键字参数;
下面是合法调用:
f(10, 20, 30, d=40, e=50, f=60)
非法调用:
f(10, b=20, c=30, d=40, e=50, f=60) # b cannot be a keyword argument
f(10, 20, 30, 40, 50, f=60) # e must be a keyword argument
可选的位置参数 (python 3.8)
def f(a=2, /): pass
f() # 允许调用方式,参数是可选的
f(1) # 允许调用方式,参数是位置参数
f(a=1) # 错误的调用方式,参数是仅位置参数
必需的位置参数 (python 3.8)
def f(a, /): pass
f() #错误,需要参数
f(1) # 正确
f(a=1) # 错误的调用方式,参数是仅位置参数
可选的关键字参数
def f(*, a=1): pass
f() # 正确
f(1) # 错误,参数是仅关键字参数
f(a=1) # 正确
必需的关键字参数
def f(*, a): pass
f() # 错误,需要传入参数
f(1) # 错误,仅关键字参数
f(a=1) # 正确
可选的位置和关键字参数
def f(a=1): pass
f() # 正确
f(1) # 正确
f(a=1) # 正确
必需的位置和关键字参数
def f(a): pass
f() # 错误,需要传入参数
f(1) # 正确
f(a=1) # 正确
结论:一个参数可以是可选的,也可以是必需的,但不能同时包含这两个参数。它也可以是位置的,关键字的,或者两者同时存在。
关于parameter
和 argument
的理解
parameter
为函数定义时的叫法, 它指明了函数可以接受的argument
类型.
argument
为函数调用时的叫法, 可以理解为实参, 即传入的值