-1

Lets say I have some variables that can take pre-setted values:

var1 = [1,2,3]
var2 = [10,20,30]

I could hardcode a loop over all like this:

for var1 in [1,2,3]:
    for var2 in [10,20,30]:
        do something with var1 and var2

How could I do this if I want to pre-specify variables and values though? If I have a dictionary storing the variables and values I want to loop through:

variables2loop = {'var1' : [1,2,3], 
                  'var2' : [10,20,30]}

I tried:

for var in variables2loop.keys():
  for value in variables2loop[var]: 
    locals()[var] = value
    do something with var1 and var2

But this is not doing all combinations, and also it is not working properly. It goes through all values per variable BEFORE the do something command.

How can a for loop like this be implemented, if I want to dynamically change the variables and values that will be used in the script?

Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
hirschme
  • 774
  • 2
  • 11
  • 40
  • 3
    I'm not sure I 100% understand your question, but judging on first bit of code, it looks like you are trying to create a cartesian product. For this use `itertools.product`. – Paul Rooney Jan 21 '19 at 21:09
  • BTW dicts are only guaranteed to be ordered in Python 3.7+ or CPython 3.6. [source](https://stackoverflow.com/a/39980744/4518341) – wjandrea Jan 21 '19 at 21:10
  • You can use OrderedDict even before 3.7, but in this case, you may as well use a list. – gilch Jan 21 '19 at 21:15

2 Answers2

2

If your hardcoded loop is what you want,

for var1 in [1,2,3]:
    for var2 in [10,20,30]:
        do something with var1 and var2

Then given the

var1 = [1,2,3]
var2 = [10,20,30]

You can accomplish the same with

for v1 in var1:
    for v2 in var2:
        do something with v1 and v2

Instead given,

variables2loop = {'var1' : [1,2,3], 
                  'var2' : [10,20,30]}

Do the same with

for v1 in variables2loop['var1']:
    for v2 in variables2loop['var2']:
        do something with v1 and v2

Or even

from itertools import product

for v in product(*variables2loop.values()):
    do something with v[0] and v[1], etc.

That last one can work even if you change the number of variables stored in the dict, but it does assume the dict is ordered, so it doesn't work on old versions of Python. You can simply use a list instead.

var = [
    [1,2,3],
    [10,20,30],
]

for v in product(*var):
    do something with v[0] and v[1], etc.

# similarly
for v0 in var[0]:
    for v1 in var[1]:
        do something with v0 and v1
gilch
  • 10,813
  • 1
  • 23
  • 28
1

First of all, we need to address key ordering. Regular dicts are only guaranteed to be ordered starting with Python 3.7 (technically speaking, they already are in Python 3.6, but that's an implementation detail rather than a part of the language specification). Therefore, if you don't want to restrict yourself to 3.7+, you should explicitly handle the ordering:

order = ['var1', 'var2', ..., 'varn']
variables2loop = {
    'var1' : [1,2,3], 
    'var2' : [10,20,30],
    ...,
    'varn': [...]
}
ordered_values = map(variables2loop.get, order)

Then comes the iteration process. Nested loops over ordered sequences are nothing more, but a Cartesian product:

from itertools import product

for v1, v2, ..., vn in product(*ordered_values):
    pass

Finally, if you want to be free from hardcoded variable assignments in a for-loop, you would have to go functional:

from itertools import starmap

def function(*args):
    # do something with args
    ...

result = starmap(function, product(*ordered_values))
Eli Korvigo
  • 10,265
  • 6
  • 47
  • 73
  • what does the * in product(*args) do? If I don't include it, it seems to work normally. If I include it I get an error : `TypeError: 'float' object is not iterable ` – hirschme Jan 21 '19 at 21:57
  • @hirshme the function is defined as `itertools.product(*iterables, repeat=1)`: take note of the asterisk. Therefore, you need to unpack `ordered_values`. The error you get makes me think, that your actual `variables2loop` dictionary contains uniterable `values` (i.e. some variable/key points to a float). – Eli Korvigo Jan 21 '19 at 22:15