Для чего используется функция id ()?

101

Я прочитал документы Python 2 и заметил id()функцию:

Вернуть «идентичность» объекта. Это целое число (или длинное целое число), которое гарантированно будет уникальным и постоянным для этого объекта в течение его времени жизни. Два объекта с неперекрывающимся временем жизни могут иметь одинаковое значение id ().

Детали реализации CPython: это адрес объекта в памяти.

Итак, я экспериментировал id()со списком:

>>> list = [1,2,3]
>>> id(list[0])
31186196
>>> id(list[1])
31907092 // increased by 896
>>> id(list[2])
31907080 // decreased by 12

Какое целое число вернула функция? Это синоним адресов памяти в C? Если да, то почему целое число не соответствует размеру типа данных?

Когда id()используется на практике?

Танакрон Тандавас
источник
4
Просто потому, что вы храните (скажем) 32-битное int в структуре данных на языке сценариев, не означает, что вы будете использовать на 32 бита больше памяти. метаданные ВСЕГДА прикреплены к ЛЮБЫМ данным, которые вы храните. тип, размер, длина, бла-бла-бла.
Marc B
cpython выделяется из кучи, которая скремблируется по мере того, как объекты освобождаются и не размещаются.
tdelaney
Числа Python - это не просто фрагменты данных. Это объекты, которые для начала используют long внутри, а затем автоматически продвигаются к представлению в стиле BigNumber, если значение становится слишком большим.
Гарет Латти,

Ответы:

158

Ваш пост задает несколько вопросов:

Какое число возвращается из функции?

Это « целое число (или длинное целое) , которое гарантированно будет уникальным и постоянным для этого объекта в течение его жизни. » (Python Standard Library - Встроенные функции) уникальный номер. Не больше, не меньше. Думайте об этом как о номере социального страхования или идентификационном номере сотрудника для объектов Python.

То же самое и с адресами памяти в C?

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

Если да, то почему число не увеличивается мгновенно на размер типа данных (я предполагаю, что это будет int)?

Поскольку список не является массивом, а элемент списка - это ссылка, а не объект.

Когда мы действительно используем id( )функцию?

Почти никогда. id()(или его эквивалент) используется в isоператоре.

Робᵩ
источник
Обычно мы используем id () в демонстрационных целях, например, здесь stackoverflow.com/questions/17246693/…
Набин
50

Это идентичность местоположения объекта в памяти ...

Этот пример может помочь вам немного лучше понять концепцию.

foo = 1
bar = foo
baz = bar
fii = 1

print id(foo)
print id(bar)
print id(baz)
print id(fii)

> 1532352
> 1532352
> 1532352
> 1532352

Все они указывают на одно и то же место в памяти, поэтому их значения одинаковы. В примере 1сохраняется только один раз, и все остальное, на что указывает, 1будет ссылаться на эту ячейку памяти.

brbcoding
источник
9
Но если вы используете числа за пределами диапазона от -5 до 256, вы не получите тот же идентификатор для переменной fii.
saurav
это очень интересно. Вы можете поделиться еще?
jouell
3
Я думаю, что этот ответ вводит в заблуждение, так как это не верно для большинства чисел; см. Оператор «is» неожиданно ведет себя с целыми числами .
kevinji
9

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

int *arr[3];
arr[0] = malloc(sizeof(int));
*arr[0] = 1;
arr[1] = malloc(sizeof(int));
*arr[1] = 2;
arr[2] = malloc(sizeof(int));
*arr[2] = 3;
printf("%p %p %p", arr[0], arr[1], arr[2]);

Другими словами, вы печатаете адрес из ссылки, а не адрес относительно того, где хранится ваш список.

В моем случае я нашел эту id()функцию удобной для создания непрозрачных дескрипторов для возврата к коду C при вызове pythonиз C. Сделав это, вы можете легко использовать словарь для поиска объекта по его дескриптору, и он гарантированно будет уникальным.

Фатальная ошибка
источник
8

