在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 :: =标识符“ =”表达式
keyword_arguments :: = keyword_item(“,” keyword_item)*
keyword_item :: =标识符“ =”表达式
其中标识符在它们可以使用的字符限制(-例如是禁止的):
-
标识符:: =(字母|“ ”)(字母|数字|“ ”)*
因此,文档表明,**在函数调用中给定的映射应仅包含有效的标识符作为键,但是CPython 2.7接受更多通用键(对于format()和具有**参数的函数,它们不会将值放入变量中)。这是可靠的功能吗?
**
format()
首先:**{...}具有非标识符名称的调用约定仅在被调用函数具有**kw接收它们的参数的情况下才有效,因为它也无法定义不是有效标识符的显式关键字参数。
**{...}
**kw
我要说的是,keyword_arguments语法仅适用于 源代码 的解析器,不能被视为对**expression结果内容的功能限制。下面的功能描述没有明确限制字典的键,功能定义文档也没有。
keyword_arguments
**expression
相反,因为语法允许的expression,功能规范规定,应该可以解决的映射 ,其中被视为额外的关键字参数的内容 ,很显然(对我)有上的按键没有任何限制 可言 ,超越适用于Python词典的普通键(键必须是不可变的)。您可以为所有Python护理传递元组或数字键。功能规格说明内容的处理方式,而不是内容必须符合特定格式。
expression
因此,在我看来,功能规范必须 明确 限制**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. */
通过将关键字限制为字符串,可以实现速度优化。