在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版本之间变化)?
我不确定是否正式支持使用非标识符作为关键字参数:事实上,documentation读取:
如果语法**表达式出现在函数调用表达式中 必须评估映射,其内容被视为 其他关键字参数。
...其中“关键字参数”被定义为具有标识符的名称:
keyword_arguments :: = keyword_item(“,”keyword_item)*
keyword_item :: = identifier“=”表达式
identifiers限制了他们可以使用的字符(例如-
是禁止的):
identifier :: =(letter |“_”)(字母|数字|“_”)*
因此,文档指出函数调用中给**
的映射只应包含有效的标识符作为键,但CPython 2.7接受更多通用键(对于format()
和函数带有{{ 1}}参数,不将值放在变量中)。这是一个可靠的功能吗?
答案 0 :(得分:5)
首先:具有非标识符名称的**{...}
调用约定仅在被调用函数具有**kw
参数的情况下才有效,因为它也无法定义无效的显式关键字参数标识符
我会说keyword_arguments
语法只适用于源代码的解析器,并且不能被视为对{{1}的内容的功能限制结果。下面的功能描述不会明确限制字典的键,function definition documentation也不会。
相反,由于语法允许**expression
,并且功能规范声明应解析为映射,其内容被视为附加关键字参数,因此很明显(对我来说,除了适用于Python词典的正常键(键必须是不可变的)之外,键没有任何限制。您可以传入所有Python关注的元组或数字键。功能规范说明了如何处理内容,而不是内容必须符合某种格式。
因此,在我看来,功能规范必须显式限制expression
字典中的键以禁止你正在做的事情,因为语法肯定不会。改变这将是一个巨大的向后不兼容的变化,并且不太可能被添加。
请注意,尽管规范没有提及对字典键的任何限制,但CPython确实:
**expression
这是python解释器在调用代码对象(用户定义的函数)时所做的限制。在引发上述异常的部分之后的the source code中解释了原因:
>>> 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
通过将关键字限制为字符串,可以实现速度优化。