Ссылки в классах python на самонаполнение стека

#python #reference

#python #ссылка

Вопрос:

Я ожидаю, что этот код должен выводить:

8
8

но это не так.

 class tree:
    def __init__(self, size=2):
        if size == 0:
            return None
        if size > 1:
            half = size//2
            self.left = tree(size-half)
            self.right = tree(half)
        else:
            self.left = self.right = None
        self.free = size
        self.size = size

    def resize(self,n):
        while self.size < n:
            t = tree(0)
            t.left = self
            t.right = tree(self.size)
            t.free = t.left.size   t.right.size
            t.size = self.size * 2
            self = t
        print("size in resize", self.size)

t = tree()
t.resize(5)
print("size of t", t.size)
  

вывод:

 size in resize 8
size of t 2
  

Я знаю, что мог бы сделать return self in resize и t = tree.resize(5) в main, но что, если я захочу вернуть что-то еще?

Комментарии:

1. Пожалуйста, не делайте этого … изменить self . Обратите внимание, что это только «именует» объект — «присваивает значение локальной переменной с именем self » — он никогда не может «изменить» сам объект или внешние переменные, которые ссылаются на указанный объект. Эта проблема является хорошим кандидатом для рекурсии и возврата новых значений.

2. Код содержит опечатку — self-rigt вместо self.right .

3. Объекты в Python действительно «предназначены для передачи по ссылке» и передаются по ссылке без того, чтобы вы делали что-то особенное, и фактически не могут быть переданы по значению. Но это не только не поможет вам решить проблему, это точная причина проблемы.

4. Этот вопрос не заслуживает отрицательных голосов. Он допустил фундаментальную ошибку в отношении Python, но это неплохой вопрос.

5. @sarnold Большая куча кода?? Я думаю, вы преувеличиваете. Насколько меньше он мог бы сделать, чтобы мы могли показать ему, как делать то, что он хотел? Для решения его проблемы было нечто большее, чем просто сказать «вы не можете назначить self подобное». Смотрите мой ответ — мне нужен был весь код, который он показал. Пример того, как выполнять мутацию в рамках, которые он уже понимает, гораздо полезнее, чем общее утверждение.

Ответ №1:

Ответ Карла абсолютно верен во всем, но, безусловно, есть способ заставить resize действовать так, как вы ожидаете.

Три шага:

  1. Создайте копию дерева
  2. Повторно инициализируйте дерево, чтобы оно было на следующий размер больше
  3. Установите увеличенное дерево left на копию исходного дерева

     def resize(self,n):
            while self.size < n:
                new = self.copy()
                self.__init__(int(round(self.size, 2)) * 2)
                self.left = new
    
            print("size in resize",self.size)
    
    def copy(self):
            new = tree(1)
            new.left = self.left
            new.right = self.right
            new.size = self.size
            new.free = self.free
            return new
      

По сути, вы пытались сделать это наоборот — заменить self и повторно self self.left использовать вместо замены self.left и повторного self использования .

Комментарии:

1. Добавление swap метода также может пригодиться, если мой опыт работы с C является каким-либо руководством. Кстати, IIRC, имя метода copy на самом деле обрабатывается copy модулем специально. 🙂

2. @KarlKnechtel Согласно документам, которые он использует __copy__ и __deepcopy__ .

Ответ №2:

self = t

Это не делает и не может быть переписано, чтобы делать то, что вы хотите. В имени в Python нет ничего «особенного» self ; это так же, как и любая другая переменная (тот факт, что вы должны явно передавать его методам, должен был быть вашим первым намеком, в отличие от языков, которые обрабатывают this как ключевое слово, должен был быть вашим первым намеком ;)), и, как и вседругие переменные, он имеет ссылочную семантику.

self = t означает «с этого момента и далее (до другого переопределения или конца области видимости) self больше не ссылается на то, на что self ссылается этот параметр, а вместо этого на значение, на которое t ссылается».

Кроме того, у вас есть опечатка в одном случае вашего __init__ метода (‘rigt’), и я предполагаю, что количество free узлов должно быть инвариантным чем-то вроде size - occupied ; в этом случае было бы чище подсчитать занятые узлы и использовать метод или свойство для вычисления свободных, вместо этогопопытки обновления, учитывающие каждое изменение.

(Более того, то, что вы, похоже, пытаетесь сделать, — это всевозможные непитонические. В частности, идея контейнера, имеющего определенный «выделенный размер», является странной; такого рода вещи обычно имеют значение только на стороне C. Забор. Для чего вам нужно двоичное дерево? Кроме того, этот метод вообще не будет балансировать дерево. И какая польза от дерева, если ни один из узлов не хранит никаких данных?)