Класс инвентаря объекта, включая класс регистратора, перезаписывает словарные записи - PullRequest
0 голосов
/ 31 января 2019

Я обнаружил это странное поведение Python 3.7.2 (я не пробовал другие версии).Я создал следующий сценарий и в надежде понять, что происходит лучше.

Я хочу написать класс инвентаризации объектов, включая класс регистратора, который регистрирует текущий инвентарь на счетчике (например, каждый день).Затем я хочу использовать класс регистратора для извлечения инвентаря в определенный день.

Вот код:

class Obj():
    def __init__(self, parameter):
        self.par = parameter


class ObjInventory():
    def __init__(self, object_list):
        self.list_of_objects = object_list
        self.counter = 0
        self.logger = InventoryLogger()

    def increase_counter(self):
        self.logger.add_list_at_counter(self.counter, self.list_of_objects)
        self.counter += 1


class InventoryLogger():
    def __init__(self):
        self.dict_of_positions = {}

    def add_list_at_counter(self, counter, object_list):
        self.dict_of_positions[counter] = object_list

    def print_object_inventory_on_count(self, counter):
         object_list = self.dict_of_positions[counter]
         list_of_parameters = [object.par for object in object_list]
         print(list_of_parameters)


Inventory = ObjInventory([])

first_list_of_objects = [Obj(1), Obj(2), Obj(3)]
Inventory.list_of_objects += first_list_of_objects
Inventory.increase_counter()
Inventory.logger.print_object_inventory_on_count(0)

second_list_of_objects = [Obj(4), Obj(5), Obj(6)]
Inventory.list_of_objects += second_list_of_objects
Inventory.increase_counter()
Inventory.logger.print_object_inventory_on_count(1)

del Inventory.list_of_objects[2:4]
Inventory.increase_counter()
Inventory.logger.print_object_inventory_on_count(2)

Inventory.logger.print_object_inventory_on_count(0)
Inventory.logger.print_object_inventory_on_count(1)
Inventory.logger.print_object_inventory_on_count(2)

Ожидаемый результат будет следующим:

[1, 2, 3] #---> first 3 objects

[1, 2, 3, 4, 5, 6] #---> first 3 objects and additional 3 objects

[1, 2, 5, 6] #---> list without removed objects

[1, 2, 3] #reiteration

[1, 2, 3, 4, 5, 6]

[1, 2, 5, 6]

НО Вместо этого я получаю следующее:

[1, 2, 3]

[1, 2, 3, 4, 5, 6]

[1, 2, 5, 6]

[1, 2, 5, 6]

[1, 2, 5, 6]

[1, 2, 5, 6]

Таким образом, печать регистратора работает только после непосредственного вызова .Если я вызову функцию регистрации на более позднем этапе, все словарные записи станут равными последней записи.

Я нашел обходной путь, изменив функцию add_list_at_counter следующим образом, что приводит ктребуемый ответ кода:

def add_list_at_counter(self, counter, object_list):
    self.dict_of_positions[counter] = []
    self.dict_of_positions[counter] += object_list

Особенно обходной путь (который я нашел после нескольких часов, пытаясь понять, почему код не работает), оставляет меня в замешательстве.Есть идеи, почему второй код работает, а первый нет?Или это какая-то ошибка?

1 Ответ

0 голосов
/ 31 января 2019

Ваша проблема вызвана тем, что многие из списков, которые являются значениями в словаре в вашем логгере, на самом деле являются ссылками на один и тот же list_of_objects.

Сравните его с этим кодом:

x = [1,2,3]      # x refers to a list
y = x            # y is another reference to the same list
x.append(4)      # modify the list through x
print(y)         # prints [1, 2, 3, 4], even though we accessed via y

Ваш код делает то же самое, но вместо простых переменных, таких как x и y, вы ссылаетесь на список через атрибуты и значения словаря (Inventory.list_of_objects и Inventory.logger.dict_of_positions[counter] для каждогоcounter значение).

Я не совсем понимаю, что должен делать ваш код, но я подозреваю, что вы можете избежать этой проблемы, изменив increase_counter для создания копии списка list_of_objectsиспользуя конструктор list:

def increase_counter(self):
    self.logger.add_list_at_counter(self.counter, list(self.list_of_objects)) # new list
    self.counter += 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...