-3

I have function 1 ma_generate which generates a list of numbers called ma_list, with one of the inputs being period.

I have function 2 multi_gen which iterates function 1 four times, each time with a different value of time. Each time function 1 is iterated, a list list1 (or list2, list3, list4 depending on which iteration) is set to equal the produced ma_list. So the intended output is to have 4 different lists (list1, list2, list3, list4) which are different versions of ma_list, with the period input changing each of the 4 times.

Here is the code:

def ma_generate(dataset, method, period): ##Function 1
    ma_list.clear()
    if method == "sma":
        for i in range(0,period-1):
            ma_list.append(0)
        for i in range(period-1,len(dataset)):
            ma = np.mean(dataset[i+1-period:i+1])
            ma_list.append(ma)
    return 

def multi_gen(dataset, method, p1, p2, p3, p4):
    ma_generate(dataset, method, p1)
    list1.append(ma_list)
    ma_generate(dataset, method, p2)
    list2.append(ma_list)
    ma_generate(dataset, method, p3)
    list3.append(ma_list)
    ma_generate(dataset, method, p4)
    list4.append(ma_list)
    return

However, all 4 of the generated lists are the same. They are all what "list4" should be. (the ma_list output of ma_generate when period = p4). Why are they the same?

ThunderPhoenix
  • 1,649
  • 4
  • 20
  • 47
Simplex1
  • 123
  • 6
  • ``ma_list`` is always the same object that you keep mutating. So no matter what's the content at a given point, unless you assign a **copy** to your lists, they will keep referencing the same object and in the end will all contain the final mutation of it. You should read up on mutable and immutable objects. – Mike Scotty Jul 04 '20 at 09:51
  • Short fix: Change `ma_list.clear()` to `nonlocal ma_list` followed by `ma_list = []`. Or change each `list#.append(ma_list)` to `list#.append(ma_list[:])`. Or the *slightly* more invasive option, just change `ma_list.clear()` to `ma_list = []` and *return* the brand new `ma_list` (which is the Pythonic solution; operating on shared globals this way is code smell); you'd use the return value as the thing to `append`. – ShadowRanger Jul 04 '20 at 10:08
  • @ShadowRanger Thanks that does indeed work. I used your second option. Does that one work because it references the contents of ma_list, as opposed to the object itself? – Simplex1 Jul 04 '20 at 10:12
  • @Simplex1: Yes, it's (shallow) copying the contents of `ma_list` and passing that copy to `append`. If the items stored in `ma_list` are themselves mutable objects that get reused, necessitating a deep copy, you're change it to `list#.append(copy.deepcopy(ma_list))` (adding an `import copy` to the top of your file). – ShadowRanger Jul 04 '20 at 10:25

1 Answers1

0

I didn't understand your objective well but from what I see here, all the lists are getting the same version of the ma_list, making it impossible for the lists to be different from each other.

ma_generate(dataset, method, p1)
    list1.append(ma_list)
    ma_generate(dataset, method, p2)
    list2.append(ma_list)
    ma_generate(dataset, method, p3)
    list3.append(ma_list)
    ma_generate(dataset, method, p4)
    list4.append(ma_list)
  • But ma_generate is supposed to generate a new version of ma_list each time since the input of the grand function is different. It does do this when I run each section individually. BTW you wrote ma_generate as the main function, it is "multi_gen". – Simplex1 Jul 04 '20 at 10:00