Ответ Роба (получивший наибольшее количество голосов выше) правильный. Я хотел бы добавить, что в некоторых ситуациях использование идентификаторов полезно, так как позволяет сравнивать объекты и определять, какие объекты относятся к вашим объектам.

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

Недавно у меня была эта проблема с приложением Python / Tkinter, где редактирование текста в одном поле ввода текста меняло текст в другом, когда я печатал :)

Вот пример того, как вы можете использовать функцию id (), чтобы отслеживать, где находятся эти ссылки. Конечно, это не решение, охватывающее все возможные случаи, но идею вы поняли. И снова идентификаторы используются в фоновом режиме, и пользователь их не видит:

class democlass:
    classvar = 24

    def __init__(self, var):
        self.instancevar1 = var
        self.instancevar2 = 42

    def whoreferencesmylocalvars(self, fromwhere):
        return {__l__: {__g__
                    for __g__ in fromwhere
                        if not callable(__g__) and id(eval(__g__)) == id(getattr(self,__l__))
                    }
                for __l__ in dir(self)
                    if not callable(getattr(self, __l__)) and __l__[-1] != '_'
                }

    def whoreferencesthisclassinstance(self, fromwhere):
        return {__g__
                    for __g__ in fromwhere
                        if not callable(__g__) and id(eval(__g__)) == id(self)
                }

a = [1,2,3,4]
b = a
c = b
democlassinstance = democlass(a)
d = democlassinstance
e = d
f = democlassinstance.classvar
g = democlassinstance.instancevar2

print( 'My class instance is of', type(democlassinstance), 'type.')
print( 'My instance vars are referenced by:', democlassinstance.whoreferencesmylocalvars(globals()) )
print( 'My class instance is referenced by:', democlassinstance.whoreferencesthisclassinstance(globals()) )

ВЫВОД:

My class instance is of <class '__main__.democlass'> type.
My instance vars are referenced by: {'instancevar2': {'g'}, 'classvar': {'f'}, 'instancevar1': {'a', 'c', 'b'}}
My class instance is referenced by: {'e', 'd', 'democlassinstance'}

Подчеркивание в именах переменных используется для предотвращения конфликтов имен. Функции используют аргумент «откуда», чтобы вы могли сообщить им, где начать поиск ссылок. Этот аргумент заполняется функцией, которая перечисляет все имена в данном пространстве имен. Globals () - одна из таких функций.

Ариджан
источник
Отличное объяснение!
Neeraj Verma
5

Я начинаю с python и использую id, когда использую интерактивную оболочку, чтобы узнать, назначены ли мои переменные одному и тому же объекту или они просто выглядят одинаково.

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

lontgomjr
источник
5

Если вы используете python 3.4.1, вы получите другой ответ на свой вопрос.

list = [1,2,3]
id(list[0])
id(list[1])
id(list[2])

возвращает:

1705950792   
1705950808  # increased by 16   
1705950824  # increased by 16

Целые числа -5должны 256иметь постоянный идентификатор, и при нахождении его несколько раз его идентификатор не меняется, в отличие от всех других чисел до или после него, которые имеют разные идентификаторы каждый раз, когда вы его находите. Числа от -5до 256имеют идентификаторы в порядке возрастания и отличаются на 16.

Число, возвращаемое id()функцией, является уникальным идентификатором, присвоенным каждому элементу, хранящемуся в памяти, и аналогично тому, как местоположение в памяти в C.

Дхванан Шах
источник
2

Ответ почти никогда. Идентификаторы в основном используются внутри Python.

Среднему программисту Python, вероятно, никогда не понадобится использовать его id()в своем коде.

Гарет Латти
источник
3
Возможно я не средний, но пользуюсь id()совсем немного. Два случая использования вне моей головы: идентификационный dict (ручной, ad-hoc) и обычай repr()для объекта, где идентичность имеет значение, но значение по умолчанию reprне подходит.
5
@delnan Я бы не стал спорить, что это обычные случаи.
Гарет Латти,
2

