Почему фрагмент списка, назначенный другому списку, не меняет оригинал? - PullRequest
1 голос
/ 18 февраля 2020

У меня есть класс, представляющий математический тензор. Тензор в классе хранится в виде одного списка, а не списков внутри другого списка. Это означает, что [[1, 2, 3], [4, 5, 6]] будет храниться как [1, 2, 3, 4, 5, 6].

Я сделал функцию __setitem__() и функцию для обработки взятия фрагментов этого тензора, пока он в формате одного списка. Например, slice(1, None, None) станет slice(3, None, None) для списка, упомянутого выше. Однако, когда я назначаю этому срезу новое значение, исходный тензор не обновляется.

Вот как выглядит упрощенный код

class Tensor:
    def __init__(self, tensor):
        self.tensor = tensor # Here I would flatten it, but for now imagine it's already flattened.

    def __setitem__(self, slices, value):
        slices = [slices] 
        temp_tensor = self.tensor # any changes to temp_tensor should also change self.tensor.

        for s in slices: # Here I would call self.slices_to_index(), but this is to keep the code simple.
            temp_tensor = temp_tensor[slice]

        temp_tensor = value # In my mind, this should have also changed self.tensor, but it hasn't.

Может быть, я просто глуп и могу не понимаю, почему это не работает. Может быть, мои настоящие вопросы не просто «почему это не работает?» но также «есть ли лучший способ сделать это?». Спасибо за любую помощь, которую вы можете мне оказать.

ПРИМЕЧАНИЯ:

Каждое «измерение» списка должно иметь одинаковую форму, поэтому [[1, 2, 3], [4, 5]] не допускается.

Этот код значительно упрощен, так как есть много других вспомогательных функций и тому подобное.

в __init__() Я бы сгладил список, но, как я только что сказал, для простоты я оставил это, наряду с self.slice_to_index().

1 Ответ

1 голос
/ 18 февраля 2020

Вы не должны думать о python переменных, как в c++ или java. Думайте о них как о ярлыках, которые вы ставите на ценности. Проверьте этот пример:

>>> l = []
>>> l.append
<built-in method append of list object at 0x7fbb0d40cf88>
>>> l.append(10)
>>> l
[10]
>>> ll = l
>>> ll.append(10)
>>> l
[10, 10]
>>> ll
[10, 10]
>>> ll = ["foo"]
>>> l
[10, 10]

Как видите, переменная ll сначала указывает на тот же список l, но позже мы просто указываем на другой список. Изменение более позднего ll не приведет к изменению исходного списка, на который указывает l.

Так что, в вашем случае, если вы хотите, чтобы self.tensor указывал на новое значение, просто сделайте это:

class Tensor:
    def __init__(self, tensor):
        self.tensor = tensor # Here I would flatten it, but for now imagine it's already flattened.

    def __setitem__(self, slices, value):
        slices = [slices] 
        temp_tensor = self.tensor # any changes to the list pointed by temp_tensor will be reflected in self.tensor since it is the same list

        for s in slices: 
            temp_tensor = temp_tensor[slice]

        self.tensor = value
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...