225

I want to create variables dynamically in Python. Does anyone have any creative means of doing this?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Noah R
  • 5,287
  • 21
  • 56
  • 75

8 Answers8

208

Unless there is an overwhelming need to create a mess of variable names, I would just use a dictionary, where you can dynamically create the key names and associate a value to each.

a = {}
k = 0
while k < 10:
    # dynamically create key
    key = ...
    # calculate value
    value = ...
    a[key] = value 
    k += 1

There are also some interesting data structures in the collections module that might be applicable.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
JoshAdel
  • 66,734
  • 27
  • 141
  • 140
  • 13
    @Josh and others... Creating an item (key,value) in a dictionary `a` isn't very different from creating the same in `locals()` or `globals()` that are implemented as dictionaries too. I wonder why I have been downvoted by some downvote sniper for my answer creating an item in `globals()` while the answer of Gintautas Miliauskas is upvoted and this answer that doesn't give the how-to for ` ` is upvoted 3 times. – eyquem Feb 18 '11 at 02:10
  • 2
    @eyquem I did not give any specific way to create the key because I know nothing about the naming scheme the OP needs in practice. Instead I just gave the most generic and clean scheme possible to solve the problem. – JoshAdel Feb 18 '11 at 02:36
  • @Josh You're right. The question is too short. I had the same problem to answer, and that's why I used random to create the names and the values – eyquem Feb 18 '11 at 02:41
  • 3
    @eyquem local variables aren't implemented as dictionaries. Almost always, the `locals()` function creates a dictionary from the local variables but the dictionary doesn't exist unless you call `locals()`. – Duncan Feb 18 '11 at 08:20
  • @Duncan Interesting; have you some reference where I can learn more about what you write, please. By the way, it's not "variables" that are implemented as dictionaries, it's namespaces; see the quotation I made in a comment to John Machin's answer. Where do the local names ly before any call of locals() ? – eyquem Feb 18 '11 at 13:33
  • 3
    @eyquem, the local namespace is implemented as slots on the stack so the bytecode can reference them directly as offsets in the stack frame (plus free variables which are also included when you call `locals()`. The exception is in Python 2.x when you use `exec` inside a function without specifying a local namespace for the exec. I'm not sure offhand where this is documented: it isn't part of the language definition because different implementations can choose differently how to implement the locals namespace. – Duncan Feb 18 '11 at 15:30
  • @Duncan Thank you very much for your answer. I am very interested by the innards of Python and the details of the execution of code. I now have much information to study. Thank you. – eyquem Feb 18 '11 at 16:24
  • 2
    This is the best answer. This should be the canonical question as a result. – Marcin Aug 15 '14 at 16:54
  • There are perfectly good (if rare) cases where inserting via ``globals()[name]=value`` is the best alternative. I have encountered this twice in actual practice (over several years of professional programming). I have no problem with warning the reader that using a dictionary is probably the better way, but it is not the actual answer to the question. The goal here is to answer questions, not enforce python coding purity. Don't let's reach so high that we fall down ;-) – stochastic Jan 26 '15 at 23:17
  • how do you programatically create the NAMES of variables (i.e. `NAME = value`)??? – oldboy Jun 28 '18 at 22:56
  • My approach is.., new_var = `eval('old_var' + str(count))` – Shirjeel Ahmed Khan Apr 26 '19 at 05:43
  • What if you want to use these variables inside a function to define equations that then you want to solve numerically? – jpcgandre May 04 '22 at 18:01
115

globals() returns a dictionary of the module's variables. You can create a new variable by creating a key on that dictionary:

# By default, a module has some hidden variables defined
print({k: v for k, v in globals().items() if not k.startswith("__")})

for i in range(1, 11):
    globals()[f"my_variable_{i}"] = i

print()
print(my_variable_1)
print(my_variable_2)
# and so on

print()
print({k: v for k, v in globals().items() if not k.startswith("__")})

Result:

{}

1
2

