SourBitter
SourBitter

Reputation: 157

Python list at module level

I broke down my problem to the following example program

xy8_block = [
    {'pulse': {}},
]

class Dummy:
    def __init__(self, block=list(xy8_block)):
        self._block = block


dumdum = Dummy()
dumdum._block[0]['pulse']['test'] = 0
print(xy8_block)

If I run the program, the variable xy8_block is changed, although both variables dumdum._block and xy8_block have both a different memory address.

How can I avoid this problem without directly initialising the class with the value.

Thanks in advance.

Upvotes: 3

Views: 143

Answers (2)

lucasnadalutti
lucasnadalutti

Reputation: 5948

Instead of:

def __init__(self, block=list(xy8_block)):

Do:

from copy import deepcopy
def __init__(self, block=deepcopy(xy8_block)):

When you do list(my_list), you do a shallow copy of your list, which means its elements are still copied by reference.

In other words, as you correctly mentioned, xy8_block and dumdum._block do have different memory addresses. However, if you check memory addresses for xy8_block[0] and dumdum._block[0], you will see that they are the same.

By using deepcopy, you copy the list and its elements' values, not their references.

EDIT

As wisely noted by @FMc, this will still make all instances' _block attributes to point to the same object, since the list that results from deepcopy is created in the method's definition, not in its execution. So here's my suggestion:

from copy import deepcopy

class Dummy:
    def __init__(self, block=None):
        self._block = block or deepcopy(xy8_block)

Upvotes: 4

FMc
FMc

Reputation: 42411

Get a fresh block each time:

def new_xy8_block():
    return [{'pulse': {}}]

class Dummy:
    def __init__(self, block=None):
        self._block = block or new_xy8_block()

ds = [Dummy() for _ in range(5)]
ds[0]._block[0]['pulse']['test'] = 0

for d in ds:
    print d._block

Upvotes: 2

Related Questions