user2610645
user2610645

Reputation: 33

SyntaxError: keyword can't be an expression while creating a dictionary

I got two strings retrieved from a cookie

name = 'rack.session'
val = 'CookieVal'

Using them I would like to build a dictionary

cookies = dict(rack.session=val)

but SyntaxError: keyword can't be an expression

So I tried to escape the (.) dot

re.escape(name)

... but it raises the same error

How is this possible? According to Python type() name is a string:

type(name)
 <class 'str'>

Why is Python mixing up strings and expressions?

Upvotes: 3

Views: 13404

Answers (7)

AndreyGS
AndreyGS

Reputation: 151

The answer from Ashwini Chaudhary was quite good, but I can add more to clarify question.

The main reason why you've got this error is because your expression contain a point - '.' symbol. And raising error directly say that: "keyword can't be an expression".

This - '.' symbol makes Python think, that current keyword name is not a valid name, but an expression, that you try to evaluate. Generally speaking you may pass as a key in dict() only valid name, from the point that such names could be a names for a variables dispite the fact that no variable evaluation actually can be happen here.

So your keys must contain only alphabeticals, digits, or underscore, and do not start with a digit (they must be valid Python identifiers as was said before).

For example these are not valid:

d = dict(1='Bob')
d = dict(b.a='Bob')
d = dict('b'='Bob')
d = dict(b$='Bob')

First, second and third are not valid, because they are expressions and because they are not valid identifiers, but fourth only because it is not a valid identifier.

To circumvent current limitations you may use one of the ways that was mentioned above, cause they accepting variable evaluation and if the key is the string, it can contain any characters:

d = dict([(1, 'Bob')])
d = dict(zip([1],['Bob']))
d = {1:'bob'}

or this one:

d = dict.fromkeys([1])
d[1] = 'Bob'

And for example of key value evaluation difference:

x = 1
d = dict(x='Bob')
d
{'x': 'Bob'}

x = 1
d = dict([(x, 'Bob')])
d
{1: 'Bob'}

Upvotes: 0

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 251116

The problem with rack.session is that python thinks that you're trying to use the value of expression rack.session and pass it to dict(), which is incorrect because dict() expects you to pass variables names when you're using keyword arguments, these variables name are then converted to strings when the dict is created.

Simple example:

>>> dict('val' = 'a')     
  File "<ipython-input-21-1cdf9688c191>", line 1
SyntaxError: keyword can't be an expression

So, you can't use an object on the left side of =, you can only use a valid identifier.

Byte code makes it even more clear what happens with rack.session:

>>> import dis
>>> dis.dis(lambda : dict(rack.session , val))
  1           0 LOAD_GLOBAL              0 (dict)
              3 LOAD_GLOBAL              1 (rack)   # load the object `rack`
              6 LOAD_ATTR                2 (session)# use the value of it's attribute
                                                    # `session`
              9 LOAD_GLOBAL              3 (val)
             12 CALL_FUNCTION            2
             15 RETURN_VALUE   

So, with rack.session = val, python will think that you're trying to use the value returned from rack.session and pass it to dict, which is incorrect. Secondly rack.session isn't a valid identifier as dots(.) are not allowed in python identifiers.

This is applicable to any function in python not even dict, a keyword argument must be a valid identifier.

From the docs:

keyword_item   ::=  identifier "=" expression

Valid examples:

>>> dict(foo = 1, bar = '2')
{'foo': 1, 'bar': '2'}

For your example you can simply do:

>>> val = 'CookieVal'
>>> name = 'rack.session'
>>> dict(((name,val),))
{'rack.session': 'CookieVal'}
#or
>>> {name:val}
{'rack.session': 'CookieVal'}

Upvotes: 9

kiriloff
kiriloff

Reputation: 26333

You should build a dictionary this way

name = 'rack.session'
val = 'CookieVal'

d = {name: val}

print d

gives you

>>> 
{'rack.session': 'CookieVal'}
>>> 

More on dictionaries http://docs.python.org/2/tutorial/datastructures.html#dictionaries

Upvotes: 1

jh314
jh314

Reputation: 27812

The reason is that you give the dict this expression: rack.session=val, rather than a keyword.

Instead, you can get around this issue using dict({name: val}), where the argument is {name:val}. Of course, you could just use {name: val}.

The python docs shows several ways to create dicts.

Upvotes: 0

Marcin
Marcin

Reputation: 49866

name = 'rack.session'
val = 'CookieVal'
cookies = dict([(name,val)])
morecookies = {name:val}

As to "Why is Python mixing up strings and expressions?", it's not. I'm not sure why you think python is doing this. You are mixing up strings and variables, which are quite different.

Upvotes: 1

Frodon
Frodon

Reputation: 3775

Try this:

name = 'rack.session'
val = 'CookieVal'
cookies = dict(zip([name],[val]))

Edit: my case is too much for your case

cookies = {name:val}

is enough

Upvotes: -1

alecxe
alecxe

Reputation: 474131

>>> name = 'rack.session'
>>> val = 'CookieVal'
>>> cookies = {name: val}
>>> cookies
{'rack.session': 'CookieVal'}

Upvotes: 1

Related Questions