一尘不染

使用可以接受不是标识符的kwargs关键字参数的函数安全吗?

python

在Python中,将 不是 Python标识符的关键字参数赋予函数是否安全?这是一个例子:

>>> '{x-y}'.format(**{'x-y': 3})  # The keyword argument is *not* a valid Python identifier
'3'
>>> '{x-y}'.format(x-y=3)
  File "<ipython-input-12-722afdf7cfa3>", line 1
SyntaxError: keyword can't be an expression

我之所以这样问,是因为使用包含破折号的名称对我来说更方便格式化(因为这些值对应于命令行参数中带破折号的名称)。但是这种行为是否可靠(即在不同的Python版本之间是否可以变化)?

我不确定是否正式支持使用非标识符作为关键字参数:实际上,文档内容如下:

如果语法** expression出现在函数调用中,则expression必须计算为一个映射,该映射的内容被视为其他关键字参数。

…其中“关键字参数”被定义为具有 标识符 名称:

keyword_arguments :: = keyword_item(“,” keyword_item)*

keyword_item :: =标识符“ =”表达式

其中标识符在它们可以使用的字符限制(-例如是禁止的):

标识符:: =(字母|“ ”)(字母|数字|“ ”)*

因此,文档表明,**在函数调用中给定的映射应仅包含有效的标识符作为键,但是CPython
2.7接受更多通用键(对于format()和具有**参数的函数,它们不会将值放入变量中)。这是可靠的功能吗?


阅读 230

收藏
2021-01-20

共1个答案

一尘不染

首先:**{...}具有非标识符名称的调用约定仅在被调用函数具有**kw接收它们的参数的情况下才有效,因为它也无法定义不是有效标识符的显式关键字参数。

我要说的是,keyword_arguments语法仅适用于 源代码
的解析器,不能被视为对**expression结果内容的功能限制。下面的功能描述没有明确限制字典的键,功能定义文档也没有。

相反,因为语法允许的expression,功能规范规定,应该可以解决的映射 ,其中被视为额外的关键字参数的内容
,很显然(对我)有上的按键没有任何限制 可言
,超越适用于Python词典的普通键(键必须是不可变的)。您可以为所有Python护理传递元组或数字键。功能规格说明内容的处理方式,而不是内容必须符合特定格式。

因此,在我看来,功能规范必须 明确
限制**expression字典中的键以禁止您执行操作,因为语法肯定不会。进行更改将是一个巨大的向后不兼容的更改,并且不可能再添加。

请注意,即使规范未提及字典键的任何限制,CPython也会:

>>> def f(*args, **kw): print args, kw
... 
>>> f(**{1: 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() keywords must be strings

这是python解释器在调用代码对象(用户定义的函数)时做出的限制。在引发上述异常的部分之后的源代码中直接说明了原因:

/* Speed hack: do raw pointer compares. As names are
   normally interned this should almost always hit. */

通过将关键字限制为字符串,可以实现速度优化。

2021-01-20