问题
The following is invalid python:
def myInvalidFun(kw arg zero=6):
pass
The following is valid python:
def myValidFun(**kwargs):
if kwargs.has_key("kw arg zero"):
pass
To call myValidFun
, however, is tricky. For instance, the next few approaches do not work:
myValidFun(kw arg zero=6) # SyntaxError: invalid syntax
myValidFun("kw arg zero"=6) # SyntaxError: keyword can't be an expression
kwargs = dict("kw arg zero"=6) # SyntaxError: keyword can't be an expression
myValidFun(**kwargs)
(Perhaps the identical errors to the last two hint at what happens under the hood?) This, however, DOES work:
kwargs = {"kw arg zero": 6}
myValidFun(**kwargs)
Is there a reason why, in particular, myValidFun("kw arg zero"=6)
is not valid, in light of the {:} syntax for creating dictionaries?
(More background: I have a class which is much like a dictionary, only with significant amounts of validation, and an __init__
which builds a container using the entries of the dictionary, but is not a dictionary... it is actually an XML ElementTree, which is in some ways list-like and in others dict-like. The __init__
method must take keys like "my first element" and "my_first_element" and consider them different things. The class and __init__
work fine with **kwargs, but initializing my class is a multi-liner in the form of my example which does work, and seems like it could be simpler.)
edit: I understand the concept of identifiers, and my invalid code is there to make a point. I guess my question should be rephrased as:
Why is the following valid?:
myValidFun(**{"invalid identifier":6})
回答1:
Keywords to python functions must be valid identifiers. This is because on the other side, they need to be unpacked into identifiers (variables):
def foo(arg=3):
print arg
most of the things you have are not valid identifiers:
kw arg zero #Not valid identifier -- Can't have spaces
"kw arg zero" #Not valid identifier -- It's parsed as a string (expression)
Doing
dict("kw arg zero" = 6)
is no different to the parser than
myValidFunc("kw arg zero" = 6)
now as you've pointed out, You can pass things view mapping packing/unpacking (**kwargs
). However, it can only be accessed through a dictionary.
回答2:
myInvalidFun(kw arg zero=6):
is invalid because spaces are not allowed in identifiers.
myValidFun("kw arg zero"=6)
is invalid because functions expect the keywords to be valid variable names not strings. Some thing like "kw arg zero"=6
is also invalid because you can't assign a value to a string.
dict("kw arg zero"=6)
: Same as above. BTW dict()
accepts (key,value) pairs or an iterable.
This is valid because you only passed a dict here and dicts can strings as key with spaces.
def myValidFun(**kwargs): #using ** here simply packs the dictionary again
pass
myValidFun(**{"invalid identifier":6})
This is valid because you used a valid identifier in function definition
def myValidFun( foo = 5): #foo from dict replaces it's default value
print foo #prints 6
myValidFun(**{"foo":6})
Invalid:
def myValidFun(foo bar = 5): # syntax error, invalid identifier
print foo
myValidFun(**{"foo bar":6})
回答3:
your key names cannot have spaces. by putting quotes around the argument in your function call, an expression is evaluated
try this
def myValidFun(**kwargs):
if "kw_arg_zero" in kwargs:
print kwargs["kw_arg_zero"]
myValidFun(kw_arg_zero="whatever")
来源:https://stackoverflow.com/questions/16700006/feature-kwargs-allowing-improperly-named-variables