>>> a = [1, 2, 3]
>>> b = a
>>> b.append(4)
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
>>>
То же самое получается если использовать b += [4]
Однако, если писать b = b + [4], то переменная переназначается.
Зачем в питоне такая логика? Почему нельзя переназначать переменные по умолчанию, а если хочется поменять оригинал, то использовать указатели? В чем преимущество модели данных питона?
perasperaadastra wrote: Почему нельзя переназначать переменные по умолчанию, а если хочется поменять оригинал, то использовать указатели? В чем преимущество модели данных питона?
В инженерии любое решение суть компромисс: из двух зол выбирают меньшее, а из двух благ - большее.
perasperaadastra wrote:Ну вот в данном случае, в чем заключается благо? Я почитал интернеты на эту тему, но там только общие слова...
У вас b и a (подобно поинтерам в языке C), указывают на тот же объект. Если вы посмотрите адрес в памяти у a и b будут совпадать (hex(id(a)) == hex(id(b))). Операцией "b = b + [4]" вы переназначаете b на новый адрес (hex(id(b + [4]))).
В данном сценарии благо заключается в оптимизации операций с памятью: если оба поинтера указывают на тот же объект вам не надо иметь его вторую копию.
...а мы такой компанией, возьмем, да и припремся к Элис!
Мне кажется, чаще всего требуется копия, а не второй указатель на уже существующий объект. А тут по умолчанию указатель на оригинал, и только если написать особым образом, будет переназначение. ИМХО, было бы удобнее наоборот — копия для всего по умолчанию, и особая форма для случаев, когда требуется мутация. Но я читал, что модель данных Питона позволяет делать какие-то особенные вещи — то есть дело не только в оптимизации работы с памятью. Но что это за особенные вещи, я нигде не нашел.
PS Кстати, раз уж пошла речь о С, хочу спросить, можно ли там сделать так, чтобы обычные переменные a и b указывали на один и тот же адрес памяти? Я понимаю, что там можно b сделать указателем, но это будет не адрес объекта, а адрес адреса оригинального объекта:
int a = 10;
int *b;
b = &a;
Можно ли сделать следующим образом, и получится ли как в питоне?:
int a = 10;
int b = *(&a);
Все более чем логично. я вообще не знаю питон, но именно такого поведения я бы ожидал.
a += [4] - явное указание на операцию над переменной [a]/ Куда еще нужно сохранить результат как не в нее же
a = a + [4] - конкатенация двух массивов в третий. Результат пишем, куда скажем, хоть в а, хоть в b
То что для переменных другого типа и значения результат идентичный не должно вводить в заблуждение, т.к. функционал операторов разный по определению (иначе бы их не было 2, обошлись бы одним)
Но это переменная а в обоих случаях. Только в одном случае она идентична b (содержит тот же адрес), а в другом преназначается и становится уникальной. Причем, это только с мутирующими видами данных типа списков, а с какими-нибудь целыми числами, переназначение происходит всегда.
b += 1 тоже самое, что b = b + 1
Как с этим обстоят дела в других языках? В Джаве, например? Можно ли там мутировать оригинал без использования указателей или как это там называется...?
perasperaadastra wrote:PS Кстати, раз уж пошла речь о С, хочу спросить, можно ли там сделать так, чтобы обычные переменные a и b указывали на один и тот же адрес памяти? Я понимаю, что там можно b сделать указателем, но это будет не адрес объекта, а адрес адреса оригинального объекта:
int a = 10;
int *b;
b = &a;
Можно ли сделать следующим образом, и получится ли как в питоне?:
int a = 10;
int b = *(&a);
Напишу чуть формальнее. Можно ли в С сделать так, чтобы &a == &b было истинно?
Варианты:
int b = *(&a)
int &b = &a
я конечно уже давно не пишу на C/C++, но что-то мне кажется что нет. & - адрес. Равенство адресов = тождественность переменных, а вроде так нельзя сделать. То есть можно чтобы были переменные указатели ссылающиеся на один адрес, но чтобы две переменные в одном scope - никак. Это только для параметров по ссылке может выполняться, а это разный scope.
Not everyone believes what I believe but my beliefs do not require them to.
perasperaadastra wrote:
Как с этим обстоят дела в других языках? В Джаве, например? Можно ли там мутировать оригинал без использования указателей или как это там называется...?
В джаве все переменные, кроме примитивов, ссылочные, включая массивы и коллекшнз. Референсинг и дереференсинг происходит автоматически, специального синтаксиса для этого нет.
List a = new ArrayList();
List b = a;
a и b будут указывать на одну и ту же структуру, мутировать можно через обе переменные.
ALV00 wrote:В джаве все переменные, кроме примитивов, ссылочные, включая массивы и коллекшнз. Референсинг и дереференсинг происходит автоматически, специального синтаксиса для этого нет.
List a = new ArrayList();
List b = a;
a и b будут указывать на одну и ту же структуру, мутировать можно через обе переменные.
с примитивами:
int a = 5;
int b = a;
будут два разных значения
Тогда это очень похоже на Питон, кроме численных типов:
a = 5
b = a
дает одинаковый адрес для a и b, но мутировать один через другой нельзя в отличие от списков и словарей. Вот это меня и напрягает, потому что нужно помнить, что вот это мутируемый тип, а вот то — нет.
union - это очень особый случай, его нельзя трактовать как независимые переменные. Он для того и создавался чтобы один кусок памяти можно было транслировать в разные типы автоматически.
Not everyone believes what I believe but my beliefs do not require them to.
>>> a = [1, 2, 3]
>>> b = a
>>> b.append(4)
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
>>>
То же самое получается если использовать b += [4]
Однако, если писать b = b + [4], то переменная переназначается.
Зачем в питоне такая логика? Почему нельзя переназначать переменные по умолчанию, а если хочется поменять оригинал, то использовать указатели? В чем преимущество модели данных питона?
Это, по-моему это совершенно стандартное поведение. В Пёрле - то же самое.
Разве это не shallow copy vs deep copy?
union - это очень особый случай, его нельзя трактовать как независимые переменные. Он для того и создавался чтобы один кусок памяти можно было транслировать в разные типы автоматически.
Вопрос был простой:
Можно ли в С сделать так, чтобы &a == &b было истинно?