天天看点

《编写高质量Python代码的59个有效方法》——第18条:用数量可变的位置参数减少视觉杂讯

本节书摘来自华章社区《编写高质量python代码的59个有效方法》一书中的第18条:用数量可变的位置参数减少视觉杂讯,作者[美]布雷特·斯拉特金(brett slatkin),更多章节内容可以访问云栖社区“华章社区”公众号查看

第18条:用数量可变的位置参数减少视觉杂讯

令函数接受可选的位置参数(由于这种参数习惯上写为*args,所以又称为star args,星号参数),能够使代码更加清晰,并能减少视觉杂讯(visual noise)。

例如,要定义log函数,以便把某些调试信息打印出来。假如该函数的参数个数固定不变,那它就必须接受一段信息及一份含有待打印值的列表。

即便没有值要打印,只想打印一条消息,调用者也必须像上面那样,手工传入一份空列表。这种写法既麻烦,又显得杂乱。最好是能令调用者把第二个参数完全省略掉。若想在python中实现此功能,可以把最后那个位置参数前面加个*,于是,对于现在的log函数来说,只有第一个参数message是调用者必须要指定的,该参数后面,可以跟随任意数量的位置参数。函数体不需要修改,只需修改调用该函数的代码。

如果要把已有的列表,传给像log这样带有变长参数的函数,那么调用的时候,可以给列表前面加上*操作符。这样python就会把这个列表里的元素视为位置参数。

接受数量可变的位置参数,会带来两个问题。

第一个问题是,变长参数在传给函数时,总是要先转化成元组(tuple)。这就意味着,如果用带有*操作符的生成器为参数,来调用这种函数,那么python就必须先把该生成器完整地迭代一轮,并把生成器所生成的每一个值,都放入元组之中。这可能会消耗大量内存,并导致程序崩溃。

只有当我们能够确定输入的参数个数比较少时,才应该令函数接受*arg式的变长参数。在需要把很多字面量或变量名称一起传给某个函数的场合,使用这种变长参数,是较为理想的。该参数主要是为了简化程序员的编程工作,并使得代码更加易读。

使用*arg参数的第二个问题是,如果以后要给函数添加新的位置参数,那就必须修改原来调用该函数的那些旧代码。若是只给参数列表前方添加新的位置参数,而不更新现有的调用代码,则会产生难以调试的错误。

问题在于:上面的第二条log语句是以前写好的,当时的log函数还没有sequence参数,现在多了这个参数,使得7从values值的一部分,变成了message参数的值。这种bug很难追踪,因为现在这段代码仍然可以运行,而且不抛出异常。为了彻底避免此类情况,我们应该使用只能以关键字形式指定的参数(keyword-only argument),来扩展这种接受*args的函数(参见本书第21条)。

要点

在def语句中使用*args,即可令函数接受数量可变的位置参数。

调用函数时,可以采用*操作符,把序列中的元素当成位置参数,传给该

函数。

对生成器使用*操作符,可能导致程序耗尽内存并崩溃。

在已经接受*args参数的函数上面继续添加位置参数,可能会产生难以排查的bug。