**kwargs 的目的和用途是什么?[重复]

2024-11-25 08:50:00
admin
原创
157
摘要:问题描述:在 Python 中有何用途**kwargs?我知道你可以objects.filter在桌子上做一个并传递一个**kwargs参数。  我也可以这样做来指定时间增量吗timedelta(hours = time1)?它究竟是如何工作的?它被归类为“拆包”吗?喜欢吗a,b=1,2?解决方案 1:您可以...

问题描述:

在 Python 中有何用途**kwargs

我知道你可以objects.filter在桌子上做一个并传递一个**kwargs参数。  

我也可以这样做来指定时间增量吗timedelta(hours = time1)

它究竟是如何工作的?它被归类为“拆包”吗?喜欢吗a,b=1,2


解决方案 1:

您可以使用**kwargs让您的函数采用任意数量的关键字参数(“kwargs”表示“关键字参数”):

>>> def print_keyword_args(**kwargs):
...     # kwargs is a dict of the keyword args passed to the function
...     for key, value in kwargs.iteritems():
...         print "%s = %s" % (key, value)
... 
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe

您还可以**kwargs在调用函数时通过构造关键字参数字典并将其传递给函数来使用该语法:

>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith

Python 教程很好地解释了它的工作原理,并提供了一些很好的例子。

Python 3 更新

对于 Python 3,请iteritems()使用items()

解决方案 2:

解包字典

**解压字典。

func(a=1, b=2, c=3)

等同于

args = {'a': 1, 'b': 2, 'c':3}
func(**args)

如果你必须构造参数,它很有用:

args = {'name': person.name}
if hasattr(person, "address"):
    args["address"] = person.address
func(**args)  # either expanded to func(name=person.name) or
              #                    func(name=person.name, address=person.address)

函数的打包参数

  • 对于 Python 3,使用.items()代替.iteritems()

def setstyle(**styles):
    for key, value in styles.iteritems():      # styles is a regular dictionary
        setattr(someobject, key, value)

这使你可以像这样使用该函数:

setstyle(color="red", bold=False)

笔记

  • kwargs是用于关键字参数的变量名,也可以使用另一个变量名。重要的是它是一个字典,并且使用双星号运算符解包**

  • 其他可迭代对象用单个星号运算符解包*

  • 为了避免混淆,最好坚持使用已识别的变量名,kwargsargs,分别用于字典和其他可迭代对象。


资源

  • PEP 448:额外的拆包概括

  • 真正的 Python:Python args 和 kwargs:揭秘

  • 函数签名中变量名前的 * 是什么意思?

解决方案 3:

kwargs只是一个添加到参数的字典。

字典可以包含键、值对。这就是 kwargs。好的,就是这样。

而其目的却不那么简单。

例如(非常假设),您有一个仅调用其他例程来完成工作的接口:

def myDo(what, where, why):
   if what == 'swim':
      doSwim(where, why)
   elif what == 'walk':
      doWalk(where, why)
   ...

现在你得到一个新的方法“驱动”:

elif what == 'drive':
   doDrive(where, why, vehicle)

但是等一下,有一个新的参数“vehicle”——你之前不知道它。现在你必须将它添加到 myDo 函数的签名中。

在这里你可以使用 kwargs —— 只需将 kwargs 添加到签名中:

def myDo(what, where, why, **kwargs):
   if what == 'drive':
      doDrive(where, why, **kwargs)
   elif what == 'swim':
      doSwim(where, why, **kwargs)

这样,每次调用的某些例程发生变化时,您不需要更改接口函数的签名。

这只是一个很好的例子,您会发现 kwargs 很有用。

解决方案 4:

基于一个好的示例有时比一个长篇大论要好,我将使用所有 python 变量参数传递功能(位置参数和命名参数)编写两个函数。您应该能够轻松地自己看到它的作用:

def f(a = 0, *args, **kwargs):
    print("Received by f(a, *args, **kwargs)")
    print("=> f(a=%s, args=%s, kwargs=%s" % (a, args, kwargs))
    print("Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)")
    g(10, 11, 12, *args, d = 13, e = 14, **kwargs)

def g(f, g = 0, *args, **kwargs):
    print("Received by g(f, g = 0, *args, **kwargs)")
    print("=> g(f=%s, g=%s, args=%s, kwargs=%s)" % (f, g, args, kwargs))

print("Calling f(1, 2, 3, 4, b = 5, c = 6)")
f(1, 2, 3, 4, b = 5, c = 6)

