0

Problem

I solved the following problem when I found a curious Python phenomenon:

Given a Python dictionary with lists as values:

{
    "a": [1, 2],
    "b": [10, 20]
}

I wanted to generate all possible combinations of these lists into a list of new dictionaries

[
    {'a': 1, 'b': 10},
    {'a': 1, 'b': 20},
    {'a': 2, 'b': 10}, 
    {'a': 2, 'b': 20}]

I wrote the following two functions to solve this:

def cartesian_tree_search(d, k_ind, key_list, d_variant = {}, variations=[]):
    k = key_list[k_ind]
    l = d[k]

    for i, v in enumerate(l):
        d_variant[k] = v
        if k_ind < len(key_list) - 1:
            d_variant_prev = d_variant.copy()
            variations = cartesian_tree_search(d, k_ind + 1, key_list, d_variant, variations)
            d_variant = d_variant_prev
        elif k_ind == len(key_list) - 1:
            variations.append(d_variant)
            d_variant = d_variant.copy()
    return variations


def cartesian_dict(d):
    return cartesian_tree_search(
        d,
        0,
        [k for k in d.keys()]
    )


print(
    cartesian_dict(
        {
            "a": [1, 2],
            "b": [10, 20]
        }
    )
)

print(
    cartesian_dict(
        {
            "a": [1, 2],
            "b": [10, 20]
        }
    )
)

The cartesian_tree_search function recursively search for all possible combination of the listed values. The cartesion cartesian_dict is just a convince function.

Well it worked at first... The code below produced the desired results in the first print statement, but in the second the result list of dictionaries are concatenated to the previous results. I do not use any global variables inside the functions. So it is pretty strange. To make it more uncanny if I reevaluate a the cartesian_tree_search function it clears away this "hidden cache".

Fix

I had a suspicion that variations optional argument is caching its value. So I rewrote the cartesian_dict function to provide the keyword arguments explicitly:

def cartesian_dict(d):
    return cartesian_tree_search(
        d,
        0,
        [k for k in d.keys()],
        {},
        []
    )

It worked, so my problem is solved, but I still very curios about explanation.

atevm
  • 801
  • 1
  • 14
  • 27

0 Answers0