30.1.5. 用辅助函数取代复杂的表达式

Python的语法相当简明,所以有时只用一条表达式就能实现许多逻辑。

例如,要把URL之中的查询字符串拆分成键值对,那么只需要使用parse_qs函数就可以了。

下面的例子会解析查询字符串之中的每个参数,并把这些参数跟它们所对应的整数值放到一份字典(dict)里面。

from urllib.parse import parse_qs

my_value = parse_qs('red=5&blue=0&green=', keep_blank_values=True)
print(repr(my_value))

在解析查询字符串时,可以发现,有的参数可能带有多个值,有的参数可能只有一个值,还有的参数可能是空白值,另外也会遇到根本没提供这个参数的情况。

下面这三行代码分别通过get方法查询结果字典里面的三个参数,这刚好对应三种不同的情况:

print("Red: ", my_value.get("red"))
print("Green: ", my_value.get("green"))
print("Opacity: ", my_value.get("opacity"))

Boolean表达式用Python的语法写起来很简单,因为Python在对这种表达式求值的时候,会把空白字符串、空白list以及0值,全都当成False看待。

所以,只需要把get方法查到的结果放在or操作符的左边,并且在右边写上0就行了。

这样的话,只要左边的子表达式为False,那么整个表达式的值自然就被评估为右边那个表达式的值,也就是0。

red = my_value.get("red", [''])[0] or 0
green = my_value.get("green", [''])[0] or 0
Opacity = my_value.get("opacity", [''])[0] or 0

print(f"Red : {red!r}")
print(f"Green : {green!r}")
print(f"Opacity : {Opacity!r}")
"""
Red:  5
Green:  0
Opacity:  0
"""

Python可以用if/else结构实现三元的条件表达式,将字符串转为整数

red_str = my_value.get("red", [''])[0] or 0
red = int(red_str) if red_str[0] else 0

或者多写几行如下

green_str = my_value.get("green", [''])
if green_str[0]:
    green = int(green_str[0])
else:
    green = 0

如果反复使用的话可以写成辅助函数如下

def get_first_int(values, key, default=0):
    found = values.get(key, [''])
    if found[0]:
        return int(found[0])
    return default


green = get_first_int(my_value, "green")

print(green)

如果你发现表达式越写越复杂,那就应该考虑把它拆分成多个部分,并且把这套逻辑写到辅助函数里面。这样虽然要多编几行代码,但可以让程序更加清晰,所以总体来说还是值得的。

语法简洁的Python虽然可以写出很多浓缩的句式,但应该避免让这样的写法把表达式弄得太复杂。

我们要遵循DRY原则,也就是不要重复自己写过的代码(Don’t Repeat Yourself)。

要点

Python的语法很容易把复杂的意思挤到同一行表达式里,这样写很难懂。

复杂的表达式,尤其是那种需要重复使用的复杂表达式,应该写到辅助函数里面。用if/else结构写成的条件表达式,要比用or与and写成的Boolean表达式更好懂。