isОператор использует его , чтобы проверить , являются ли два объекта идентичны (в отличие от равных). Фактическое значение, которое возвращается из id(), практически никогда не используется ни для чего, потому что на самом деле оно не имеет значения и зависит от платформы.

омз
источник
2

Это адрес объекта в памяти, как сказано в документе. Однако к нему прикреплены метаданные, свойства объекта и место в памяти необходимы для хранения метаданных. Итак, когда вы создаете свою переменную с именем list, вы также создаете метаданные для списка и его элементов.

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

Лайош Арпад
источник
1
На самом деле, быть гуру Python бесполезно для предсказания каких-либо объектов id(). Вы должны быть хорошо знакомы с рассматриваемыми менеджерами памяти (во множественном числе!), Знать их точное состояние в какой-то момент времени и знать точный порядок, в котором были размещены объекты. Другими словами: этого не произойдет.
Вы абсолютный гуру Python, если абсолютно знаете все его нюансы, включая возможные менеджеры памяти.
Лайош Арпад,
1
Знание Python и конкретной реализации (например, CPython) - две совершенно разные вещи. И даже знание CPython наизнанку не поможет, поскольку есть несколько вызовов CPython менеджеров памяти, которые не являются частью CPython, а являются частью соответствующей операционной системы. И, как я уже говорил ранее, даже знание всех этих вещей, отличных от Python, вам не поможет, поскольку фактические адреса зависят от состояния выполнения диспетчеров памяти, а иногда даже случайны.
1
Не говоря уже о том, что было бы бесполезно знать, поскольку полагаться на такую ​​вещь будет зависеть от деталей реализации и, следовательно, будет хрупким и негибким.
Gareth Latty
2

У меня есть идея использовать значение id()в логировании.
Это дешево, и оно довольно короткое.
В моем случае я использую торнадо и id()хотел бы иметь привязку для группировки сообщений, разбросанных и смешанных по файлу через веб-сокет.

Даниэль С. Яицков
источник
0

В python 3 id присваивается значение, а не переменная. Это означает, что если вы создадите две функции, как показано ниже, все три идентификатора будут одинаковыми.

>>> def xyz():
...     q=123
...     print(id(q))
...
>>> def iop():
...     w=123
...     print(id(w))
>>> xyz()
1650376736
>>> iop()
1650376736
>>> id(123)
1650376736
Асиш Кумар
источник
Несмотря на то, что это противоречит предыдущим объяснениям, кажется, что это происходит, и я не знаю почему. Любое объяснение? Например, x [0] = "abc" x [1] = "def" q = ["abc", "def"]. Id (x) == Id (q) истинно. Стечение обстоятельств?
VMMF
0

Я немного опоздал и расскажу о Python3. Чтобы понять, что такое id () и как он (и Python) работает, рассмотрим следующий пример:

>>> x=1000
>>> y=1000
>>> id(x)==id(y)
False
>>> id(x)
4312240944
>>> id(y)
4312240912
>>> id(1000)
4312241104
>>> x=1000
>>> id(x)
4312241104
>>> y=1000
>>> id(y)
4312241200

Вы должны думать обо всем, что находится справа, как об объектах. Каждый раз, когда вы делаете присвоение - вы создаете новый объект, а это означает новый идентификатор. Посередине вы можете увидеть «дикий» объект, который создается только для функции - id (1000). Итак, это время жизни только для этой строки кода. Если вы проверите следующую строку - вы увидите, что когда мы создаем новую переменную x, она имеет тот же идентификатор, что и этот дикий объект. В значительной степени это работает как адрес памяти.

Томас
источник
0

Будьте осторожны (относительно ответа чуть ниже) ... Это правда только потому, что 123 находится между -5 и 256 ...

In [111]: q = 257                                                         

In [112]: id(q)                                                            
Out[112]: 140020248465168

In [113]: w = 257                                                         

In [114]: id(w)                                                           
Out[114]: 140020274622544

In [115]: id(257)                                                         
Out[115]: 140020274622768
гы
источник