有时,你会看到python中定义函数的时候带有两个奇怪的参数:*args、**kwargs。如果你曾经想知道它们是干什么的,或者想知道你的IDE为什么在main()函数中定义它们,那么本文可以帮助到你。本文会告诉你在python中如何使用args和kwargs,来增加函数的灵活性。

1.传递多个参数给函数

*args和*kwargs允许你给一个参数传递多个参数或者keyword参数。考虑下面的例子。这是一个简单的函数,需要获取两个参数并返回它们之和:

def my_sum(a, b):

return a + b

这个函数可以正常工作,但它仅限于两个参数。如果需要对不同数量的参数求和,如果传递的特定参数数量仅在运行时确定,该怎么办?创建一个可以对传递给它的所有整数求和的函数,不管是多少个参数,是不是很好?

2.在python函数定义中使用变量args

有多种方法可以给一个函数传递不同数量的参数。

对于有经验的人来说,第一种最直观的方法是使用集合。简单地传递一个list或者set作为函数的参数。因此,对于my_sum(),你可以将你所有要相加的所有整数以一个list的形式传入:

# sum_integers_list.py

def my_sum(my_integers):

result = 0

for x in my_integers:

result += x

return result

list_of_integers = [1, 2, 3]

print(my_sum(list_of_integers))

可以这样实现,但是每当你要调用这个函数的时候,你就需要创建一个list作为参数传入。这样可能并不方便,尤其是你实现并不知道要加入list的所有值的时候。

这就是*args的作用之处了,它可以让你传递可变数量的位置参数。以下为示例:

# sum_integers_args.py

def my_sum(*args):

result = 0

# Iterating over the Python args tuple

for x in args:

result += x

return result

print(my_sum(1, 2, 3))

这个例子中,你不再需要向my_sum()函数传递一个list。而是传递三个不同的位置参数。my_sum()会获取所有输入的参数,并将它们打包成一个可迭代的简单对象,命名为args。

注意,args只是一个名字。你可以不用args这个名字。你可以选择任何你喜欢的名字,比如integers:

# sum_integers_args_2.py

def my_sum(*integers):

result = 0

for x in integers:

result += x

return result

print(my_sum(1, 2, 3))

这个函数仍然正常工作,即使你传递的可迭代对象是integers而不是args。这里最重要的是你使用的解包(unpacking)操作符(*)。

请记住,你使用解包(unpacking)操作符*获得的可迭代对象不是一个list,而是一个元组(tuple)。

一个元组(tuple)类似一个list,它们都支持切片和迭代。然而,元组(tuple)又是和list不同的,至少在一个方面:lists是可变的、tuple是不可变的。

为了测试这点,可以运行以下的代码。这个脚本尝试去修改一个list的值:

# change_list.py

my_list = [1, 2, 3]

my_list[0] = 9

print(my_list)

list中,第一个元素的值就被更新成了9。如果你执行这个脚本,你会看到list的值的确被修改了

$ python change_list.py

[9, 2, 3]

第一个元素的值不再是0,而是被更新成了9。现在,尝试对一个元组(tuple)做相同的操作:

# change_tuple.py

my_tuple = (1, 2, 3)

my_tuple[0] = 9

print(my_tuple)

这里,你可以看到相同的值,除了它们被作为一个元组被放在一起。如果你尝试执行脚本,你会看到python解释器返回了一个error:

$ python change_tuple.py

Traceback (most recent call last):

File "change_tuple.py", line 3, in

my_tuple[0] = 9

TypeError: 'tuple' object does not support item assignment

这是因为元组(tuple)是不可变对象,它的值不能在指定后就不能被更改。请牢记这一点,当你使用tuple和*args的时候。

3.在python函数定义中使用变量kwargs

到这里,你已经知道*args的用途了,但是**kwargs呢?**kwargs工作原理和*args有点类似,但不是接收位置参数,而是接收关键字(keyword)参数(也叫被命名的参数)。以下为例:

# concatenate.py

def concatenate(**kwargs):

result = ""

# Iterating over the Python kwargs dictionary

for arg in kwargs.values():

result += arg

return result

print(concatenate(a="Real", b="Python", c="Is", d="Great", e="!"))

执行上面的脚本,concatenate()会通过python的kwargs字典进行迭代并将找到的所有值连接起来:

$ python concatenate.py

RealPythonIsGreat!

和args类似,kwargs只是一个名字,可以修改成任何你想要的名字。最重要的是解包(unpacking operator)操作符(**)的用途。

因此,上面的例子可以写成这样:

# concatenate_2.py

def concatenate(**words):

result = ""

for arg in words.values():

result += arg

return result

print(concatenate(a="Real", b="Python", c="Is", d="Great", e="!"))

