Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Non-identifiers in dictionary keys for **expression syntax

14 views
Skip to first unread message

Matthew Gilson

unread,
May 23, 2013, 2:52:07 PM5/23/13
to pytho...@python.org
This is a question regarding the documentation around dictionary unpacking.  The documentation for the call syntax (http://docs.python.org/3/reference/expressions.html#grammar-token-call) says:

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

That's fine, but what is a keyword argument?  According to the glossary (http://docs.python.org/3.3/glossary.html):

"keyword argument: an argument preceded by an identifier (e.g. name=) in a function call or passed as a value in a dictionary preceded by **."

As far as I'm concerned, this leads to some ambiguity in whether the keys of the mapping need to be valid identifiers or not.

Using Cpython, we can do the following:

     def func(**kwargs):
          print kwargs

     d = {'foo bar baz':3}

So that might lead us to believe that the keys of the mapping do not need to be valid identifiers.  However, the previous function does not work with the following dictionary:

    d = {1:3}

because not all the keys are strings.  Is there a way to petition to get this more rigorously defined?

Thanks,
~Matt



Neil Cerutti

unread,
May 23, 2013, 3:20:44 PM5/23/13
to
On 2013-05-23, Matthew Gilson <m.gi...@gmail.com> wrote:
> That's fine, but what is a keyword argument? According to the glossary
> (http://docs.python.org/3.3/glossary.html):
>
> /"keyword argument/: an argument preceded by an identifier (e.g. name=)
> in a function call or passed as a value in a dictionary preceded by **."
>
> As far as I'm concerned, this leads to some ambiguity in
> whether the keys of the mapping need to be valid identifiers or
> not.

I don't see any ambiguity. A keyword argument is an argument
preceded by an identifier according to the definition. Where are
you perceiving wiggle room?

--
Neil Cerutti

Ethan Furman

unread,
May 23, 2013, 3:37:18 PM5/23/13
to pytho...@python.org
--> def func(**kwargs):
... print(kwargs)
...

--> d = {'foo bar baz':3}

--> func(**d)
{'foo bar baz': 3}

Even though 'foo bar baz' is not a valid identifier, and could not be passed as `func(foo bar baz = 3)`, it still worked
when going through a dict.

--
~Ethan~

Ian Kelly

unread,
May 23, 2013, 4:22:28 PM5/23/13
to Python
On Thu, May 23, 2013 at 12:52 PM, Matthew Gilson <m.gi...@gmail.com> wrote:
> Using Cpython, we can do the following:
>
> def func(**kwargs):
> print kwargs
>
> d = {'foo bar baz':3}
>
> So that might lead us to believe that the keys of the mapping do not need to
> be valid identifiers. However, the previous function does not work with the
> following dictionary:
>
> d = {1:3}
>
> because not all the keys are strings. Is there a way to petition to get
> this more rigorously defined?

The string requirement is probably for optimization, but if the
argument is both sent and received using the ** syntax, is there a
good reason why only identifiers should be allowed?

Matthew Gilson

unread,
May 23, 2013, 4:49:19 PM5/23/13
to pytho...@python.org
The wiggle room comes from the "or passed as a value in a dictionary"
clause. We sort of get caught in a infinite loop there because the
stuff that can be passed in a dictionary is a keyword which is an
identifer=expression or something passed as a value in a dictionary ...

Also the fact that:

func(**{"foo bar baz":1})

works even though `foo bar baz` isn't a valid identifier, but:

func(**{1:3})

doesn't work.

Terry Jan Reedy

unread,
May 23, 2013, 4:52:11 PM5/23/13
to pytho...@python.org
On 5/23/2013 2:52 PM, Matthew Gilson wrote:
> This is a question regarding the documentation around dictionary
> unpacking. The documentation for the call syntax
> (http://docs.python.org/3/reference/expressions.html#grammar-token-call)
> says:
>
> "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."
>
> That's fine, but what is a keyword argument? According to the glossary
> (http://docs.python.org/3.3/glossary.html):
>
> /"keyword argument/: an argument preceded by an identifier (e.g. name=)
> in a function call or passed as a value in a dictionary preceded by **."

It appears that the requirement has been relaxed (in the previous
quote), so that 'dictionary' should also be changed to 'mapping'. It
might not hurt to add 'The key for the value should be an identifier.'
>
> As far as I'm concerned, this leads to some ambiguity in whether the
> keys of the mapping need to be valid identifiers or not.

I think you are being too lawyerly. The pretty clear and sensible
implication is that the key for the value should be a string with a
valid identifier. If it is anything else, you are on your own and
deserve any joy or pain that results ;=)

> Using Cpython, we can do the following:
>
> def func(**kwargs):
> print kwargs
>
> d = {'foo bar baz':3}
>
> So that might lead us to believe that the keys of the mapping do not
> need to be valid identifiers.

There are two ways to pass args to func to be gathered into kwargs;
explicit key=val pairs and **mapping, or both.
func(a=1, b='hi', **{'foo bar baz':3})
#
{'foo bar baz': 3, 'a': 1, 'b': 'hi'}

So func should not expect anything other than identifier strings.

However, the previous function does not
> work with the following dictionary:
>
> d = {1:3}
>
> because not all the keys are strings.

So CPython checks that keys are strings, because that is cheap, but not
that the strings are identifiers, because that would be more expensive.
Just because an implementation allow somethings (omits a check) for
efficiency does not mean you should do it.

globals()[1] = 1
works, but is not normally very sensible or useful.

> Is there a way to petition to get this more rigorously defined?

bugs.python.org
The problem is that mandating a rigorous check by implementations makes
Python slower to the detriment of sensible programmers.




Matthew Gilson

unread,
May 23, 2013, 5:15:15 PM5/23/13
to pytho...@python.org
To be clear, you're saying that

func(**{'foo bar baz':3})

is not supported (officially), but it works in CPython because checking
that every string in the dict is a valid identifier would be costly. Of
course that is sensible and I don't think the behaviour should be
changed "to the detriment of sensible programmers". However, it would
be nice if it was documented somewhere that the above function call is
something that a non-sensible programmer would do. Perhaps with a
"CPython implementation detail" type of block.
0 new messages