11

I've been wondering if there is a way to use an iterator as a variable name in a Python loop. For example, if I wanted to create objects v0, v1, v2, is there a way to do something like this:

for i in range(3):
    v + str(i) = i**2

I know the syntax is wrong, but the idea should be clear. Something equivalent to paste in R? Thanks much,

mike
  • 22,931
  • 31
  • 77
  • 100
  • 2
    What does this have to do with the question in your title? Better yet, why would you want want to do this? – NullUserException Dec 16 '11 at 06:44
  • 2
    There are ways of doing this, but you would probably be better off assigning to another list and then accessing that list by index. – Michael Hoffman Dec 16 '11 at 06:47
  • I've changed the question name. I have encountered situations where it would be helpful to store or reference data in this particular fashion (I know there are other ways, but this would be useful at times). – mike Dec 16 '11 at 06:47
  • Show me an example of a situation where this would be better than a `list`. – NullUserException Dec 16 '11 at 06:49
  • 1
    One should be able to note a common theme among the [accepted] answers: http://stackoverflow.com/questions/1373164/how-do-i-do-variable-variables-in-python , http://stackoverflow.com/questions/4277056/declaring-a-global-dynamic-variable-in-python , http://stackoverflow.com/questions/6677424/how-do-i-import-variable-packages-in-python-like-using-variable-variables-i –  Dec 16 '11 at 07:11
  • @pst I think this question really counts as a duplicate of that first one. – Karl Knechtel Dec 16 '11 at 07:36

5 Answers5

9

The builtin method globals() returns a dictionary representing the current global symbol table.

You can add a variable to globals like this:

globals()["v" + str(i)] = i**2

FYI: This is the answer to your question but certainly not the recommended way to go. Directly manipulating globals is hack-solution that can mostly be avoided be some cleaner alternative. (See other comments in this thread)

gecco
  • 17,969
  • 11
  • 51
  • 68
  • +1 because this solves it. I wouldn't recommend doing it, but it solves it. You could also do something similar with any associative array type, rather than just the `globals` array, though you'd have to access the array to extract it. – Merlyn Morgan-Graham Dec 16 '11 at 06:50
  • There is also `locals()` which is tied to the current scope. – rrjamie Dec 16 '11 at 06:52
  • 2
    I hate it when people provide solutions that allow people to do things they shouldn't be doing. I don't know if I should downvote this for encouraging a bad idea, or not, because that's just what the OP asked for. – NullUserException Dec 16 '11 at 06:52
  • 2
    Some do simply provide answers to questions while others debate about finding a better way of achieving something. I think that it is the mix of both answer types that makes SO so precious. _(But I share your point of view that using `globals` is not the recommended way to go)_ – gecco Dec 16 '11 at 06:57
  • `locals()` usually won't work (if used in a function, where you'd want to use it), though. You can assign to it, but the assignment won't be reflected in your actual variables. – kindall Dec 16 '11 at 06:57
  • 3
    Heh. Okay, a +1 for answering the question :) However, when suggesting something ... "generally frowned upon" ... like this, it's often best to point out the general issues/limitations with it in the answer itself. (I have used both `globals()` and `locals()` before, but in *very* special circumstances.) –  Dec 16 '11 at 07:08
  • 2
    Im baffled as to why someone would want to try and create variable variables in python? To me it seems like you would just have no handle to the variables your just made and would have to go digging through global or local to find them. Can the OP change the question to "why would anyone create variable variables in py?" so I can see an answer? – jdi Dec 16 '11 at 07:27
  • @jdi Because said person uses such in another language/environment and are still in said mindset :) -- it looks like R support this (I have never used R) and, at least older PHP code, heavily abused this construct. –  Dec 16 '11 at 08:10
6

While this does not attempt to answer the question directly (see geccos answer for that), this is generally the "approved" method for such an operation:

v = [i**2 for i in range(3)]

print v[0] # 0
print v[1] # 1
print v[2] # 4

In general it is both cleaner and more extensible to use an ADT (a list in this case) to represent the given problem than trying to create "dynamic variables" or "variable variables".

Happy coding.


While the above uses indices, the more general form of "variable variables" is generally done with a dictionary:

names = dict(("v" + str(i), i**2) for i in range(3))
print names["v2"] # 4

And, for a fixed finite (and relatively small) set of variables, "unpacking" can also be used:

v0, v1, v2 = [i**2 for i in range(3)]
print v1 # 1
4

There are a few ways to do this, the best will depend on what you actually want to do with the variables after you've created them.

globals() and locals() will work but they're not what you want. exec() will also work but it's even worse than globals() and locals().

A list comprehension as mentioned by @user166390 is a good idea if v1, v2 and v3 are homogenous and you just want to access them by index.

>>> v = [i ** 2 for i in range(3)]
>>> v[0]
0
>>> v[1]
1
>>> v[2]
4

You could also do this, if it's always exactly three elements:

