Non-identifiers in dictionary keys for **expression syntax

Matthew Gilson m.gilson1 at gmail.com
Thu May 23 17:15:15 EDT 2013


On 05/23/2013 04:52 PM, Terry Jan Reedy wrote:
> 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 

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.



More information about the Python-list mailing list