I know that most are not fans of using exec to do dynamic assignment. However, I would like to treat variable names as data for my purposes (both pragmatic and eccentric).
Consider this example, which I am using during a class initialization
Now I am going to dynamically assign to these variables
class Example(object):
__tree_dict = {"self.genomedir": "genomes",
"self.pre_align": "pre_alignment",
"self.alignments": "alignments",
"self.trimmed": "trimmed",
"self.prf_pre": "prf_preprocess",
"self.scaled": "scaled",
"self.csv": "csv"}
def __init__(self, rootdir):
self._rootdir = Path(rootdir)
self.outdir = self.mksubdir(self._rootdir, "out")
for variable, human_readable in self.__tree_dict.items():
try:
exec(variable + " = self.mksubdir(self.outdir,human_readable)")
except:
LOGGER.error("%s failed to initialize as %s, defaulting output to root" (variable, human_readable), exc_info=True)
exec(variable + '= Path(self._rootdir)')
This code will run, but I am not sure whether the exception handling will actually work, because when I add a finally statement to write the variable assignment to a logger, eg
finally:
LOGGER.info(variable + "set to %s" % getattr(self, variable))
the python interpreter raises
AttributeError: 'Example' object has no attribute 'self.csv'
(the attribute name changes at runtime, because the dictionary is not ordered - the attribute itself is not important)
The important problem is that when I reference the new variables outside the scope of the for loop, they are accessible w/ no attribute error. Their assignment has taken place and they are attributes of the class. These variables are found both in dir(self) and also by self.
What feature of python is at play here that prevents me from accessing these variables inside the for block (or the finally block)?
EDIT:
A self contained example:
class Example(object):
__vars_to_be_assigned: {"self.foo": "value", "self.bar": "not foo"}
def __init__(self):
for key, value in self.__vars_to_be_assigned:
try:
exec(key + " = value")
except:
print("Exception!")
else:
print(getattr(self, variable[5:]))
This example should raise an AttributeError