Страницы

Поиск по вопросам

вторник, 26 ноября 2019 г.

Что такое объект в Python. Почему id(a) == id(b) == id(1)?


Детализирую вопрос.
В книгах по Python пишут, что все в Python есть объект.

Берем традиционный подход к изучению/обучению языкам программирования.
Языки Pascal, C, C++, у них есть понятие  "имя переменной" (идентификатор). С имене
переменной связывается/присваивается значение. Значение хранится в памяти. Имя переменной - это способ (в исходном тексте программы) обратиться к ячейке памяти для получения значения, которое там хранится. 

Не знаю верно ли высказывание (для компилируемых языков): Для  переменных, например
целого типа, в момент выполнения программы на компьютере, процессор работает уже с адресам
ячеек памяти, где хранятся значения переменных. Т.е. не такого, что где-то по какому-то адресу хранится имя переменной и оно связывается с адресом ячейки, в которой хранится значение.

Теперь переходим к Python. В этом языке все является объектом, даже определение функции.
Переменная объект, значение объект и т.д. В разное время с одним и тем же объектом может соотноситься разный другой объект. 

a = 1
print(a)
a = "Hello"
print(a)


Но тогда как понять действие функции id()? По определению стандарта
она возвращает "identify" указанного объекта. Причем, "возвращает целое, гарантированно являющееся уникальным" и постоянным для объекта на время его существования."

Тогда почему 

a = 1
b = 1
print(id(a) == id(b) == id(1))  # True
print("Why?")


ведь a, b, 1 разные объекты?
По-моему вопрос получился...

Используется Python 3.6



Про значения от -5 до 256 наслышан. Имеет место быть

a = 1000000
b = 1000000
print(id(a) == id(b))  # True
print("Why?")


На счет того, что достаточно "знать об именах и т.д.". Для меня не достаточно, потом
и спрашиваю у уважаемых профи. В Питоне все объект. Нет имен переменных. Отсюда и мой вопрос.
    


Ответы

Ответ 1



В питоне интерпретатор оптимизирован так, что небольшие целые числа представлен одним объектом - это сделано в целях улучшения производительности. Для больших чисел это уже не выполняется. Марк Лутц - Изучаем Python, 4-е издание, 2011, стр. 204: >>> X = 42 >>> Y = 42 # Должно получиться два разных объекта >>> X == Y True >>> X is Y # Тот же самый объект: кэширование в действии! True В этом примере переменные X и Y должны быть равны (==, одно и то же значение), но не эквивалентны (is, один и тот же объект), потому что было выполнено два разных литеральных выражения. Однако из-за того, что малые целые числа и строки кэшируются и используются повторно, оператор is сообщает, что переменные ссылаются на один и тот же объект.

Ответ 2



В разное время с одним и тем же объектом может соотноситься разный другой объект. Вы хотели сказать: в разное время, одно и то же имя может ссылаться на разные объекты Модель в Питоне простая — совершенно не нужно знать что такое адрес, ячейка памяти, указатель. Достаточно знать только об именах и объектах, к которым они привязаны. Вот картинки, которые поясняют разницу между переменными в С подобных языках и именам в Питоне. Ярлыки и шарики достаточны, чтобы любое поведение на уровне Питона объяснить — сперва не верится что такая простая модель все крайние случаи охватывает. ведь a, b, 1 разные объекты? У вас только один объект (единица). Маленькие целые кэшируются в CPython. Разны имена a, b ссылаются на один и тот же объект: a is b (id(a) == id(b)). 1 это константа в исходном коде (думайте как о вызове конструктора для объекта). Подробнее об int объектах: Присваивание в Python. a = 1000000; b = 1000000; print (id(a) == id(b)) # True Для проверки ссылаются ли имена на одни и те же объекты, используйте a is b (здесь это равнозначно id(a) == id(b), но id может быть переопределён в общем случае). Результат может быть True (зависит как Питон код был в байт-код скомпилирован в выбранной реализации), но не обязан быть True: >>> a = 1000000 >>> b = 1000000 >>> print (a is b) False В данном случае, каждое выражение отдельно компилируется, a и b на разные объекты ссылаются. Сравните: >>> def f(): ... a = 1000000 ... b = 1000000 ... print(a is b) >>> f() True Код функции как одно целое компилируется, поэтому a is b может (но не обязано) быт True. Один это объект или несколько может зависеть от реализации Питона (CPython, Pypy Jython, etc) и даже конкретной версии реализации. Реальный код не должен зависеть от подобных деталей реализации. Как явно сказано по ссылке: не используйте проверку на идентичность для сравнения чисел (разные объекты могут иметь одно значение). Используйте a == b, чтобы узнать равны ли числа. Питоне все объект. Нет имен переменных. Отсюда и мой вопрос. Конечно в Питоне есть имена. a и b это имена в вашем вопросе. То что кодом Питона в разных представлениях можно манипулировать как простым объекто (в функцию передать как параметр, вернуть из функции, вызвать методы, итд) никак не отменяет наличие имён. Примеры: на уровне AST — имена это узлы типа _ast.Name. Более сложный пример это MacroPy на уровне байт-кода (byteplay) исходного кода (lib2to3) Также, для манипуляций Питон кода, может быть полезно знать о compile(), eval() exec() встроенных функциях, dis, uncompyle6, inspect модулях. К примеру, inspect.signature( позволяет манипулировать описанием функции как объектом. В уже упомянутой ссылке показано как саму память, занимаемую объектом в CPython реализации, можно также как обычным Питон объектом манипулировать с помощью ctypes (пример изменяет неизменяемый на уровне Питона объект типа int).

Ответ 3



переменные хранят только ссылки на объект оператор = присваивает переменной ссылку примитивные типы (литералы: числа, строки) с одинаковым значением представлены единственным объектом

Комментариев нет:

Отправить комментарий