Почему адреса разных типов данных разные [Python]?

>>> a=5
>>> b=6
>>> id(a)
10914496
>>> id(b)
10914528
>>> c='Hello'
>>> d='World'
>>> id(c)
139973573252184
>>> id(d)
139973616356744
>>> e=(4>5)
>>> f=(4<5)
>>> id(e)
10739968
>>> id(f)
10740000
  1. Почему длина адреса строки и типа данных boolean / int так различается?
  2. Почему последующие объявления имеют значительную разницу в своих адресах по сравнению с размером типа данных?

Обновление №1

>>> id(c)
139973616356856
>>> id(c[0])
139973652926112
>>> id(c[1])
139973653190728
>>> id(c[2])
139973653634272
>>> id(c[3])
139973653302104

У меня были эти сомнения, потому что я сначала изучил C ++ (честно говоря, Turbo C ++), и способ определения адресов строк в Python сильно отличается от того, что происходит в C ++. Я думаю, это нормально в Python, поскольку мы не можем получить доступ к объекту через его адрес в Python, я прав?

Кроме того, какой смысл иметь разные адреса для c и c [0]? Для некоторых эти вопросы могут быть ненужными, но мне слишком любопытно знать, как Python распределяет адреса по разным типам данных, особенно (здесь) строкам.


person Reeshabh Ranjan    schedule 26.08.2017    source источник
comment
Также объясните отрицательный голос, так как это мой первый вопрос на этом сайте.   -  person Reeshabh Ranjan    schedule 26.08.2017


Ответы (3)


Во-первых, мы должны начать с того, что Python не работает так же, как C. В C массив - это просто блок памяти. В Python это объект. В результате id() c и c[0] не совпадают.

Во-вторых, вы должны понимать, что все в Python - это объект. В C, когда вы выполняете что-то вроде c[0], вы запрашиваете первое значение из последовательности ячеек памяти. В Python это не всегда так. Для стандартного списка он поддерживается массивом, но его адрес скрыт от вас. Вы видите адрес объекта через id(). В этом случае c - это строка, но c[0] тоже (в Python нет типов символов). Это означает, что когда вы запрашиваете c[0], Python создает новую строку для представления запрошенного вами символа (или, скорее, подстроки). К счастью, Python на самом деле не создает новую строку каждый раз, поскольку Python автоматически создает односимвольные строки.

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

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

У меня были эти сомнения, потому что я сначала изучил C ++ (честно говоря, Turbo C ++), и способ определения адресов строк в Python сильно отличается от того, что происходит в C ++. Я думаю, это нормально в Python, поскольку мы не можем получить доступ к объекту через его адрес в Python, я прав?

Да и нет. Когда вы говорите c[0], под капотом запускается специальный метод для извлечения подстроки из строки. Это отличается от того, что вы получаете в C ++. Однако Python эффективно хранит строку под капотом как последовательность байтов. То, что вы не видите этих адресов для проверки эффективности, не означает, что их там нет. Кроме того, как я упоминал выше, c[0] возвращает новую строку, представляющую желаемую подстроку. Python здесь умен и вернет односимвольную строку, но это будет интернированная строка. Вы можете видеть, что у некоторых писем один и тот же адрес:

>>> for c in "hobo":
...     print c, id(c)
...
h 4434994600
o 4434861432
b 4434859712
o 4434861432

Вы можете видеть, что строка для "o" имеет один и тот же адрес - BTW, пример - Python 2, но такое же качество существует в Python 3.

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

Кроме того, какой смысл иметь разные адреса для c и c [0]? Для некоторых эти вопросы могут быть ненужными, но мне слишком любопытно знать, как Python распределяет адреса по разным типам данных, особенно (здесь) строкам.

Я объяснил это выше, но напомним: c и c[0] отличаются от C. В Python первая строка, а вторая запрашивает подстроку, содержащую первый символ строки.

Python действительно использует схему управления памятью в стиле арены во многих областях, но по большей части вам не нужно об этом заботиться. Если вам интересно, я предлагаю вам взглянуть на исходный код Python. Подкаталог Python содержит много битов поддержки языка и низкоуровневой среды выполнения. А также поймите, что Python также предварительно кэширует некоторые вещи, что также может объяснить несоответствие в адресах, которое вы видите выше.

person John Szakmeister    schedule 26.08.2017

В зависимости от архитектуры вашего компьютера типы данных будут храниться в памяти в байтах разной длины. Например, для каждого символа ASCII в строке потребуется один байт для его хранения, в то время как целые числа могут храниться с любой длиной в битах до предела, зависящего от размера сохраняемого числа. Я не совсем уверен, но python также может хранить разные типы данных в разных областях выделенной памяти.

Python также хранит в выделенной памяти гораздо больше, чем просто переменные, которые вы ему передаете. IDE также работает в этой области. Таким образом, между двумя выделениями могла быть сохранена какая-то другая переменная.

Для обновления №1 взгляните на это

person pointerless    schedule 26.08.2017
comment
Я понимаю вашу точку зрения. Спасибо. Также обратите внимание на мое обновление №1. - person Reeshabh Ranjan; 26.08.2017

Это id адреса в CPython - это деталь реализации; они гарантированно будут отличаться только для объектов, которые существуют одновременно.

Вы наблюдаете группировку, потому что CPython предварительно создает ряд объектов, включая -5 - 256, а также True и False. В обычных обстоятельствах эти значения не будут отображаться ни по каким другим адресам, что стало возможным, потому что они имеют неизменяемый тип.

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

Доступ к знакомым вам типам C можно получить с помощью ctypes, но делать это обычно неудобно и рискованно. Например, если вы передаете строку Python функции, которая изменяет строку C, вы разрываете саму строку; Python ожидает, что строки будут неизменяемыми, и может делиться ими и кэшировать их хэши.

person Yann Vernier    schedule 26.08.2017