mike
mike

Reputation: 23821

Use iterator as variable name in python loop

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,

Upvotes: 12

Views: 59243

Answers (5)

mOmOney
mOmOney

Reputation: 373

# 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!

Upvotes: 0

Andrew Magee
Andrew Magee

Reputation: 6684

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))}

Upvotes: 4

jimifiki
jimifiki

Reputation: 5544

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

Upvotes: 1

user166390
user166390

Reputation:

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

Upvotes: 6

gecco
gecco

Reputation: 18870

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)

Upvotes: 9

Related Questions