I am looking for an easy test to see if a given string is a valid Python identifier that is not a reserved keyword. It will be used in an exec
statement in a function call.
Checking with a regex for an identifier, e.g. [A-Za-z_][A-Za-z0-9_]*
, isn't enough, because it could be a Python keyword like for
or and
:
>>> def f(**kwargs):
... return kwargs
...
>>> f(x=3, y=4)
{'y': 4, 'x': 3}
>>> f(zip-zop=4)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression
>>> f(for=4)
File "<stdin>", line 1
f(for=4)
^
SyntaxError: invalid syntax
>>> f(and=4)
File "<stdin>", line 1
f(and=4)
^
SyntaxError: invalid syntax
Is there a way to do this without using an additional exec call? (or other evaluation-based method; see below for an exec
-based approach)
>>> import re
>>> ident_re = re.compile('[A-Za-z_][A-Za-z0-9_]*')
>>> def testarg(arg):
... if not ident_re.match(arg):
... return False
... try:
... exec('dict(%s=None)' % arg) # safe because we know it's an identifier
... except SyntaxError:
... return False
... return True
...
>>> testarg('!!')
False
>>> testarg('hey')
True
>>> testarg('for')
False
>>> testarg('in')
False
>>> testarg('and')
False