{'i': 10, 'my_variable_1': 1, 'my_variable_2': 2, 'my_variable_3': 3, 'my_variable_4': 4, 'my_variable_5': 5, 'my_variable_6': 6, 'my_variable_7': 7, 'my_variable_8': 8, 'my_variable_9': 9, 'my_variable_10': 10}
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
eyquem
  • 26,771
  • 7
  • 38
  • 46
  • @Ned Batchelder Thank you to respond. The question is misguided ?! – eyquem Feb 18 '11 at 02:16
  • 4
    The OP needs a way to create many values associated with many names. He worded that as "dynamically create variables," but using a dictionary is the right way to solve his real problem. – Ned Batchelder Feb 18 '11 at 02:22
  • 50
    @Ned Batchelder Maybe the question is misguided. But I think it could be better for him to receive two answers: 1- yes you can do what you want 2- but the way you want to enter in isn't a godd one for this ans that reason. Doing so, the OP would learn two things: that Python is powerfull, and some advice to code correctly. On the contrary, if anybody is prevented to think by his own and to think about a problem, it is a restraint put on brain_storming and reflexion – eyquem Feb 18 '11 at 02:25
  • @Ned Batchelder I find his question very short to be sure in his place of what he needs and what he doesn't – eyquem Feb 18 '11 at 02:26
  • 14
    I think the reason you are being downvoted is because spamming keys in to the globals dict is generally not considered a best practice. In fact in your own code example, what would you suppose happens if your random key generator were to generate a key that was already in the globals dict (for example the key "alphabet"). Also, I think it was implied by the OPs question that he would need to get his "variables" after they were created. How can he differentiate his dynamic variables from the ones that already existed in global scope using your solution? A separate dict is better in this case. – apiguy Feb 18 '11 at 06:05
  • 2
    @free-dom Thank you. There are 3 different points in your words. 1) _not well considered_ isn't an explanatory argument, even not an authoritative one, it is an argument of "most commonly thought" style. It isn't enough for me 2) Yes there're latent problems in my code but my goal wasn't to anticipate all the consequences of a rapidly written code, it was just to show to Noah that it's possible to do what he asked for. The interest of SO is that if one solution is not very good, it will be underlined by some other in a debate. And if the OP needs complementary corrections, they'll be given – eyquem Feb 18 '11 at 10:56
  • 1
    @free-dom 3) _How can he differentiate_ ? It's also a problem attached to the particular way i choosed to make my example, not a problem linked with the nature of globals(). It could be that Noah would have a list of names in which the object's names would be choosen and would be found after the insertion in globals(). In this case there wouldn't exist a difficulry to find them. I will post codes to treat the solutions to this two problems. So it's not an absolute argument against the use of globals() – eyquem Feb 18 '11 at 10:58
  • 1
    @free-dom So, in the end, I think there is still no real and developped argument against this use. Saying _using a dictionary is the right way to solve his real problem_ without more explanation, even from authoritative Ned B, (how does he know what is his REAL problem, by the way?), and relative defaults of my particular code are not sufficient talks to convince me. At the moment, I still don't know why my solution is counter-productive and why globals() is widely considered as bad as it is. – eyquem Feb 18 '11 at 11:01
  • 3
    While possibly not the best presented solution, this is a valid answer. +1. I actually used this to answer this question [here](http://stackoverflow.com/questions/11748780/is-it-possible-something-like-lvalue-of-perl-or-setf-of-lisp-in-python/11750015#11750015). Not only this, but the same concept can be applied to using locals(). You are all right, eyquem's example should never be used verbatim, but eyquem does not need to write the project for the OP. The OP should make sure that `somevar not in globals()` before attempting to use this method. – Logan Jul 31 '12 at 22:43
  • 28
    It's a good answer. I stumbled upon the answer with a legitimate need to do this, preventing me from having to write a nearly duplicated question. – acjay Mar 06 '13 at 13:27
  • 1
    @Ned: To start with, let me acknowledge all the good things you do for the coders community. But I also think down-voting is an overkill. You know, sometimes there could be more than one person seeking for an answer to a similar question. ( BTW, personally I prefer to use `compile`/`exec`. Of course, avoiding it as much as possible. But nevertheless. Sometimes quick and dirty is just the right thing ) ) – ジョージ Sep 18 '13 at 10:13
  • 1
    I agree. He answered a question directly and solved my slightly different, legitimate, need as well. This should be upvoted not downvoted. – Inversus Apr 27 '14 at 03:11
  • 1
    This is an absolutely awful idea - not only are globals a bad idea in the first place (IMHO), this idea just creates more code mess, with very little gain. It might work, but why would you do it. – Tony Suffolk 66 Jul 02 '14 at 18:29
  • 1
    This is an amazing solution for people wanting to write runtime dynamic codes. Creating variables on-the-fly may be necessary in certain cases, and having a safe way to do it without requiring the use of the evil exec is great. This should be more upvoted. – gaborous Mar 07 '15 at 20:50
  • 1
    OK, can you give me a good example of the need to create dynamic variables? I'm not saying there aren't any, but they are few and far between (and use of `exec` or assignment via `globals()` is almost always a code smell). – holdenweb Jun 04 '15 at 08:25
  • 6
    It is worth pointing out that this answers provides the way to dynamically create *global* variables. This means that every variable defined on `globals()` will go on the module namespace and stay there until the end of the program. Most of the times when one says "variable" they mean a *function local* variable, which only exists in the context of the execution of a function. In this case `globals()` is likely not the solution to the problem. Consider explicitly using a dictionary, as in the answer provided by JoshAdel. – Davide R. Jun 29 '15 at 12:39
  • Should you want to add a simple variable: ```key_name = 'my_new_variable' value = '2019-10-25T06:09:32-07:00' globals()[key_name] = last_modified``` – theStud54 Nov 05 '19 at 12:05
  • Thanks! This taught me what I wanted!! – Seth Jul 07 '23 at 20:57
