Как работает ссылка на Python? - PullRequest
5 голосов
/ 15 марта 2012

Я запутался с ссылками на Python. Рассмотрим следующий пример:

Моя задача: Редактировать каждый элемент в списке

d = { 'm': [1,2,3] }
m = d['m']
m = m[1:]   # m changes its reference to the new sliced list, edits m but not d (I wanted to change d)

Аналогично:

d = { 'm': [1,2,3] }
m = d['m']
m = m[0]    # As per python referencing, m should be pointing to d['m'] and should have edited d

В python все идет по ссылке, тогда когда создается новый объект? Всегда ли нам нужны copy и deepcopy из модуля copy для создания копий объектов?

Пожалуйста, уточните.

Ответы [ 3 ]

12 голосов
/ 15 марта 2012

В Python переменная - это не поле, в котором хранятся объекты, а имя, указывающее на объект. В вашем коде:

  • d = { 'm': [1,2,3] } -> связывает имя d со словарем
  • m = d['m'] -> связывает имя m со списком
  • m = m[1:] -> связывает имя m с другим списком

Ваша третья строка не меняет m сама по себе, но на что указывает m

Чтобы редактировать элементы в списке, вы можете сделать следующее:

m = d['m']
for i, item in enumerate(m):
    result = do_something_with(item)
    m[i] = result
5 голосов
/ 15 марта 2012

Итан Фурман отлично объяснил, как работают внутренние компоненты Python, я не буду повторять.

Поскольку m действительно представляет список в словаре, вы можете изменить его. Вы просто не можете переназначить его на что-то новое, что происходит, когда вы используете =, чтобы приравнять его к новому срезу.

Чтобы вырезать первый элемент списка, например:

>>> m[0:1] = []
>>> d
{'m': [2, 3]}
4 голосов
/ 15 марта 2012

В питоне все идет по ссылке

В Python все является ссылкой, и ссылки передаются по значению.

Если вы хотите использовать эти термины. Но эти термины усложняют понимание.

Намного проще: в Python переменная - это имя объекта. = используется для изменения объекта, к которому относится имя. Левая часть может относиться к части существующего объекта, и в этом случае весь объект изменяется путем замены этой части. Это потому, что объект, в свою очередь, на самом деле не содержит своих частей, а вместо этого содержит больше имен, которые могут стать причиной ссылки на разные вещи.

тогда когда создается новый объект?

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

m = m[1:]   # m changes its reference to the new sliced list

Да, конечно. Теперь m относится к результату оценки m[1:].

edits m but not d (I wanted to change d)

Да, конечно. Почему изменится , изменится d? Это была не какая-то магия, это был просто результат оценки d['m']. Точно то же самое происходит в обеих строках.

Давайте рассмотрим более простой пример.

m = 1
m = 2

Это приводит к тому, что 1 становится 2? Нет, конечно нет. Целые числа неизменны. Но происходит то же самое: m заставляют назвать одну вещь, а затем назвать другую вещь.

Или иначе: если бы «ссылки» работали так, как вы ожидаете, то строка m = m[1:] была бы рекурсивной. Вы ожидаете, что это будет означать «где бы вы ни увидели m, относитесь к нему так, как если бы оно означало m[1:]». Ну, в этом случае m[1:] будет означать m[1:][1:], что будет означать m[1:][1:][1:] и т. Д.

...