Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
412 views
in Technique[技术] by (71.8m points)

python - Is is safe to use a function accepts kwargs keyword arguments that are not identifiers?

In Python, is it safe to give keyword arguments that are not Python identifiers to a function? Here is an example:

>>> '{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

I am asking this because it is more convenient for me to format with names that contain a dash (because the values correspond to command-line argument with dashes in their name). But is this behavior reliable (i.e. can it vary between version of Python)?

I am not sure that using non-identifiers as keyword arguments is officially supported: in fact, the documentation reads:

If the syntax **expression appears in the function call, expression must evaluate to a mapping, the contents of which are treated as additional keyword arguments.

… where "keyword arguments" are defined as having a name which is an identifier:

keyword_arguments ::= keyword_item ("," keyword_item)*

keyword_item ::= identifier "=" expression

where identifiers are restricted in what characters they can use (- is for instance forbidden):

identifier ::= (letter|"_") (letter | digit | "_")*

So, the documentation indicates that the mapping given to ** in a function call should only contain valid identifiers as keys, but CPython 2.7 accepts more general keys (for format() and functions with a ** argument, which do not put values in variables). Is this a reliable feature?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

First of all: the **{...} call convention with non-identifier names only works if the called function has a **kw argument to receive them, as it too cannot define explicit keyword arguments that are not valid identifiers.

I'd say that the keyword_arguments grammar only applies to the parser of the source code, and cannot ever be seen as a functional restriction on the contents of the **expression result. The functional description below does not restrict the keys of the dictionary explicitly, nor does the function definition documentation.

Instead, since the grammar allows an expression, and the functional spec states that that should resolve to a mapping the contents of which are treated as additional keyword arguments, it is clear (to me) that there are no restrictions on the keys at all, beyond the normal ones applicable to Python dictionaries (keys must be immutable). You can pass in tuple or numeric keys for all Python cares. The functional spec states how the contents are treated, not that the contents must fit a certain format.

So, in my opinion the functional spec would have to explicitly restrict the keys in the **expression dictionary to disallow what you are doing, because the grammar certainly does not. Changing that would be a huge backwards-incompatible change, and is not likely to ever be added.

Note that even though the spec doesn't mention any restrictions on the keys of the dictionary, CPython does:

>>> 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

This is a restriction made by the python interpreter when invoking code objects (user defined functions). The reason why is explained in the source code right after the part that raises the above exception:

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

By restricting keywords to strings a speed optimisation is possible.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...