分享

python中的双星参数展开问题

 xiaoyimin 2019-07-12

在python的函数中允许有不定参数,我们对于这种参数已经习以为常了,并且这种写法很方便的,但是对于它背后的运行机制却不是很熟悉,正好最近在写项目过程中有遇到过这种双星不定参数的问题,这里也记录一下。

基本使用

这个脚本的测试结果为:

我们看到,调用函数test的参数为'yang', 18, 'is', 'a', 'good', 'man', sex='male',python依次将yang和18赋给了name和age,将'is', 'a', 'good', 'man'赋给了args元组,将sex='male'转换成了一个字典给了kwargs.

双星操作到底做了什么?

我们知道kwargs是一个字典,但是是否考虑过**kwargs是个什么东西吗?打印一下看看。

试图打印**dict的时候却报错了,它的意思是name并不是print函数的参数,那么标准库中的print函数都有哪些参数呢?我们来看一下print在标准库中的定义

print(self, *args, sep=' ', end='\n', file=None),

它确实没有一个name的形参,如果使用print(**d)是不是就和print(name='yangyanxing')的效果是一样的呢?

它们报了相同的错误,这里们先假定使用**dict其实就是将一个字典里的各项依次展开,比如d={'name':'yangyanxing'},使用**d则返回name='yangyanxing'的形式。

我们写一个函数检测一下

这里test函数需要两个参数,name和age,但是我们在传参数的时候并没有直接传这两个参数,而是传一个**字典,**号会把字典展开成key=value的形式并且传递到test函数中。于是得到了以下的输出

name: 杨彦星
age 18

如果所传入的字典中包含了不只包含了函数所需要的参数,还有更多的参数呢?

它得到的结果是

name: 杨彦星
age 18
kwargs: {'school': 'bjut', 'sex': 'male'}

可以看到,它将字典里多余的键值对放到了kwargs字典中了。

同理,一个*也是自动展开列表和元组

这里我们将列表l和元组t展开传到test函数中,相当于

test('a','b','c','d','e','f',name1='杨彦星',age1=18),

于是得到以下输出

args: ('c', 'd', 'e', 'f')
kwargs: {'age1': 18, 'name1': '杨彦星'}
name: a
age: b

这里有几个问题需要注意下,由于**kwargs 只能定义在函数参数的最后,它后面不能再有形参了,但是*参数可以不限制参数的位置,所以上面的代码在定义d的时候不能再有name和age的定义了,因为在传参的时候,已经将'a'赋给了name,'b'赋给了age,所以如果之后再有name的定义则会报参数重复定义的错误。但是却可以如下的定义

因为把*args放到了第一个参数,所以在调用函数时为

test('a','b','c','d','e','f',name='杨彦星',age=18,sex='male'),

此时如果d的定义的时候没有name和age也会报错。

我觉得这种写法并不是很优雅,但是看到过有些库里有过类似的写法,所以之后看到不用太困惑,只需要理解**和*只是把后面的字典和列表或者元组进行展示即可。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多