1) 函数中的类型提示
我刚开始学 Python 的时候,完全没用过类型提示。所以在最初的几年里写 Python 代码时,我一个类型提示都没加过。
举个简单的例子,假设我们要写一个函数来计算两个整数的平均值。以前我是这样写的:
def avg(a, b):
return (a + b) / 2
现在我在工作中写函数的方式(添加了类型提示和文档字符串):
def avg(a: int, b: int) -> float:
"""
计算 a 和 b 的平均值
参数:
a (int): 一个整数
b (int): 一个整数
返回:
float: a 和 b 的平均值
"""
return (a + b) / 2
a: int
意味着 a 最好是个整数b: int
意味着 b 最好也是个整数-> float
意味着函数最好返回一个浮点数值
不过,需要注意的是,类型提示只是提示,不会强制执行。如果我们传入字符串或其他数据类型到 a 和 b 中,Python 其实并不介意(直到它试图把字符串除以 2 时才会出错)
类型提示的主要作用是 1) 让人类更容易读懂代码,2) 让你的 IDE(比如 PyCharm 或 VSCode)能为你做检查。
尽可能地给你的函数添加类型提示,这样其他程序员(或者未来的自己)就能更容易理解这些函数了。
2) 默认参数
def greet(name, greeting='hi'):
print(greeting, name)
上面的函数中,greeting='hi'
就是一个默认参数。
- 如果我们不给 greeting 传入任何值,它就默认被赋值为
'hi'
- 如果我们决定给 greeting 传入某个值,那就用那个值
greet('汤姆')
# hi 汤姆
greet('汤姆', greeting='你好')
# 你好 汤姆
在 greet('汤姆')
中,我们没有给 greeting 传入任何值。这意味着它会采用默认值 'hi'
。
而在 greet('汤姆', greeting='你好')
中,我们给 greeting 传入了 '你好'
。这就覆盖了默认参数,把 greeting 设定为 '你好'
。
如果你的函数有很多参数,又不想每次调用时都得传入所有参数的话,这招可真管用。
3) 参数与实参
在我刚开始学 Python 的头几年里,我一直以为这两个词是一个意思。
其实不然,它们之间还是有些微妙的区别。
假设我们有个简单的函数,接受 a 和 b 两个参数,返回它们的平均值。
def avg(a, b):
return (a + b) / 2
参数是在定义函数时括号内写明的变量。这里,a 和 b 就是参数。
实参是我们调用函数时实际传入的值。当我们调用 avg(a, b)
函数时,3 和 5 就是实参。
4) 位置参数与关键字参数
一个简单的示例函数。
def test(a, b):
print(f'a={a} b={b}')
我们先通过位置参数来调用这个函数。
test(4, 7) # a=4, b=7
这里,4 和 7 是位置参数。位置参数必须按顺序传递——4 被传给 a,而 7 则传给了 b。
接着,我们通过关键字参数来调用函数。
test(b=5, a=8) # a=8, b=5
这里,b=5
和 a=8
是关键字参数。关键字参数不必按顺序传递,但必须以 键=值
的形式传入。
5) 任意数量的位置参数 (*args)
函数中的任意数量的位置参数,通常写作 *args,能让函数接收任意多个位置参数。
def test(*args):
print(args)
test() # 错误
test(1) # 错误
test(1, 2) # (1, 2)
test(1, 2, 3, 4) #(1, 2, 3, 4)
这里,test 函数使用 *args — 这意味着 test 可以接收任意数量的位置参数,这些参数会被收集到一个名为 args 的元组中。
我们可以把这个与普通参数结合使用(*args 必须放在后面)。
def test(a, b, *args):
print([a, b], args)
test() # 错误
test(1) # 错误
test(1, 2) # [1, 2], ()
test(1, 2, 3, 4) #[1, 2], (3, 4)
额外说明 — 我们不必非要用 *args,只要在前面加个星号就行。
6) 任意数量的关键字参数 (**kwargs)
任意数量的关键字参数,通常写作 **kwargs,能让我们的函数接收任意多个关键字参数。
def test(**kwargs):
print(kwargs)
test() # {}
test(a=1) #{'a': 1}
test(a=1, b=2) #{'a': 1, 'b': 2}
这里,test 函数使用 **kwargs — 这意味着 test 可以接收任意数量的关键字参数,这些参数会被收集到一个名为 kwargs 的字典中。
我们也可以把这个与普通参数结合使用(**kwargs 也必须放在后面)。
额外说明 — 我们不必非得用 **kwargs,只要在前面加两个星号就行。
7) 使用 * 和 ** 传递列表/字典到函数中
这里有一个简单的函数,用来打印出它的参数。
def hi(a, b):
print(f'{a=} {b=}')
除了像 hi(1, 2)
这样正常调用函数外,我们还可以:
- 使用 * 来传递包含位置参数的列表
def hi(a, b):
print(f'{a=} {b=}')
nums = [100, 200]
hi(*nums)
这里,*nums 前面的星号将列表的内容展开为位置参数。这就相当于 hi(100, 200)
。
- 使用 ** 来传递包含关键字参数的字典
def hi(a, b):
print(f'{a=} {b=}')
nums = {'a': 100, 'b': 10}
hi(**nums)
这里,**nums 前面的两个星号将字典的键值对展开为关键字参数。这就相当于 hi(a=100, b=10)
。