Python-函数定义详解
函数定义支持可变数量的参数。下面列出三种可以组合使用的形式。
1 默认值参数
为参数指定默认值,在调用函数时可以使用比定义时更少的参数。
def student_info(name, sex, age=18, score=100):
if sex == 'male':
print(f"{name} is {age} years old, his score is {score}")
else:
print(f"{name} is {age} years old, her score is {score}")
该函数接收两个必选参数name
和 sex
,两个可选参数 age
,score
。该函数可用下列方式调用
- 只传入必选参数
student_info('ZhangSan', 'male')
# zhangSan is 18 years old, his score is 100.
- 传入一个可选参数
student_info('LiSi', 'female', 17)
# LiSi is 17 years old, her score is 100.
- 传入所有实参
student_info('XiaoHong', 'female', 17, 99)
# XiaoHong is 17 years old, her score is 99.
2 关键字参数
kwarg=value
形式的 关键字参数 也可以用于调用函数。
def student_info(name, sex, age=18, score=100):
if sex == 'male':
print(f"{name} is {age} years old, his score is {score}")
else:
print(f"{name} is {age} years old, her score is {score}")
使用了默认值参数的函数都可以通过kwarg=value
形式的关键字参数调用函数。该函数可以通过下列方式调用。
student_info('ZhangSan', 'male')
student_info('ZhangSan', 'male', age=17)
student_info('ZhangSan', 'male', score=99)
student_info('ZhangSan', 'male', age=19, score=98)
student_info('ZhangSan', 'male', score=95, age=20)
从上面调用函数的方式可以看出:
- 关键字参数的顺序可以和定义的顺序不一致
- 关键字参数必须放在位置参数之后
如果你想打乱所有参数的顺序,包括位置参数,那么你需要对所有参数使用kwarg=value
的方式来传入实参。如:
student_info(score=100, age=19, name='ZhangSan', sex='malae')
不能在一次调用中多次对同一个参数进行赋值(即使多次赋值都是同一个值):
student_info('ZhangSan', 'male', name='ZhangSan')
这样是不被允许的。
**name
当最后一个形参为**name
形式时,接收一个字典,该字典包含与函数中已定义形参之外的所有关键字参数。**name
可以和*name
形参组合使用(注意:*name
必须在**name
前面),*name
接收一个元组,该元组包含形参列表之外的位置参数。
其中**name
接收的字典中数据的顺序和调用函数时实参传入的顺序一致。
3 特殊参数
默认情况下,参数可以按位置或显式关键字传递给 Python 函数。为了让代码易读、高效,最好限制参数的传递方式,这样,开发者只需查看函数定义,即可确定参数项是仅按位置、按位置或关键字,还是仅按关键字传递。需要使用/
和*
。
函数定义如下:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ----------- ----------
| | |
| | |
位置参数 位置参数或关键字参数 关键字参数
其中/
和*
是可选的。
3.1 位置或关键字参数
当函数定义中未使用/
和*
时,参数可以按照位置或关键字传递给函数。
3.2 仅位置参数
特定形参可以标记为 仅限位置。仅限位置 时,形参的顺序很重要,且这些形参不能用关键字传递。仅限位置形参应放在 /
(正斜杠)前。/
用于在逻辑上分割仅限位置形参与其它形参。如果函数定义中没有 /
,则表示没有仅限位置形参。
/
后可以是 位置或关键字 或 仅限关键字 形参。
3.3 仅限关键字参数
把形参标记为仅限关键字,表明必须以关键字参数的形式传递该参数。
3.4 函数示例
def standard_arg(arg):
print(arg)
def pos_only_arg(arg, /):
print(arg)
def kwd_only_arg(*, arg):
print(arg)
def combined_example(pos_only, /, standard, *, kwd_only):
print(pos_only, standard, kwd_only)
第一个函数 standard_arg
的函数定义对调用的方式没有任何限制,可以按位置也可以按关键字传递参数:
standard_aeg(2)
standard_aeg(arg=2)
第二个函数 pos_only_arg
的函数定义中有 /
,且形参全在 /
之前定义,所以仅限使用位置参数。
pos_only_arg(3)
pos_only_arg(arg=3) # 无效的调用
# TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'
第三个函数 kwd_only_arg
的函数定义通过 *
表明仅限关键字参数。
kwd_only_arg(arg=5)
kwd_only_arg(5) # 无效的调用
# TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
最后一个函数 combined_example
的函数定义中,使用了全部三种调用惯例:
- 该函数接收三个参数
- 第一个参数仅限位置参数
- 第二个参数可使用位置或关键字参数
- 第三个参数仅限关键字参数
combined_example(6, 7, kwd_only=8)
combined_example(6, standard=7, kwd_only=8)
下面的函数定义中,kwds
里面不能把 name
当做键。会与第一个参数 name
冲突。
def foo(name, **kwds):
print(name, **kwds)
foo(1, **{name: 2})
因为上面的函数调用相当于把name
赋值了两次。等价于:
foo(1, name=2)
由于此时name
既可以当作位置参数,也可以当作关键字参数,所以上述行为相当于给一个参数在一次函数调用中赋值了两次。
那么如何才能让 kwds
使用 name
当作键呢?
这就需要使用 特殊参数 /
来解决了,只要把 name
参数仅限使用位置参数,那么再使用name=2
时就不会被认为是第二次赋值了。
所以需要把函数定义为:
def foo(name, /, **kwds):
print(name, kwds)
foo(1, name=2, age=18)
# 1 {'name': 2, 'age': 18}
就可以了。👼
总结:仅限位置形参的名称可以在**kwds
中使用,而不产生歧义。
4 任意实参列表
调用函数时,使用任意数量的实参是最少见的选项。这些实参包含在元组中。
有时候,需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息。在这种 情况下,可将函数编写成能够接受任意数量的键值对——调用语句提供了多少就接受多少。
def sumnum(a, *ddd):
print(a)
result = a
for num in ddd:
result += num
return result
print(sumnum(1, 2, 3, 5, 6, 9, 8, 7))
# 1
# 41
*name
用于接收传递给函数的所有剩余位置参数,因此*name
的后面不允许出现位置参数,而是仅限关键字参数,同样的*name
的前面也不允许出现任何的关键字参数,而是仅限位置参数。
5 解包实参列表
函数调用要求独立的位置参数,但实参在列表或元组里时,要执行相反的操作。例如,内置的 range() 函数要求独立的 start 和 stop 实参。如果这些参数不是独立的,则要在调用函数时,用 *
操作符把实参从列表或元组解包出来:
>>> list(range(3, 6))
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args))
[3, 4, 5]
同样,字典可以用 **
操作符传递关键字参数。
6 Lambda 表达式
Lambda 关键字用于创建小巧的匿名函数。
Lambda a, b: a+b
上面的函数返回两个参数的和。Lambda 函数可用于任何需要函数对象的地方。在语法上,匿名函数只能是单个表达式。在语义上,它只是常规函数定义的语法糖。与嵌套函数定义一样,lambda 函数可以引用包含作用域中的变量:
def make_incrementor(n):
return lambda x: x + n
f = make_incrementor(42)
print(f(0))
# 42
print(f(1))
# 43
上例用 lambda 表达式返回函数。还可以把匿名函数用作传递的实参:
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
pairs.sort(key=lambda pa: pa[1])
print(pairs)
# [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
本文来自博客园,作者:雨-铃,原文链接:https://www.cnblogs.com/yuling25/p/15247764.html