首页 > temp > python入门教程 >
-
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}
就可以了。