在上面例子中,可迭代对象是标准的字典(dict)。如果你迭代字典并想返回值,你就必须使用.values(),就像例子中那样所示。

事实上,如果你忘记了这个方法,你会发现你的迭代是通过你的python的kwargs字典的键实现的,就下下面的例子所示:

# concatenate_keys.py

def concatenate(**kwargs):

result = ""

# Iterating over the keys of the Python kwargs dictionary

for arg in kwargs:

result += arg

return result

print(concatenate(a="Real", b="Python", c="Is", d="Great", e="!"))

现在,你再执行示例,你会发现以下结果输出:

$ python concatenate_keys.py

abcde

可以看到,如果你不指定.values(),你的函数会通过键进行迭代你的python的kwargs字典,返回错误的结果。

4.函数中参数的顺序

既然你已经学习了*args和**kwargs是干什么的,你可以开始编写获取不同数量的参数的函数了。但是,如果你想创建一个函数,该函数接受可变数量的位置参数和命名参数,该怎么办?

这时,你就需要记住顺序很重要。非默认参数必须在默认参数之前处理,因此*args在**kwargs的前面。

总结一下,参数的正确顺序是:

(1)位置参数

(2)*args参数

(3)**kwargs参数

例如,以下函数的定义是正确的:

# correct_function_definition.py

def my_function(a, b, *args, **kwargs):

pass

*args变量在**kwargs的前面。但是,如果你想修改参数的顺序呢?例如,考虑下面的函数:

现在,函数定义中**kwargs在*args的前面。如果你想运行这个例子,你会接收到来自解释器一个错误:

$ python wrong_function_definition.py

File "wrong_function_definition.py", line 2

def my_function(a, b, **kwargs, *args):

^

SyntaxError: invalid syntax

这种情况下,因为*args在**kwargs的后面,python解释器抛出SyntaxError。

这里还可以分场景继续细化出其它场景:

(1)如果只有位置参数、默认参数、*args。顺序是:(位置参数,默认参数,*args)或者(位置参数,*args,默认参数)

(位置参数,默认参数,*args)

def foo(x,y=1,*args):

pass

foo (1,2,3,4,5) // 其中的x为1,y=1的值被2替换,3,4,5都给args,即args=(3,4,5)

(位置参数,*args,默认参数)

def foo(x,*args,y=1):

pass

foo (1,2,3,4,5) // 其中的x为1,2,3,4,5都给args,即args=(2,3,4,5),y始终为1

(2)位置参数、默认参数、*args*和*kwargs同时出现。顺序是:(位置参数,*args*,默认参数,*kwargs)

def foo1(x, y, *args, a=8, b=9, **kwargs):

pass

foo1(1,2,3,4,a=5,b=6,y=7)

#其中的x为1,y为2

#3,4都给args,即args=(3,4)

#a,b分别被替换成5,6

#y=7以字典形式传给kwargs

如果不带默认参数:

def foo2(x, y, *args,**kwargs):

pass

foo2(1,2,3,4,a=5,b=6,y=7)

#其中的x为1,y为2

#3,4都给args,即args=(3,4)

#a=5,b=6,y=7以字典形式传给kwargs

5.解包(unpacking)星号操作符:*和**

现在你可以使用*args和**kwargs来定义获取变化的输入参数的python函数了。让我们再深入地理解解包(unpacking)操作符。

单个星号(*)和两个星号(**)解包操作符是在Python2中引入的。在3.5版本中,它们变得更强大。简而言之,解包(unpacking)操作符是将python中可迭代对象的值解包的操作符。单个星号操作符可以用在任意python提供的可迭代对象上,两个星号操作符只能用于字典。

我们从下面这个例子开始:

# print_list.py

my_list = [1, 2, 3]

print(my_list)

代码定义了一个list,然后将其打印输出到标准输出:

$ python print_list.py

[1, 2, 3]

注意列表是如何打印的,以及相应的括号和逗号。

现在,试着把解包操作符*添加到列表中:

# print_unpacked_list.py

my_list = [1, 2, 3]

print(*my_list)

这里,*操作符告诉print()首先将list解包。

在这个例子中,输出不再是list本身,而是list的内容:

$ python print_unpacked_list.py

1 2 3

你能看出这个例子执行结果和print_list.py有什么不同么?print()已经将三个不同的参数作为输入,而不是以一个list作为输入。

另外你可能看到,在print_unpacked_list.py中,你使用了解包操作符(*)来调用函数,而不是用在函数定义中。在这里,print()将list中的单个item作为一个个参数。

你也可以使用这个方法调用自己的函数,但是如果你的函数需要特定数量的参数,那么你解包的iterable必须具有相同数量的参数。

