#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
действовать так, как вы ожидаете.
Три шага:
- Создайте копию дерева
- Повторно инициализируйте дерево, чтобы оно было на следующий размер больше
-
Установите увеличенное дерево
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. Забор. Для чего вам нужно двоичное дерево? Кроме того, этот метод вообще не будет балансировать дерево. И какая польза от дерева, если ни один из узлов не хранит никаких данных?)