Изменяемые объекты в Python, копии и ссылки: как обнаружить проблему?
Пожалуйста, скажите мне, если то, что я пишу, правильно, и если вы можете ответить на мой вопрос в конце, я очень рад:
Верно ли, что переменные, назначенные спискам в python, являются "ссылками"? И то же самое справедливо для других изменяемых объектов (например, dict, но не кортежей)?
a = [1,2,3]
b = a
def app(l,e):
l += [ e ]
app(a,5)
print b
дает
[1,2,3,5]
для того, чтобы иметь назначение по значению, а не по ссылке, я должен использовать deepcopy
(из копии)?
Проблема для меня в том, что очень легко вносить ошибки, не обращая на это внимания! Итак, я заявляю следующее
ВОПРОС: есть ли инструмент статического анализа (например, pylint или что-то подобное), который может выдавать предупреждение для таких строк, как b = a
или же app(a,5)
сказать мне, что я потенциально изменяю свои изменяемые объекты (списки, словари)?
Спасибо
0 ответов
Я прочитал ссылку на вопрос в комментариях под названием "Как передать переменную по ссылке?" и некоторая документация. Я считаю, что обычные назначения Python и передача параметров технически передаются по значению. Однако каждое присвоение в Python автоматически запускает создание ссылки на объект. Когда вы назначилиa
к b
и прошел a
в качестве параметра вашей функции обе строки кода инициировали создание ссылок на объект a
. Затем ссылки были переданы в качестве значений вашей функции иb
.
К сожалению, я не знаю ни одного инструмента статического анализа, который предупреждал бы вас об этих правилах. Я признаю, что они сбивают с толку, но единственное решение, которое я знаю, - это прочитать документацию и попытаться проверить концепции, используя простые фрагменты кода. Ваш код - хороший пример, из которого вы можете вывести "правила" Python и возможные проблемы.
В разделе документации Python говорится:
"... аргументы в Python передаются путем присваивания. Поскольку присваивание просто создает ссылки на объекты..."
Далее, согласно ответу на вопрос "Как передать переменную по ссылке?",
Если вы передаете изменяемый объект в метод, метод получает ссылку на тот же объект, и вы можете изменить его к своему удовольствию, но если вы повторно привяжете ссылку в методе, внешняя область ничего не будет знать об этом, а после все готово, внешняя ссылка по-прежнему будет указывать на исходный объект.
В вашем коде l += e
выглядит как "повторное связывание" внутри метода и не должно изменяться a
. Однако можно сделать вывод, что Python рассматривал+= [e]
похожий на .append(e)
. Было указано, что "повторное связывание" переменной функции, которой был передан параметр вне области видимости, не должно влиять на переданный объект; несмотря на это,a
был изменен l += [e]
. Таким образом, можно сделать вывод, что Python не лечил+= []
как переплет. Я призываю других также добавлять ссылки через комментарии в случае появления новой информации или исправлений.
ПРИМЕЧАНИЕ: может быть полезно использовать Pythonid()
функция от переменной. Он показывает целое число, которое Python присваивает для идентификации объекта на протяжении "времени жизни" объекта. К сожалению, я не знаю точного определения понятия "время жизни". Вам лучше спросить других или прочитать документацию: встроенная функция Python id()