Nicolas Gervais
Nicolas Gervais

Reputation: 36624

Iteratively creating variables: What are safe alternatives to globals()?

In S/O threads about iteratively creating variables, most replies suggest using globals(), but highlight the fact that it is dangerous to play with the global scope. Yet, locals() and vars() can also be used to iteratively create variables. For instance:

for i in range(1, 6):
    vars()[f'variable_{i}'] = i

print(key for key in vars().keys() if 'variable' in key)

Out[2]: ['variable_1', 'variable_2', 'variable_3', 'variable_4', 'variable_5']

Are locals() and vars() safe to iteratively create variables? If so, why are they never mentioned, as opposed to globals()?

Upvotes: 0

Views: 32

Answers (2)

javidcf
javidcf

Reputation: 59701

Not, it is not safe to use vars or locals that way. From the documentation:

vars:

Without an argument, vars() acts like locals(). Note, the locals dictionary is only useful for reads since updates to the locals dictionary are ignored.

locals:

Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

In the case of locals, one could give that note the interpretation that you should not change the existing contents in the returned dictionary (as opposed to introducing new contents). Still, nothing in the documentation suggests that introducing new values in the dictionary should have any effect.

Upvotes: 1

chepner
chepner

Reputation: 531125

Assigning to the output of vars doesn't actually modify the local scope; it just populates a mapping which you can only access via vars(). Observer:

>>> def bar():
...   for i in range(6):
...     vars()[f'var_{i}'] = i
...   print(vars()['var_3'])
...   print(var_3)
...
>>> bar()
3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in bar
NameError: name 'var_3' is not defined

Since you are already commited to mapping semantics, you may as well just use a dict:

def bar():
    data = {}
    for i in range(6):
        data[f'var_{i}'] = i
    print(data['var_3'])

Upvotes: 1

Related Questions