type
status
date
slug
summary
tags
category
icon
password
我们在阅读python一些库的官方文档或源码时,经常会遇到*args**kwargs这样的参数(见下图)。这篇blog的目的是解释一下这俩奇怪的参数是什么意思,以及我们为什么要使用它们。
notion image

*args

向函数传递多个参数

假设要你写一个函数,它的输入是两个数,要求返回两个数的和。我们可以很轻松地写出下面的代码。
另一种看起来更酷炫的写法是:
显然这个函数是正确的,然而这并不算是一个好的函数定义。如果我需要这个函数能够计算三数之和、四数之和呢?难道我们又要重新写两个函数吗?
 
一个不错的方法是把my_sum 这个函数的输入换成一个list (tuple),然后在内部遍历这个list求和。
其实这已经相当接近*args的作用了,我们暂且记住这个思路。

*args的用法

将list传进我们写的函数里就要求我们每次调用都必须先创建好一个list (tuple),而*args则不需要。
可见,如果我们定义一个函数时将它的形参写为*args,那这个函数就允许我们输入任意多的参数。而且在函数体内部,我们基本就将这个args看作是一个包含了这些参数的tuple。它是一个tuple而非list这一点可以通过下面的代码验证。我们知道,tuple里的元素是不允许进行修改的,这个性质很好地保护了我们传进来的参数,能够避免很多的误操作,如在函数内部更新了某变量的值。
 

**kwargs

直接从英文入手的话,kw可以看成是keyword的缩写。**kwargs支持我们用键值对的方式传入参数。

Keyword Arguments

上一部分的例子my_sum函数的功能非常单一。现在考虑另外一个函数,用于打印个人信息。
print_info("John", "SCUT", "school of physics", "6666")这种调用方法其实不是很好,因为我们需要记住每个位置对应的属性是什么,所以我们也经常会使用如下指定keyword的方法进行调用。
然而,如果我想传入一个age的参数,这个程序就会报错,因为函数在定义的时候并没有包括这个参数。
想要让这个函数对未知的属性也能正常运作,一个很简单的思路就是把输入改成一个字典。

**kwargs的用法

**kwargs的用法其实和传入一个字典非常类似。如果我们定义函数时将参数写为**kwargs ,我们就可以通过keyword arguments来传入参数,并在函数内部访问kwargs 来获取具体关键词参数的键值对。
 
总结一下,*args**kwargs允许我们向函数传入任意长度的位置参数(positional arguments)与关键词参数(keyword arguments)。下一部分,我们看看***是起到什么作用。

Unpacking Operation (* and **)

在函数内部args是一个tuple,kwargs是一个dict。那么*和**到底是什么鬼东西?
 
***这两个操作符是对iteratable object(以下都以list为例)和dict的unpacking操作符。pack是打包,unpack就是从包里取出来。而我们的listdict就可以看作是箱包。
 
考虑这样一个问题,假设我们有一个list l=[1, 2, 3],现在我们想把里面的元素放到另外一个list的某个位置上,使得我们另外一个list是L=[0, 1, 2, 3, 4],那应该怎么操作呢?我们当然可以这样写
然而这种写法非常啰嗦。如果用我们前面学到的*操作符,我们可以更优雅地完成这个任务。
用一个例子来类比,就是我们出去旅游的时候打包行李箱,其他东西都装好了,然后留了个位置放电脑和充电器,我们就把电脑包打开,把里面的东西放进行李箱里,然后搞定了。
 
对dict也是同理。我们可以用unpacking operator **来简便地完成一些任务。比如合并两个dict:
 

Conclusion

在这篇blog里,我们主要介绍了函数定义中*args**kwargs的用法,以及***这两个unpacking操作符。
 
Kill Parallel Programs in BashHigh DPI for plt.show() in Jupyter