仅强调关键字参数
在Python
中通过关键字来传递参数值是一个很强大的特征(详见第19
项:使用关键字参数来提供可选行为操作)。关键字参数的灵活性可以帮助你书写更加简洁,易读的代码。
例如:你可能想用一个数除以另一个数,但是在特殊情况下,你需要非常的小心。你可能想忽略ZeroDivisionError
异常,使用无穷值返回来替代。又有时,你想忽略OverflowError
异常返回零来替代。
def safe_division(number, divisor, ignore_overflow, ignore_zero_division):
try:
return number / divisor
except OverflowError:
if ignore_overflow:
return 0
else:
raise
except ZeroDivisionError:
if ignore_zero_division:
return float('inf')
else:
raise
# 使用起来也是直截了当,调用的时候会忽略除数的float overflow,并返回0;或者忽略除数为零,返回无限值
result = safe_division(1, 10**500, True, False)
print(result)
result = safe_division(1, 0, False, True)
print(result)
>>>
0.0
inf
容易使人疑惑的问题就是两个布尔类型的控制异常忽略的参数的位置。改变这一现状的一个方式就是使用关键字参数来改善代码的可读性。默认地,这个函数可能过于谨慎了,并且可能重新触发异常。
def safe_division_b(number, divisior, ignore_overflow=False, ignore_zero_division=False)
# ······
这样的话调用方就可以指定关键字来决定到底要忽略哪一个操作,或者来覆盖默认的行为。
safe_division_b(1, 10**500, ignore_overflow=True)
safe_division_b(1, 10**500, ignore_zer0_division=True)
然而问题是,当关键字参数变成了可选的时候,就不能够强迫调用者使用关键字参数来简化代码了。不过还好,新定义的这个safe_division_b
函数仍然可以通过位置参数的调用来工作。
safe_division_b(1, 10*500, True, False)
当函数变得像上面代码中展示的那样复杂的时候,最好是需要调用者对他们自己的意图非常的了解。如果都不知道自己要做什么,又怎么能做得好呢?在Python3
中,你可以只使用关键字参数来使你的代码变得更加的整洁。这些参数也仅仅只能通过关键字参数赋值的形式被使用,而不是通过位置参数赋值的方式。
def safe_division_c(number, division, *, ignore_overflow=False, ignore_zero_division=False):
# ······
# 1.然后现在如果还是使用位置参数赋值的方式的话,函数就不会正常地工作了。
safe_division_c(1, 10**500, True, False)
>>>
TypeError: safe_division_c() takes 2 position arguments but 4 ware given.
# 2. 现在使用关键字参数赋值的方式的话,就可以得到正常的预期结果了。
safe_division_c(1, 0, ignore_zero_division=True)
try:
safe_division_c(1, 0)
except ZeroDivisionError:
pass
Python2 中的只使用关键字参数
不幸的是,我们家的Python2
中也是没有明确的像Python3
中的keyword-only
语法。不过伟大的程序员们总是可以想到替代方案嘛。那就是通过在参数列表中使用**
操作符来帮助无效调用来触发TypeError
。其实**
操作符和*
操作符起到的作用类似(详见第18
项:使用可变位置参数减少代码干扰),除了接收可变数量的位置参数以外,它还可以接收任意数量的关键字参数。
# Python2
def print_args(*args, **kwargs):
print 'Positional:', args
print 'Keyword:', kwargs
print_args(1, 2, foo='bar', stuff='meep')
>>>
Positional: (1, 2)
Keyword: {'foo': 'bar', 'stuff': 'meep'}
为了实现在Python2
中的keyword-only
性质的safe_division
函数,我们就需要使用**
操作符了。然后从kwargs
字典中去除我们预期的关键字参数,使用pop
方法的第二个参数来指定默认的值,这对关键字对应的值出现丢失的情况非常的适用。最终,确保kwargs
列表中没有所需的关键字的遗留来防止调用方提供无效的参数。
# Python 2
def safe_division(number, divisor, **kwargs):
ignore_overflow = kwargs.pop('ignore_overflow', False)
ignore_zero_division = kwargs.pop('ignore_zero_division', False)
if kwargs:
raise TypeError("Unexpected **kwargs: %r"%kwargs)
# ···
# 测试
safe_division(1, 10)
safe_division(1, 0, ignore_zero_division=True)
safe_division(1, 10**500, ignore_overflow=True)
# 而想通过位置参数赋值,就不会正常的运行了
safe_division(1, 0, False, True)
>>>
TypeError:safe_division() takes 2 positional arguments but 4 were given.
# 而输入了非预期的关键字的时候,也会触发类型错误
safe_division(0, 0, unexpected=True)
>>>
TypeErroe: Unexpected **kwargs: {'unexpected': True}
备忘录
- 关键字参数使得函数调用的意图更加的清晰,明显。
- 适用
keyword-only
参数可以强迫函数调用者提供关键字来赋值,这样对于容易使人疑惑的函数参数很有效,尤其适用于接收多个布尔变量的情况。 Python3
中有明确的keyword-only
函数语法。Python2
中可以通过**kwargs
模拟实现keyword-only
函数语法,并且人工的触发TypeError
异常。keyword-only
在函数参数列表中的位置很重要,这点大家尤其应该明白!