输出如下:

Calling f(1, 2, 3, 4, b = 5, c = 6)
Received by f(a, *args, **kwargs) 
=> f(a=1, args=(2, 3, 4), kwargs={'c': 6, 'b': 5}
Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
Received by g(f, g = 0, *args, **kwargs)
=> g(f=10, g=11, args=(12, 2, 3, 4), kwargs={'c': 6, 'b': 5, 'e': 14, 'd': 13})

解决方案 5:

Motif:*args作为**kwargs需要传递给函数调用的参数的占位符

使用*args**kwargs调用函数

def args_kwargs_test(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

现在我们将使用*args调用上面定义的函数

#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)  
>>> args_kwargs_test(*args)

结果:

参数 1:2

参数 2:3

参数 3:5


现在,使用**kwargs调用相同的函数

#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)

结果:

参数 1:5

参数 2:2

参数 3:3

底线:*args没有智能,它只是将传递的参数插入到参数中(按从左到右的顺序),同时**kwargs通过将适当的值放置在所需的位置来智能地行事

解决方案 6:

  • kwargsin**kwargs只是变量名。你可以有**anyVariableName

  • kwargs代表“关键字参数”。但我觉得它们应该被称为“命名参数”,因为这些只是与名称一起传递的参数(我认为“关键字参数”一词中的“关键字”没有任何意义。我猜“关键字”通常是指编程语言保留的词,因此程序员不能将其用作变量名。在 kwargs 的情况下,这里没有发生这种情况。)。因此,我们为传递给函数的两个参数值赋予名称
    param1和,param2如下所示:func(param1="val1",param2="val2"),而不是仅传递值:func(val1,val2)。因此,我觉得它们应该被适当地称为“任意数量的命名参数”,func因为如果具有签名,我们可以指定任意数量的这些参数(即参数)func(**kwargs)

因此,让我先解释一下“命名参数”,然后再解释“任意数量的命名参数” kwargs

命名参数

  • 命名参数应该遵循位置参数

  • 命名参数的顺序并不重要

  • 例子

def function1(param1,param2="arg2",param3="arg3"):
    print("
"+str(param1)+" "+str(param2)+" "+str(param3)+"
")

function1(1)                      #1 arg2 arg3   #1 positional arg
function1(param1=1)               #1 arg2 arg3   #1 named arg
function1(1,param2=2)             #1 2 arg3      #1 positional arg, 1 named arg
function1(param1=1,param2=2)      #1 2 arg3      #2 named args       
function1(param2=2, param1=1)     #1 2 arg3      #2 named args out of order
function1(1, param3=3, param2=2)  #1 2 3         #

#function1()                      #invalid: required argument missing
#function1(param2=2,1)            #invalid: SyntaxError: non-keyword arg after keyword arg
#function1(1,param1=11)           #invalid: TypeError: function1() got multiple values for argument 'param1'
#function1(param4=4)              #invalid: TypeError: function1() got an unexpected keyword argument 'param4'

任意数量的命名参数kwargs

  • 函数参数顺序:

1. 位置参数
2. 捕获任意数量参数的形式参数(以 * 为前缀)
3. 命名形式参数
4. 形式参数捕获任意数量的命名参数(以 ** 为前缀)
  • 例子

def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
    print("param1: "+ param1)
    print("param2: "+ param2)
    print("param3: "+ param3)
    print("custom tuple params","-"*10)
    for p in tupleParams:
        print(str(p) + ",")
    print("custom named params","-"*10)
    for k,v in dictionaryParams.items():
        print(str(k)+":"+str(v))

function2("arg1",
          "custom param1",
          "custom param2",
          "custom param3",
          param3="arg3",
          param2="arg2", 
          customNamedParam1 = "val1",
          customNamedParam2 = "val2"
          )

# Output
#
#param1: arg1
#param2: arg2
#param3: arg3
#custom tuple params ----------
#custom param1,
#custom param2,
#custom param3,
#custom named params ----------
#customNamedParam2:val2
#customNamedParam1:val1

传递元组和字典变量作为自定义参数

最后,我还要指出的是,我们可以通过

  • “形式参数捕获任意数量的参数”作为元组变量和

  • “形式参数捕获任意数量的命名参数”作为字典变量

因此可以按如下方式进行相同的调用:

tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}

function2("arg1",
      *tupleCustomArgs,    #note *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs     #note **
      )

最后请注意上面函数调用中的***。如果我们忽略它们,可能会得到错误的结果。

*省略元组参数:

function2("arg1",
      tupleCustomArgs,   #omitting *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs
      )

印刷

param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1

上面的元组('custom param1', 'custom param2', 'custom param3')按原样打印。

省略参数dict

function2("arg1",
      *tupleCustomArgs,   
      param3="arg3",
      param2="arg2", 
      dictCustomNamedArgs   #omitting **
      )

给出

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg

解决方案 7:

另外,你还可以在调用 kwargs 函数时混合使用不同的使用方式:

def test(**kwargs):
    print kwargs['a']
    print kwargs['b']
    print kwargs['c']


args = { 'b': 2, 'c': 3}

test( a=1, **args )

给出以下输出:

1
2
3

请注意,**kwargs 必须是最后一个参数

解决方案 8:

这是一个用于解释用法的简单函数:

def print_wrap(arg1, *args, **kwargs):
    print(arg1)
    print(args)
    print(kwargs)
    print(arg1, *args, **kwargs)

任何在函数定义中指定的参数将被放入args列表中,或者kwargs列表中,取决于它们是否是关键字参数:

>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah

如果添加从未传递给函数的关键字参数,则会引发错误:

>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function

解决方案 9:

kwargs 是一种语法糖,用于将名称参数作为字典传递(用于 func),或将字典作为命名参数传递(给 func)

解决方案 10:

以下是我希望对您有所帮助的示例:

#! /usr/bin/env python
#
def g( **kwargs) :
  print ( "In g ready to print kwargs" )
  print kwargs
  print ( "in g, calling f")
  f ( **kwargs )
  print ( "In g, after returning from f")

def f( **kwargs ) :
  print ( "in f, printing kwargs")
  print ( kwargs )
  print ( "In f, after printing kwargs")


g( a="red", b=5, c="Nassau")

g( q="purple", w="W", c="Charlie", d=[4, 3, 6] )

运行该程序时,您会得到:

$ python kwargs_demo.py 
In g ready to print kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
in g, calling f
in f, printing kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
In f, after printing kwargs
In g, after returning from f
In g ready to print kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
in g, calling f
in f, printing kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
In f, after printing kwargs
In g, after returning from f

这里的关键点是,调用中可变数量的命名参数转换为函数中的字典。

解决方案 11:

在 Python 中,关键字参数通常缩写为kwargs。在计算机编程中,

关键字参数是指计算机语言对函数调用的支持,它明确说明函数调用中每个参数的名称。

当不知道有多少关键字参数要传递给函数时,可以在参数名称前使用两个星号*kwargs 。在这种情况下,这被称为任意/通配符关键字参数。*

其中一个例子就是Django 的接收器函数。

def my_callback(sender, **kwargs):
    print("Request finished!")

请注意,该函数接受发送方参数以及通配符关键字参数 (**kwargs);所有信号处理程序都必须接受这些参数。所有信号都会发送关键字参数,并且可能会随时更改这些关键字参数。对于request_finished,它被记录为不发送任何参数,这意味着我们可能会倾向于将信号处理写为 my_callback(sender)。

这样做是错误的——事实上,如果你这样做,Django 会抛出错误。这是因为在任何时候参数都可能被添加到信号中,而你的接收器必须能够处理这些新参数。

请注意,它不必被称为kwargs,但它需要有 * (名称kwargs*是一种惯例)。

解决方案 12:

这是一个了解Python 解包的简单示例,

>>> def f(*args, **kwargs):
...    print 'args', args, 'kwargs', kwargs

例如1:

>>>f(1, 2)
>>> args (1,2) kwargs {} #args return parameter without reference as a tuple
>>>f(a = 1, b = 2)
>>> args () kwargs {'a': 1, 'b': 2} #args is empty tuple and kwargs return parameter with reference as a dictionary

解决方案 13:

在 Java 中,可以使用构造函数来重载类并允许多个输入参数。在 Python 中,可以使用 kwargs 来提供类似的行为。

Java示例: https: //beginnersbook.com/2013/05/constructor-overloading/

Python示例:

class Robot():
    # name is an arg and color is a kwarg
    def __init__(self,name, color='red'):
        self.name = name
        self.color = color

red_robot = Robot('Bob')
blue_robot = Robot('Bob', color='blue')

print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))

>>> I am a red robot named Bob.
>>> I am a blue robot named Bob.

这只是另一种思考方式。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用