2016-11-24 5 views
3

я сломалась моя проблема в следующем примере программысписок Python на уровне модуля

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) 

Если я запускаю программу, переменная xy8_block изменяется, хотя обе переменные dumdum._block и xy8_block имеют и другую память адрес.

Как я могу избежать этой проблемы без непосредственной инициализации класса класса со значением.

Заранее спасибо.

+0

@lucasnadalutti правильно, вы можете доказать это, глядя на идентификаторах словаря: '' печати ID (xy8_block [ 0]) '' и '' print id (dumdum._block [0]) '' –

+0

Возможный дубликат [«Наименьшее удивление» и аргумент аргумента по умолчанию] (http://stackoverflow.com/questions/1132941/least- astonishment-and-the-mutable-default-argument) – wwii

ответ

4

Вместо:

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

Do:

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

Когда вы делаете list(my_list), вы делаете неглубокой копии списка, что означает его элементы все еще копируется посредством ссылки.

Другими словами, как вы правильно упоминали, xy8_block и dumdum._block имеют разные адреса памяти. Однако, если вы проверите адреса памяти для xy8_block[0] и dumdum._block[0], вы увидите, что они одинаковы.

Используя deepcopy, вы копируете список и значения его элементов, а не их ссылки.

EDIT

Как мудро отметил @FMc, это все равно будет делать все экземпляры _block атрибуты, чтобы указать на тот же объект, так как список, что результаты deepcopy создается в определении метода, а не в его исполнение. Так вот мое предложение:

from copy import deepcopy 

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

Это не будет работать должным образом. Каждый экземпляр «Dummy» будет содержать ссылку на ту же самую глубокую копию. Значения по умолчанию arg определяются один раз, во время определения класса. Это одна из причин, по которой вы обычно хотите избежать измененных значений в качестве значений по умолчанию. – FMc

+0

Хотя это работает для конкретного примера, вы правы в этом. Я подробно расскажу, спасибо. – lucasnadalutti

2

Получить новый блок каждый раз:

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 
Смежные вопросы