为了测试这个行为,考虑以下的脚本:

# unpacking_call.py

def my_sum(a, b, c):

print(a + b + c)

my_list = [1, 2, 3]

my_sum(*my_list)

这里,my_sum()显式声明a,b,c是需要的参数。

如果你运行这个脚本,你会获得my_list中三个数的和:

$ python unpacking_call.py

6

my_list中的三个元素完美地匹配了my_sum()需要的参数。

现在,看一下下面的脚本,my_list有四个参数而不是三个:

# wrong_unpacking_call.py

def my_sum(a, b, c):

print(a + b + c)

my_list = [1, 2, 3, 4]

my_sum(*my_list)

在这个例子中,my_sum()仍然期待三个参数,但是*操作符从list中获得了四个。如果你尝试执行这个脚本,你会发现python解释器仍然可以运行它:

$ python wrong_unpacking_call.py

Traceback (most recent call last):

File "wrong_unpacking_call.py", line 6, in

my_sum(*my_list)

TypeError: my_sum() takes 3 positional arguments but 4 were given

当你用*操作符去解包一个list并传递给函数作为参数,就好像你在传递每一个单独的参数。

这表示你可以使用多个解包(unpacking)操作符,从多个lists中获取值并作为参数传递个一个函数。

可以用以下的示例来测试:

# sum_integers_args_3.py

def my_sum(*args):

result = 0

for x in args:

result += x

return result

list1 = [1, 2, 3]

list2 = [4, 5]

list3 = [6, 7, 8, 9]

print(my_sum(*list1, *list2, *list3))

如果你运行这个例子,所有的lists都被解包。每个单独的项被传递给my_sum(),结果如下:

$ python sum_integers_args_3.py

45

解包操作符还有其他方便的用途。例如,假设你需要将列表分成三个不同的部分。输出应该显示第一个值、最后一个值和中间的所有值。使用解包操作符,你可以用一行代码完成:

# extract_list_body.py

my_list = [1, 2, 3, 4, 5, 6]

a, *b, c = my_list

print(a)

print(b)

print(c)

在这个例子中,my_list包含6个项。第一个变量被分配给a,最后一个被分配给c,其它的值都被打包成一个list b。如果你运行一下,print()会显示三个变量的值:

$ python extract_list_body.py

1

[2, 3, 4, 5]

6

另一个有趣的事是,你可以使用解包操作符(*)来对任何可迭代对象进行分片。如果你需要将两个list进行合并,就会非常有用:

# merging_lists.py

my_first_list = [1, 2, 3]

my_second_list = [4, 5, 6]

my_merged_list = [*my_first_list, *my_second_list]

print(my_merged_list)

解包操作符(*)作为my_first和my_second的前缀。

如果你运行脚本,你会看到一个合并的list:

$ python merging_lists.py

[1, 2, 3, 4, 5, 6]

你可以合并两个不同的字典,通过解包操作符(**):

# merging_dicts.py

my_first_dict = {"A": 1, "B": 2}

my_second_dict = {"C": 3, "D": 4}

my_merged_dict = {**my_first_dict, **my_second_dict}

print(my_merged_dict)

这里,迭代合并了my_first_dict和my_second_dict。

执行这个代码,输出一个合并后的字典:

$ python merging_dicts.py

{'A': 1, 'B': 2, 'C': 3, 'D': 4}

请牢记,*操作可以对任意可迭代对象起作用。可以对一个字符串进行解包操作:

# string_to_list.py

a = [*"RealPython"]

print(a)

在python中,字符串是可迭代对象,因此*会解包字符串并将单个值放入list a中:

$ python string_to_list.py

['R', 'e', 'a', 'l', 'P', 'y', 't', 'h', 'o', 'n']

在使用这些操作符的时候,要记住代码的可读性很重要。

考虑以下的代码:

# mysterious_statement.py

*a, = "RealPython"

print(a)

这里的解包操作符*,后面跟了一个变量,一个逗号和一个赋值。一行中打包了很多东西,这个代码和上面的代码没有什么区别。只是将字符串RealPyhton中所有的项指定到一个新的list a。

a后面的逗号就可以了。当使用带有变量赋值的解包操作符时,Python要求得到的变量要么是列表,要么是元组。使用后面的逗号,实际上已经定义了一个只有一个命名变量a的元组。

虽然这是一个巧妙的技巧,但许多Pythonistas并不认为这段代码可读性很强。因此,最好少用这类结构。

6.结论

现在,在你的python函数中,可以使用*args和**kwargs来接收可变数量的参数了。你也了解了解包操作符。

你已经学会:

(1)*args和**kwargs的含义。*args:非关键字参数、**kwargs:关键字参数