>>> v1, v2, v3 = [i ** 2 for i in range(3)]
>>> v1
0
>>> v2
1
>>> v3
2

This is nice if the objects are more individual because you can give them their own names.

Another in-between option is to use a dict:

d = {}
for i, val in enumerate(range(3)):
    d["v{}".format(i)] = val

>>> d["v0"]
0
>>> d["v1"]
1
>>> d["v2"]
4

Or a shortcut for the above using a dict comprehension:

d = {"v{}".format(i): val for i, val in enumerate(range(3))}
Andrew Magee
  • 6,506
  • 4
  • 35
  • 58
1

I prefer xrange() to range(). Here the code for you:

for i in xrange(3):
    exec("v"+str(i)+" = i * i")

Even if... you should consider using a list

jimifiki
  • 5,377
  • 2
  • 34
  • 60
0
# Python 3.8.2 (default, Feb 26 2020, 02:56:10)

Creating variable names using globals() and unpacking a tuple using exec():

glo = globals()
listB=[]
for i in range(1,11):
    glo["v%s" % i] = i * 10
    listB.append("v%s" % i)

def print1to10():
    print("Printing v1 to v10:")
    for i in range(1,11):
        print("v%s = " % i, end="")
        print(glo["v%s" % i])

print1to10()

listA=[]
for i in range(1,11):
    listA.append(i)

listA=tuple(listA)
print(listA, '"Tuple to unpack"')

listB = str(str(listB).strip("[]").replace("'", "") + " = listA")

print(listB)

exec(listB)

print1to10()

Output:

Printing v1 to v10:
v1 = 10
v2 = 20
v3 = 30
v4 = 40
v5 = 50
v6 = 60
v7 = 70
v8 = 80
v9 = 90
v10 = 100
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) "Tuple to unpack"
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 = listA
Printing v1 to v10:
v1 = 1
v2 = 2
v3 = 3
v4 = 4
v5 = 5
v6 = 6
v7 = 7
v8 = 8
v9 = 9
v10 = 10

Note that either locals(), globals(), or vars() can be used:

vList = []
for i in range(3):
    vars()["v%s" % i] = i ** 2
    vList.append(vars()["v%s"%i])

for i in range(3):
    print("v%s"%i, "=", vList[i])

Output:

v0 = 0
v1 = 1
v2 = 4

This example uses a dictionary instead of a list:

vDict = {}
for i in range(3):
    vars()["v%s" % i] = i ** 2
    vDict[i] = vars()["v%s" % i]

for i in range(3):
    print("v%s"%i, "=", vDict[i])

Output:

v0 = 0
v1 = 1
v2 = 4

Also note that locals(), globals(), and vars() can be used interchangeably whether creating a variable from a string, assigning a direct value, or assigning an indirect value:

vDict = {}
for i in range(1000):
    vars()["v%s" % i] = i ** 2
    vDict[i] = vars()["v%s" % i]

for i in range(0, 1000, 200):
    print("v%s"%i, "=", vDict[i])

print()
locals()[vDict[200]] = 1999  #indirect assignment
print("v200 =", vDict[200], "(direct v200 value is unchanged)") 
print()
print("v200 =", vars()[vDict[200]], "(indirect value)")
print("v200 =", locals()[vDict[200]], "(indirect value)") 
print("v200 =", globals()[vDict[200]], "(indirect value)")
print()

vars()["v%s"%200] = 2020
print("v200 =", globals()["v%s"%200], "(direct value)")
v200 = 2021
print("v200 =", locals()["v%s"%200], "(direct value)")

Output:

v0 = 0
v200 = 40000
v400 = 160000
v600 = 360000
v800 = 640000

v200 = 40000 (direct v200 value is unchanged)

v200 = 1999 (indirect value)
v200 = 1999 (indirect value)
v200 = 1999 (indirect value)

v200 = 2020 (direct value)
v200 = 2021 (direct value)

How it works

vDict = {}
for i in range(0, 1000, 200):
    vars()["v%s" % i] = i ** 2
    vDict[i] = vars()["v%s" % i]

for i in range(0, 1000, 200):
    print("v%s"%i, "=", vDict[i])

print()
# indirect assignment using 40000 as variable (variable variable)
locals()[vDict[200]] = 1999  # using value 40000 as a variable
print("v200 =", vDict[200], "(direct v200 value is unchanged)") 
print()
print("v200 =", vars()[vDict[200]], "(indirect value from key 40000)")
print("{ '40000':", globals()[40000],"}")
print()
if vars()[vDict[200]] == globals()[40000]:
  print("They are equal!")
if globals()[vDict[200]] == locals()[40000]:
  print("They are equal!")

Output:

v0 = 0
v200 = 40000
v400 = 160000
v600 = 360000
v800 = 640000

v200 = 40000 (direct v200 value is unchanged)

v200 = 1999 (indirect value from key 40000)
{ '40000': 1999 }

They are equal!
They are equal!
mOmOney
  • 333
  • 3
  • 5