关于函数实参的基础知识,请参阅函数概念。
形参名和变量名一样,必须以字母或下划线开头,并且可以包含字母、下划线或数字。 形参名不应包含空格或标点符号。
位置实参是按与绑定它们的形参相同的顺序传给函数的值。 位置实参也可以选择通过形参名来传递:
def concat(greeting, name):
return f"{greeting}{name}"
# Passing data to the function by position.
print(concat("Hello, ", "Lilly"))
#-> Hello, Lilly
# Passing data to the function using the parameter name.
print(concat(name="Glenn", greeting="Hello, "))
#-> Hello, Glenn
第一次调用 concat 时,实参是按位置传递的。
第二次调用 concat 时,实参是按名字传递的,因此可以改变它们的位置。
注意,位置实参不能跟在按名字传递的实参之后(也称为关键字实参。不要与可变位置形参或 **kwargs 混淆)。
这组实参:
print(concat(greeting="Hello, ", "Gregor"))
会导致这个错误:
SyntaxError: positional argument follows keyword argument
如果要求函数调用只能使用仅位置实参,可以在形参列表中使用 / 运算符:
# Parameters showing a position-only operator.
def concat(greeting, name, /):
return f"{greeting}{name}"
print(concat("Hello, ", "Ginnie"))
#-> Hello, Ginnie
# Call to the function using keyword arguments.
print(concat(name="Franklin", greeting="Hello, "))
Traceback (most recent call last):
print(concat(name="Franklin", greeting="Hello, "))
TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting, name'
关键字实参在调用函数时使用形参名。 它们也可以选择按位置来引用:
def concat(greeting, name):
return f"{greeting}{name}"
# Function call using parameter names as argument keywords.
print(concat(name="Eliza", greeting="Hello, "))
#-> Hello, Eliza
# Function call with positional data as arguments.
print(concat("Hello, ", "Tim"))
#-> Hello, Tim
如果要求函数调用只能使用仅关键字实参,可以在形参列表中使用 * 运算符:
# Function definition requiring keyword-only arguments.
def concat(*, greeting, name):
return f"{greeting}{name}"
# Keyword arguments can be in an arbitrary order.
print(concat(name="Kimmie", greeting="Hello, "))
#-> Hello, Kimmie
# Calling the function with positional data raises an error.
print(concat("Hello, ", "Coleen"))
Traceback (most recent call last):
print(concat("Hello, ", "Coleen"))
TypeError: concat() takes 0 positional arguments but 2 were given
可以在形参列表中为一个或多个实参提供默认值。 这样在需要时就可以用_更少_的实参来调用函数。 通过用新的实参值调用函数,可以覆盖默认值:
# Function with default argument values.
def concat(greeting, name="you", punctuation="!"):
return f"{greeting}, {name}{punctuation}"
print(concat("Hello"))
#-> Hello, you!
# Overriding the default values
print(concat("Hello", name="Polly", punctuation="."))
#-> Hello, Polly.
如果形参定义中既没有使用 / 也没有使用 * 运算符,实参就既可以是位置实参,也可以是关键字实参。
另一种做法是,把既可位置也可关键字的实参放在左边的仅位置形参和右边的仅关键字形参之间:
# Position-only argument followed by position-or-keyword, followed by keyword-only.
def concat(greeting, /, name, *, ending):
return f"{greeting}{name}{ending}"
print(concat("Hello, ", "Mark", ending="!"))
#-> Hello, Mark!
print(concat("Hello, ", name="Rachel", ending="!"))
#-> Hello, Rachel!
print(concat(greeting="Hello, ", name="JoJo", ending="!"))
Traceback (most recent call last):
print(concat(greeting="Hello, ", name="JoJo", ending="!"))
TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting'
*args代码示例中经常会出现类似下面这样的函数定义:
def my_function(*args, **kwargs):
# code snipped
*args 是一个由两部分组成的名字,表示一个包含任意数量、彼此独立的位置实参的 tuple,也称为 variadic argument。
args 是给这个实参 tuple 起的名字,但它也可以是任何其他合法的 Python 名字,比如 my_args、arguments 等。
* 是把这一组彼此独立的实参转换成 tuple 的运算符。
由于 tuple 可以被迭代,args 可以传给任何接受可迭代对象的其他函数。
虽然 *args 常与 **kwargs 一起出现,但并不是必须如此:
def add(*args):
# args is passed to the sum function, which iterates over it.
return sum(args)
print(add(1, 2, 3))
#-> 6
如果 *args 跟在一个或多个位置实参之后,那么 *args 就是位置实参之后剩下的部分:
def add(first, *args):
# first will be 1, leaving the values 2 and 3 in *args
return first + sum(args)
print(add(1, 2, 3))
#-> 6
如果在 *args 之后定义了一个或多个默认实参,它们与 *args 中的值是分开的:
def add(first, *args, last=0):
return first + sum(args) + last
print(add(1, 2, 3))
#-> 6
print(add(1, 2, 3, last=4))
#-> 10
# This uses the unpacking operator * to separate the list elements into positional arguments.
# It does not have the same behavior as the * (packing) in *args.
print(add(*[1, 2, 3]))
#-> 6
注意,当实参本身已经在一个 iterable 里(比如 tuple 或 list)时,在把它传给接受任意数量独立实参的函数之前,需要先解包。
这可以通过 * 来完成,它就是解包运算符。
在这个上下文中,* 把容器_解包_成一个个独立的元素,然后由 *args 转换成 tuple。
如果只有位置实参,解包操作得到的实参数量必须与定义的形参数量相同。
如果不解包传给 add 的列表,程序就会报错:
def add(first, *args, last=0):
return first + sum(args) + last
print(add([1, 2, 3]))
Traceback (most recent call last):
print(add([1, 2, 3]))
return first + sum(args) + last
TypeError: can only concatenate list (not "int") to list
**kwargs**kwargs 是一个由两部分组成的名字,表示任意数量的、彼此独立的键值对实参。
kwargs 是这组实参的名字,也可以是任何其他名字,比如 my_args、arguments 等。
** 把这组具名实参转换成一个由 {argument name: argument value} 键值对组成的 dictionary。
由于字典可以被迭代,kwargs 可以传给任何接受可迭代对象的其他函数。
虽然 **kwargs 常与 *args 一起出现,但并不是必须如此:
def add(**kwargs):
return sum(kwargs.values())
print(add(one=1, two=2, three=3))
#-> 6
注意这里调用了 dict.values() 方法来遍历 kwargs 字典的 values。
遍历字典时,默认遍历的是 keys,所以需要显式指定 dict.values():
def concat(**kwargs):
# Join concatenates the tuples from `kwargs.items()`
return " ".join((str(item) for item in kwargs.items()))
print(concat(one=1, two=2, three=3))
#-> ('one', 1) ('two', 2) ('three', 3)