83

Use the exec() method to run arbitrary code. For example, say you have a dictionary and you want to turn each key into a variable with its original dictionary value, you can do the following:

>>> c = {"one": 1, "two": 2}
>>> for k, v in c.items():
...     exec(f"{k} = {v}")
... 
>>> one
1
>>> two
2
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
chris-piekarski
  • 1,088
  • 8
  • 6
  • 1
    Yes, this would work, but I don't know why you would do this - remember Explicit is better than implicit, and "Readability Counts". This is just a bad idea IMHO. – Tony Suffolk 66 Jul 02 '14 at 18:31
  • 8
    @chris-piekarski Thanks for this answer. One reason for wanting to do such thing is when you need to communicate with a 3rd-party software that expects inputs passed as local variables, and at compile time you don't know the variables that it expects (I'm creating a Paraview plugin, for example, and it imposes this kind of constraints). – Daniel Jan 08 '15 at 17:42
  • 4
    Be aware that this will not work in Python 3 within a function execution context. It still is fine in the top level (module) context. If you need to create a module variable, I would suggest editing the `globals()` dict, or calling `setattr()` on the module object. – Davide R. Jun 29 '15 at 12:44
  • 2
    Let me also underline that, in general, this poses a security risk when the keys or values are provided by external data (user input, a file or anything). The usual warnings when using eval/exec apply. You don't want someone to set the value to `"send_me_all_your_private_data()"` and get it executed on your machine. – Davide R. Jun 29 '15 at 12:48
  • 4
    Actually, this is a very good answer, and the only solution in specific circumstances. Say you have an array that represents an inventory. Say this inventory can have containers inside of it, and these containers has an inventory of its own, representing the items the container is holding. This is the only way that I know of to be able to store INDEXES in a string, and be able to change it, and access different indexes dynamically, e.g. if you change which container you are looking inside of. – Douglas Nov 16 '16 at 19:38
  • 1
    `exec` is bad practice, otherwise good – U13-Forward Oct 09 '18 at 10:20
  • This doesn't work with values that are strings. – AleB Nov 30 '20 at 13:56
  • This is a good idea when your python code needs to communicate with a another environment altogether. For instance if my python code with HP Prime calculator need to pass variables to HP Prime native variables – nightcrawler Nov 01 '22 at 16:09
