Как изменить атрибуты одного экземпляра с помощью метода другого экземпляра в Python - PullRequest
2 голосов
/ 28 марта 2019

Я пытаюсь изменить атрибуты экземпляров одного класса, изменив атрибуты другого класса. Однако в некоторых случаях атрибуты не изменяются должным образом.

Предположим, что у меня есть класс Dot, который содержит координату X этой точки

class Dot:
    def __init__(self, x = 0):
        self.x = x

и другой класс Cloth, который инициализируется списком экземпляров Dot

class Cloth:
    def __init__(self, dots):
        self.dots = dots
        self._x = [dot.x for dot in dots]

    @property 
    def x(self):
        return self._x

    @x.setter
    def x(self, arr):
        for ii in range(len(arr)):
            self.dots[ii].x = arr[ii]   
        self._x = arr

Класс Cloth имеет атрибут x, который возвращает список со всеми x-координатами экземпляров Dot, а также метод получения и установки, который позволяет изменять список x. Если я сейчас изменю список x-координат, то получится хорошо

#instantiate list of dots
dots = [Dot(x = 1), Dot(x = 2), Dot(x = 3)]
#instantiate the cloth
cloth = Cloth(dots)

#change all x-coordinates at once
cloth.x = [2, 3, 4]

print(cloth.x) 
#returns [2, 3, 4]
print(cloth.dots[0].x) 
#returns 2

Однако, если я попытаюсь изменить только одну x-координату, x-координата этого экземпляра точки не изменится, так как метод установки не вызывается

#change one x-coordinate
cloth.x[0] = -1

print(cloth.x) 
#returns [-1, 3, 4]
print(cloth.dots[0].x) 
#still returns 2 instead of -1

Есть ли способ обойти эту проблему или это из-за плохого дизайна классов?

1 Ответ

0 голосов
/ 28 марта 2019

Как упомянуто гекконами выше, проблема здесь заключается в том, что проектное решение должно реплицировать данные в двух местах, а не чтобы ваш объект Cloth предоставлял интерфейс для данных. Копируя данные из объектов Dot в массив _x, мы путаем назначение каждого класса и задаем себе проблему синхронизации.

Как насчет того, чтобы просто перейти к таким данным?

class Cloth:
    def __init__(self, dots):
        self.dots = dots

    @property
    def x(self):
        return (dot.x for dot in self.dots)

    @x.setter
    def x(self, arr):
        for value, dot in zip(arr, self.dots):
            dot.x = value

Работа наших двух классов теперь хорошо разделена. Задача Dot - хранить данные x, а задача Cloth - предоставлять интерфейс для этих данных в формате массива.

...