繁体   English   中英

python 使用 *args 和 **kwargs 以及其他仅位置和关键字参数解包 arg 列表

[英]python unpacking arg list with *args and **kwargs along with other positional and keyword only params

我在名为 kwargs.py 的文件中定义了以下 function。 (将模块更改为 unpacking.py 使 function 按预期工作)。 请参阅问题底部的图像。

def tag(name, *content, cls=None, **attrs):
    if cls is not None:
        attrs['class'] = cls
    
    if attrs:
        attr_str = ''.join(' %s="%s"' % (key,val) 
                                         for key, val 
                                         in sorted(attrs.items()))
    else:
        attr_str = ''
    
    if content:
        return '\n'.join('<%s%s>%s</%s>' % (name,attr_str,c,name) for c in content)
    else:
        return '<%s%s />' % (name,attr_str)

执行此操作时

tag('div', 'testing', cls='test', **dict(id=33,alt='this is a test'))

我得到的结果是

'<div alt="this is a test" class="test" id="33">testing</div>'

但是当我执行这个

tag(**dict(name='div', content=('testing','and testing'), cls='test', id=33, alt='this is a test'))

我只得到

'<div alt="this is a test" class="test" id="33" />'

为什么要分配参数name但未分配content (即使元组没有解包,我也希望至少元组本身被分配给 content[0])。

我在这里想念什么?

编辑: Windows 10 中的 Python 3.8.3 x86 在此处输入图像描述

*content不是论据。 你不能给它分配任何东西。

文档确实没有明确解释。 它只是一个可以在 function 主体中使用的变量。 它的作用是“收集所有剩余的输入参数”。

通常,这些可变参数 arguments 将在形式参数列表中排在最后,因为它们会收集传递给 function 的所有剩余输入 arguments。

https://docs.python.org/3/tutorial/controlflow.html#arbitrary-argument-lists

本 function

def func(*args, **kwargs):
    print("args", args)
    print("kwargs", kwargs)


func(args=[1, 2, 3])

将打印

args ()
kwargs {'args': [1, 2, 3]}

编辑:

你的例子是错误的。 您无法获得不同的 output。

对于这个 function

def tag(name, *content, cls=None, **attrs):
    if cls is not None:
        attrs['class'] = cls
    if attrs:
        attr_str = ''.join(' %s="%s"' % (key, val)
                           for key, val
                           in sorted(attrs.items()))
    else:
        attr_str = ''

    if content:
        resp = '\n'.join('<%s%s>%s</%s>' % (name, attr_str, c, name) for c in content)
    else:
        resp = '<%s%s />' % (name, attr_str)

    print("name", name)
    print("*content", content)
    print("cls", cls)
    print("attrs", attrs)
    print("attrs_str", attr_str)
    print("resp", resp)
    print('-'*10)
   
    return resp

如果你运行这个

tag('div', 'testing', cls='test', **dict(id=33, alt='this is a test'))
tag(**dict(name='div', content=('testing','and testing'), cls='test', id=33, alt='this is a test'))

你得到

name div
*content ('testing',)
cls test
attrs {'id': 33, 'alt': 'this is a test', 'class': 'test'}
attrs_str  alt="this is a test" class="test" id="33"
resp <div alt="this is a test" class="test" id="33">testing</div>
----------
name div
*content ()
cls test
attrs {'content': ('testing', 'and testing'), 'id': 33, 'alt': 'this is a test', 'class': 'test'}
attrs_str  alt="this is a test" class="test" content="('testing', 'and testing')" id="33"
resp <div alt="this is a test" class="test" content="('testing', 'and testing')" id="33" />
----------

所以你不应该在第二种情况下得到'<div alt="this is a test" class="test" id="33" />' 对于完全相同的 function,我得到<div alt="this is a test" class="test" content="('testing', 'and testing')" id="33" />

编辑2:可能您的名称空间已损坏,因为名称**kwargs经常以您在此处使用**attrs的方式在其他地方使用,因此更改此模块名称/直接导入 function 应该可以解决您的问题。

首先让我们确保我们使用相同的术语:

  • A function 声明参数(在您的示例中name, *content, cls=None, **attrs ),
  • 一个 function 调用接收arguments (例如'div', 'testing', cls='test', **dict(id=33, alt='this is a test') )。

然后将 arguments 绑定到参数,因此可以在 function 主体中访问它们。

首先让我们看一下 function 签名:

def tag(name, *content, cls=None, **attrs):
    ...

这个function定义了四个参数:

  • name - 位置或关键字参数,
  • content - 一个可变参数参数,它捕获任意数量的附加位置arguments,
  • cls - 具有默认值的仅限关键字的参数,
  • attrs - 一个关键字参数,它捕获任意数量的附加关键字arguments。

当您以下列方式调用此 function 时,会发生以下情况:

tag('div', 'testing', cls='test', **dict(id=33, alt='this is a test'))
  • 'div'绑定到name
  • 'testing'content捕获,产生一个 1 元组,
  • 'test'绑定到cls
  • id=33, alt='this is a test'attrs捕获。

现在关于*content**attrs参数的特殊之处在于它们捕获任意数量的多余 arguments 但它们不能直接绑定。 即你不能绑定content=(1, 2) 相反,如果你传递tag('foo', 1, 2)这个绑定会自动发生。 因此,如果您通过以下方式调用 function:

tag(**dict(name='div', content=('testing', 'and testing'), cls='test', id=33, alt='this is a test'))

然后所有 arguments 都由关键字提供,因此除namecls之外的所有内容都由attrs捕获。 这是因为*content仅捕获位置arguments。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM