tldr; see the final line; the rest is just preamble.
I am developing a test harness, which parses user scripts and generates a Python script which it then runs. The idea is for non-techie folks to be able to write high-level test scripts.
I have introduced the idea of variables, so a user can use the LET
keyword in his script. E.g. LET X = 42
, which I simply expand to X = 42
. They can then use X later in their scripts - RELEASE CONNECTION X
But what if someone writes LET 2 = 3
? That's going to generate invalid Python.
If I have that X
in a variable variableName
, then how can I check whether variableName
is a valid Python variable?
A valid variable name begins with a letter and contains not more than namelengthmax characters. Valid variable names can include letters, digits, and underscores.
Given a string, write a Python program to check if it is a valid identifier or not. An identifier must begin with either an alphabet or underscore, it can not begin with a digit or any other special character, moreover, digits can come after.
A variable name must start with a letter or the underscore character. A variable name cannot start with a number. A variable name can only contain alpha-numeric characters and underscores (A-z, 0-9, and _ ) Variable names are case-sensitive (age, Age and AGE are three different variables)
If you want to check that a variable is explicitly True or False (and is not truthy/falsy), use is ( if variable is True ). If you want to check if a variable is equal to 0 or if a list is empty, use if variable == 0 or if variable == [] .
In Python 3 you can use str.isidentifier()
to test whether a given string is a valid Python identifier/name.
>>> 'X'.isidentifier()
True
>>> 'X123'.isidentifier()
True
>>> '2'.isidentifier()
False
>>> 'while'.isidentifier()
True
The last example shows that you should also check whether the variable name clashes with a Python keyword:
>>> from keyword import iskeyword
>>> iskeyword('X')
False
>>> iskeyword('while')
True
So you could put that together in a function:
from keyword import iskeyword
def is_valid_variable_name(name):
return name.isidentifier() and not iskeyword(name)
Another option, which works in Python 2 and 3, is to use the ast
module:
from ast import parse
def is_valid_variable_name(name):
try:
parse('{} = None'.format(name))
return True
except SyntaxError, ValueError, TypeError:
return False
>>> is_valid_variable_name('X')
True
>>> is_valid_variable_name('123')
False
>>> is_valid_variable_name('for')
False
>>> is_valid_variable_name('')
False
>>> is_valid_variable_name(42)
False
This will parse the assignment statement without actually executing it. It will pick up invalid identifiers as well as attempts to assign to a keyword. In the above code None
is an arbitrary value to assign to the given name - it could be any valid expression for the RHS.
EDIT: this is wrong and implementation dependent - see comments.
Just have Python do its own check by making a dictionary with the variable holding the name as the key and splatting it as keyword arguments:
def _dummy_function(**kwargs):
pass
def is_valid_variable_name(name):
try:
_dummy_function(**{name: None})
return True
except TypeError:
return False
Notably, TypeError
is consistently raised whenever a dict
splats into keyword arguments but has a key which isn't a valid function argument, and whenever a dict
literal is being constructed with an invalid key, so this will work correctly on anything you pass to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With