40

Stuffing things into the global and/or local namespaces is not a good idea. Using a dict is so some-other-language-ish ... d['constant-key'] = value just looks awkward. Python is OO. In the words of a master: """Namespaces are one honking great idea -- let's do more of those!"""

Like this:

>>> class Record(object):
...     pass
...
>>> r = Record()
>>> r.foo = 'oof'
>>> setattr(r, 'bar', 'rab')
>>> r.foo
'oof'
>>> r.bar
'rab'
>>> names = 'id description price'.split()
>>> values = [666, 'duct tape', 3.45]
>>> s = Record()
>>> for name, value in zip(names, values):
...     setattr(s, name, value)
...
>>> s.__dict__ # If you are suffering from dict withdrawal symptoms
{'price': 3.45, 'id': 666, 'description': 'duct tape'}
>>>
Hack-R
  • 22,422
  • 14
  • 75
  • 131
John Machin
  • 81,303
  • 11
  • 141
  • 189
  • 2
    I don't understand what you want to say. Why global and local namespaces are not good ideas ? Because _"most namespaces are currently implemented as Python dictionaries"_ ? and that dictionaries are _"some-other-language-ish"_ ? Why this criticism about dictionaries ? You think that the namespace of an instance is a better thing to use than a dictionary ? Well... do you know that: – eyquem Feb 18 '11 at 03:20
  • 4
    _"A namespace is a mapping from names to objects. **Most namespaces are currently implemented as Python dictionaries**, but that's normally not noticeable in any way (except for performance), and it may change in the future. Examples of namespaces are: the set of built-in names (functions such as abs(), and built-in exception names); the global names in a module; and the local names in a function invocation. **In a sense the set of attributes of an object also form a namespace.** "_ – eyquem Feb 18 '11 at 03:21
  • (http://docs.python.org/release/2.5/tut/node11.html#SECTION0011200000000000000000) The author is GvR himself, it's written in the 2.5 version, but not later, that's why I give this link – eyquem Feb 18 '11 at 03:25
  • It seems there is no salvation outside dictionaries. Anyway, Python is based on objects and use mappings between the names and the objects everywhere, it's the data model, so it isn't possible to escape to that fact. That's what I think. Am I wrong ? – eyquem Feb 18 '11 at 03:29
  • By the way: despite my argumentation, I prefer your solution. It's clearer ans simpler than the use of globals(). I like the use of setattr() – eyquem Feb 18 '11 at 11:03
  • Correct me if I'm wrong but isn't this what `genpy ` attempts to do with the `generate_dynamic()` function? see [link](https://github.com/ros/genpy/blob/62062ed7fc7ff651af3f1e85f45e756f0677db26/test/test_genpy_dynamic.py#L41) – nimig18 Dec 16 '20 at 04:36
11
vars()['meta_anio_2012'] = 'translate'
Pjl
  • 1,752
  • 18
  • 21
  • 8
    This is the same as doing `locals()['meta_anio_2012'] = 'translate'`, which won't work in a function and is specifically warned against in the documentation. It also suffers from many of the problems pointed out in the comments to other answers. – DSM Jun 04 '13 at 15:42
  • 3
    There is absolutely nothing wrong with using the [vars()](https://docs.python.org/3/library/functions.html#vars) function to modify an object's variables, but you would need to update it slightly to use it to set the variables to a module (by passing in the module object). `vars(sys.modules[__name__])['my_variable'] = 'value'` There is nothing wrong with doing this as it fetches the underlying object's `__dict__`. The only time this may not work is if the object being fetched has write permissions on attributes. – OozeMeister Feb 25 '19 at 04:08
8

Keyword parameters allow you to pass variables from one function to another. In this way you can use the key of a dictionary as a variable name (which can be populated in your while loop). The dictionary name just needs to be preceded by ** when it is called.

# create a dictionary
>>> kwargs = {}
# add a key of name and assign it a value, later we'll use this key as a variable
>>> kwargs['name'] = 'python'

# an example function to use the variable
>>> def print_name(name):
...   print name

# call the example function
>>> print_name(**kwargs)
python

Without **, kwargs is just a dictionary:

>>> print_name(kwargs)
{'name': 'python'}
Kinsa
  • 686
  • 8
  • 14
4

NOTE: This should be considered a discussion rather than an actual answer.

An approximate approach is to operate __main__ in the module you want to create variables. For example there's a b.py:

#!/usr/bin/env python
# coding: utf-8


def set_vars():
    import __main__
    print '__main__', __main__
    __main__.B = 1

try:
    print B
except NameError as e:
    print e

set_vars()

print 'B: %s' % B

Running it would output

$ python b.py
name 'B' is not defined
__main__ <module '__main__' from 'b.py'>
B: 1

But this approach only works in a single module script, because the __main__ it import will always represent the module of the entry script being executed by python, this means that if b.py is involved by other code, the B variable will be created in the scope of the entry script instead of in b.py itself. Assume there is a script a.py:

#!/usr/bin/env python
# coding: utf-8

try:
    import b
except NameError as e:
    print e

print 'in a.py: B', B

Running it would output

$ python a.py
name 'B' is not defined
__main__ <module '__main__' from 'a.py'>
name 'B' is not defined
in a.py: B 1

Note that the __main__ is changed to 'a.py'.

Reorx
  • 2,801
  • 2
  • 24
  • 29
-1

For free-dom:

import random

alphabet = tuple('abcdefghijklmnopqrstuvwxyz')

globkeys = globals().keys()
globkeys.append('globkeys') # because name 'globkeys' is now also in globals()

print 'globkeys==',globkeys
print
print "globals().keys()==",globals().keys()

for i in xrange(8):
    globals()[''.join(random.sample(alphabet,random.randint(3,26)))] = random.choice(alphabet)
del i

newnames = [ x for x in globals().keys() if x not in globkeys ]
print
print 'newnames==',newnames

print
print "globals().keys()==",globals().keys()

print
print '\n'.join(repr((u,globals()[u])) for u in newnames)

Result

globkeys== ['__builtins__', 'alphabet', 'random', '__package__', '__name__', '__doc__', 'globkeys']

globals().keys()== ['__builtins__', 'alphabet', 'random', '__package__', '__name__', 'globkeys', '__doc__']

newnames== ['fztkebyrdwcigsmulnoaph', 'umkfcvztleoij', 'kbutmzfgpcdqanrivwsxly', 'lxzmaysuornvdpjqfetbchgik', 'wznptbyermclfdghqxjvki', 'lwg', 'vsolxgkz', 'yobtlkqh']

globals().keys()== ['fztkebyrdwcigsmulnoaph', 'umkfcvztleoij', 'newnames', 'kbutmzfgpcdqanrivwsxly', '__builtins__', 'alphabet', 'random', 'lxzmaysuornvdpjqfetbchgik', '__package__', 'wznptbyermclfdghqxjvki', 'lwg', 'x', 'vsolxgkz', '__name__', 'globkeys', '__doc__', 'yobtlkqh']

('fztkebyrdwcigsmulnoaph', 't')
('umkfcvztleoij', 'p')
('kbutmzfgpcdqanrivwsxly', 'a')
('lxzmaysuornvdpjqfetbchgik', 'n')
('wznptbyermclfdghqxjvki', 't')
('lwg', 'j')
('vsolxgkz', 'w')
('yobtlkqh', 'c')

Another way:

import random

pool_of_names = []
for i in xrange(1000):
    v = 'LXM'+str(random.randrange(10,100000))
    if v not in globals():
        pool_of_names.append(v)

alphabet = 'abcdefghijklmnopqrstuvwxyz' 

print 'globals().keys()==',globals().keys()

print
for j in xrange(8):
    globals()[pool_of_names[j]] = random.choice(alphabet)
newnames = pool_of_names[0:j+1]

print
print 'globals().keys()==',globals().keys()

print
print '\n'.join(repr((u,globals()[u])) for u in newnames)

result:

globals().keys()== ['__builtins__', 'alphabet', 'random', '__package__', 'i', 'v', '__name__', '__doc__', 'pool_of_names']


globals().keys()== ['LXM7646', 'random', 'newnames', 'LXM95826', 'pool_of_names', 'LXM66380', 'alphabet', 'LXM84070', '__package__', 'LXM8644', '__doc__', 'LXM33579', '__builtins__', '__name__', 'LXM58418', 'i', 'j', 'LXM24703', 'v']

('LXM66380', 'v')
('LXM7646', 'a')
('LXM8644', 'm')
('LXM24703', 'r')
('LXM58418', 'g')
('LXM84070', 'c')
('LXM95826', 'e')
('LXM33579', 'j')
eyquem
  • 26,771
  • 7
  • 38
  • 46
  • 1
    -1: saying it twice doesn't make it a good idea. Modifying globals() is bad, and should only be done in very specialized circumstances, usually involving coding tools. If you need a dynamic set of named values, use a dictionary, it's what they're there for. – Ned Batchelder Feb 18 '11 at 12:34
  • 1
    Why add to globals() just to have to turn around and keep a separate list of all the names you dumped in there? A dictionary will handle all of that for you, in a cleaner, simpler, more understandable, more flexible, and safer way. Just because you *can* do something doesn't mean you *should* do something. – Ned Batchelder Feb 18 '11 at 12:35
  • 1
    @Ned Batchelder Downvoting twice doesn't make me undertsand more. I don't pretend that these two codes are perfect arguments: they are only answers to criticism made by free-dom on 2 points. They don't want to prove that it is good to use `globals()['X']` to create a new object with name **X** that will be used as following: `li.append(X)` etc etc; – eyquem Feb 18 '11 at 16:33
  • @Ned Batchelder Indeed, as far as I understood the initial question, the point is to create an new object with only his name as a string **X** at the beginning, not by an instruction like `X = 42`. Until recently, I knew only one way to do that: inserting the name **X** in `globals()` or `locals()`. – eyquem Feb 18 '11 at 16:36
  • 2
    @Ned Batchelder Now, thanks to the answer and the CODE of John Machin, I know another manner: creating a new attribute in an instance with the name **X**, using setattr() : that's fine. Or I understand nothing. Until now, I wrote several codes, and John Machin also, and Duncan gave me precise explanations, while you only merely contented to downvote twice and to emit dogmatic sentence that _Modifying globals() is bad_ Your downvotes begin to bore me and they don't make me understand – eyquem Feb 18 '11 at 16:44
  • 3
    @Ned Batchelder Moreover, modifying globals() can't be bad in the absolute, since it IS modified when we just wrote `v = 48` or `for i in xrange(20)` . I think that it's for a great part because writing `globals()["v"] = 48` looks long and weird that it is badly considered. But where is the real weirdness in that ? I don'y understand. – eyquem Feb 18 '11 at 16:53
  • @Ned Batchelder Saying _A dictionary will handle all, in a cleaner, simpler, more understandable, more flexible, and safer way. _ is one thing, but I would like to see the code to do that, the problem being not to put a string in a dictionary, but to create the object to which this string is binded as its name. Show me a code and give more arguments, then. – eyquem Feb 18 '11 at 16:55
  • @Ned Batchelder Note that it's not me that downvoted your first comment above. Oh, and have a nice day or evening. – eyquem Feb 18 '11 at 16:57
  • 1
    @eyquem: I don't know what else you are looking for. How the values and names are computed is entirely orthogonal to how you then associate them together. In your answers, you've simply invented a way to compute them. That same technique can be used with a dictionary. I can't give you any more arguments other than this one: Your own solution with globals is getting more and more involved as you try to answer people's concerns with it. Use the simpler solution: a dictionary. – Ned Batchelder Feb 19 '11 at 13:38
  • Amm.. what, inefficient!!! – U13-Forward Oct 09 '18 at 10:21