(2)如何使用*args和**kwargs来定义函数

(3)如何使用单个星号(*)来解包可迭代对象

(4)如何使用两个星号(**)来解包字典对象

7.python小技巧

# How to merge two dicts

# in Python 3.5+

>>> x = {'a':1,'b':2}

>>> y = {'b':3,'c':4}

>>> z = {**x,**y}

>>> z

{'c':4,'a':1,'b':3}

python args kwargs_Python中的args和kwargs相关推荐

  1. Python中的*args和**kwargs是什么?该如何使用?

    2020-01-16 12:30:00 全文共2911字,预计学习时长9分钟 来源:Pexels 在编程中,函数就是生命! 作为使用Python的新手--无论是编程新手,还是熟悉另一语言的人--都需要 ...

  2. python的认识_理解 Python 中的 *args 和 **kwargs

    Python是支持可变参数的,最简单的方法莫过于使用默认参数,例如: def test_defargs(one, two = 2): print 'Required argument: ', one ...

  3. 理解 Python 中的 *args 和 **kwargs

    Python是支持可变参数的,最简单的方法莫过于使用默认参数,例如: def test_defargs(one, two = 2):print 'Required argument: ', onepr ...

  4. python中形参*args和**kwargs简述

    形参*args的作用:传递任意数量的实参. 形参*args中的星号让python创建一个名为args的空元组,并将收到的所有值都封装到这个元组中.其实args换成其他的标识符完全没问题,只是习惯上用a ...

  5. python 中参数*args, **kwargs

    python 中参数*args, **kwargs def foo(*args, **kwargs): print 'args = ', args print 'kwargs = ', kwargs ...

  6. Python中的args和kwargs

    在Python中的代码中经常会见到这两个词 args 和 kwargs,前面通常还会加上一个或者两个星号.其实这只是编程人员约定的变量名字,args 是 arguments 的缩写,表示位置参数:kw ...

  7. Python中的*args和**kwargs

    *args表示的是arguments,**kwargs表示的是keyword arguments,他们两个叫做python中的可变参数. 注意:args和kwargs可以随便修改,重点在于*和**,所 ...

  8. 一文弄懂Python中的*args 和 **kwargs

    1. 引言 在本文中,我们将讨论 Python 中的 *args 和 **kwargs 及其用法和示例. 闲话少说,我们直接开始吧. 2. 问题引入 在Python中写函数的时候,我们经常需要给函数传 ...

  9. 了解Python中的Args和Kwargs

    在本教程中,我将重点介绍Python中的参数( *args )和关键字参数( *kwargs ). 我将教你什么是args和kwargs,最重要的是,如何使用它们-即如何在函数中接受无限数量的参数和关 ...

最新文章

  1. C++ Primer 5th笔记(9)chapter9 顺序容器 vector 容器的自增长 容器适配器
  2. Android Studio 如何导入第三方jar包(整理)
  3. LiveVideoStack 2021招聘季
  4. 使用 docker 构建分布式调用链跟踪框架skywalking
  5. Android 布局练习
  6. android webview简单使用,android WebView 简单使用Demo
  7. delphi webbrowser 对象不支持_建模初学者,那些你可能还不知道的10个ZBrush小技巧!【值得收藏】...
  8. linux部署Oracle数据库--安装篇
  9. python 字符串 类型互相转换 str bytes 字符串连接
  10. 最小生成树的纠结_交流电之王-ChinaUnix博客
  11. IIC协议简介—学习笔记
  12. 微信小程序-map地图标签的初级使用, 拥有图标,气泡,地图本身无法缩放移动需要点击跳转第三方地图平台
  13. Angular6项目运行到95%emitting LicenseWebpackPlugin不动卡住
  14. java语言编程入门
  15. Unity3D游戏开发入门学习笔记
  16. js版ffmpeg压缩视频以及去除背景音乐
  17. python中seaborn是什么_Python数据分析之seaborn常用方法
  18. 父亲节送礼!购机推荐iQOO Neo6 SE与红米Note 11T Pro
  19. .NET应用程序安全操作概述
  20. ThinkPHP校园后勤在线报修系统

热门文章

  1. Linux疑难杂症解决方案100篇(十一)-常用Linux命令,助力工作更轻松便捷
  2. 怎样更好地使用快捷键?
  3. 树转化为二叉树_森林转化为二叉树(详解版)
  4. windows安装anaconda_[计算机科学工具系列] Anaconda和conda
  5. Python入门100题 | 第075题
  6. 深度学习100例 -卷积神经网络(ResNet-50)鸟类识别 | 第8天
  7. selenium教程
  8. Python--strip()学习记录
  9. JS数据类型与分支结构
  10. Python编程基础:第五节 用户输入User Input