Разница в работе памяти и ссылок в C# и Python?
Зависит от версии языка, конкретной реализации виртуальной машины и операционной системы. С этого момента вопрос превращается в гадание на кофейной гуще. Формально следует открыть спецификацию языка и убедиться, что детали реализации не задокументированы.
ситуация с ссылочными типами должна быть примерно идентична с Питоном
Да, ситуация очень похожа, и в большинстве случаев так и будет работать.
Но как я и предупреждал: "The actual lifetime of a local variable is implementation-dependent."
Но что происходит, когда я так делаю с value типами?
В действительности существует 7 категорий переменных, о которых можно прочитать
по ссылке.
Ссылки тут нет (нет же?) и как я понял, то переменная с value типом хранит сам объект, а не ссылку на объект.
Значимые типы
могут содержать ссылки, поэтому сборщик мусора молчаливо удалит лишь оболочку и любезно предоставит вам
утечку памяти, но это очень редкий случай. В большинстве случаев можно сказать, что значимая переменная хранит значение. Причём не просто хранит, а
копирует его при присваивании ("Assignment to a variable of a value type creates a copy of the value being assigned. ").
Получается, my_number просто перезапишет значение с 10 на 20 и все?
Хороший вопрос, но в нём есть подвох. Выражение
int my_number = 10;
ничего никуда не записывает, а инициализирует - создаёт привязку переменной my_number к ячейке памяти с числом 10 на этапе компиляции. В итоге ваш пример записывает новое значение в переменную всего один раз и завершается.
Кроме того, это новое значение вовсе и не значение, а литерал. Встаёт ряд вопросов: "Литералы тоже копируются согласно спецификации, или компилятор умнее?" А если компилятор умный, то почему бы ему не объединить этот код в
int my_number = 20;
на этапе компиляции? Тут уже не лишним и исходники компилятора + виртуальной машины посмотреть.
Читал про стэк, но ясного понимания пока нет.
Со стеком всё более-менее просто, если не разбираться, какие типы в какой памяти хранятся. Все операции можно разложить в граф, а из графа собрать цепочку простейших операций, которая при обработке LIFO реализует алгоритм. Так вот эта цепочка и называется стеком вызовов. Аналогично существует стек данных.
p.s.
На всякий случай хочу заметить, что в питоне тоже не всё так просто и очевидно.
Например:
x = 1; print(id(x))
x = 2; print(id(x))
y = 1; print(id(y))