Para que é usada a função id ()?


99

Eu li a documentação do Python 2 e percebi a id()função:

Retorna a “identidade” de um objeto. Este é um inteiro (ou inteiro longo) que é garantido como único e constante para este objeto durante sua vida útil. Dois objetos com tempos de vida não sobrepostos podem ter o mesmo valor id ().

Detalhe de implementação do CPython: Este é o endereço do objeto na memória.

Então, experimentei usar id()com uma lista:

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

Qual é o número inteiro retornado da função? É sinônimo de endereços de memória em C? Em caso afirmativo, por que o número inteiro não corresponde ao tamanho do tipo de dados?

Quando é id()usado na prática?


4
Só porque você armazena (digamos) um int de 32 bits em uma estrutura de dados em uma linguagem de script não significa que estará usando até 32 bits a mais de memória. há SEMPRE metadados anexados a QUALQUER dado que você armazena. tipo, tamanho, comprimento, blá, blá, blá.
Marc B

cpython aloca de um heap que é embaralhado conforme os objetos são malocalizados e liberados.
tdelaney

Os números do Python não são simples dados. Eles são objetos que usam longs internamente para começar e, em seguida, são promovidos automaticamente para uma representação do estilo BigNumber se o valor ficar muito grande.
Gareth Latty

Respostas:


156

Sua postagem traz várias perguntas:

Qual é o número retornado da função?

É " um inteiro (ou inteiro longo) que é garantido como único e constante para este objeto durante sua vida útil. " (Biblioteca padrão do Python - funções integradas) Um número único. Nada mais e nada menos. Pense nisso como um número de segurança social ou número de identificação de funcionário para objetos Python.

É o mesmo com endereços de memória em C?

Conceitualmente, sim, porque ambos têm a garantia de serem únicos em seu universo durante sua vida. E em uma implementação particular do Python, na verdade é o endereço de memória do objeto C correspondente.

Se sim, por que o número não aumenta instantaneamente de acordo com o tamanho do tipo de dados (suponho que seria int)?

Porque uma lista não é um array e um elemento de lista é uma referência, não um objeto.

Quando realmente usamos a id( )função?

Quase nunca. id()(ou seu equivalente) é usado no isoperador.


Usamos id () geralmente para fins de demonstração, como aqui stackoverflow.com/questions/17246693/…
Nabin

49

Essa é a identidade da localização do objeto na memória ...

Este exemplo pode ajudá-lo a entender um pouco mais o conceito.

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

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

> 1532352
> 1532352
> 1532352
> 1532352

Todos eles apontam para o mesmo local na memória, razão pela qual seus valores são os mesmos. No exemplo, 1é armazenado apenas uma vez e qualquer outra coisa que aponte 1fará referência a esse local da memória.


9
Mas se você usar números além do intervalo de -5 a 256, não obterá o mesmo id para a variável fii.
saurav

isso é extremamente interessante. Você pode compartilhar mais?
jouell

3
Acho que essa resposta é enganosa, pois não é verdade para a maioria dos números; consulte o operador “is” se comporta inesperadamente com números inteiros .
kevinji

8

id()retorna o endereço do objeto que está sendo referenciado (em CPython), mas sua confusão vem do fato de que as listas python são muito diferentes dos arrays C. Em uma lista python, cada elemento é uma referência . Então, o que você está fazendo é muito mais semelhante a este código 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]);

Em outras palavras, você está imprimindo o endereço da referência e não um endereço relativo ao local onde sua lista está armazenada.

No meu caso, achei a id()função útil para criar identificadores opacos para retornar ao código C ao chamar pythonde C. Fazendo isso, você pode facilmente usar um dicionário para consultar o objeto de seu identificador e é garantido que seja exclusivo.


7

A resposta de Rob (mais votada acima) está correta. Gostaria de acrescentar que, em algumas situações, o uso de IDs é útil, pois permite a comparação de objetos e descobrir quais objetos se referem a seus objetos.

O último geralmente ajuda você, por exemplo, a depurar bugs estranhos onde objetos mutáveis ​​são passados ​​como parâmetro para dizer classes e são atribuídos a vars locais em uma classe. Transformar esses objetos irá transformar vars em uma classe. Isso se manifesta em um comportamento estranho, em que várias coisas mudam ao mesmo tempo.

Recentemente, tive esse problema com um aplicativo Python / Tkinter em que editar texto em um campo de entrada de texto alterava o texto em outro conforme eu digitava :)

Aqui está um exemplo de como você pode usar a função id () para rastrear onde essas referências estão. Sem dúvida, essa não é uma solução que abranja todos os casos possíveis, mas essa é a ideia. Novamente, os IDs são usados ​​em segundo plano e o usuário não os vê:

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()) )

RESULTADO:

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'}

Sublinhados em nomes de variáveis ​​são usados ​​para prevenir colisões de nomes. As funções usam o argumento "de onde" para que você possa informá-los por onde começar a procurar por referências. Este argumento é preenchido por uma função que lista todos os nomes em um determinado namespace. Globals () é uma dessas funções.


Ótima explicação!
Neeraj Verma

5

Estou começando com o python e uso id quando uso o shell interativo para ver se minhas variáveis ​​são atribuídas à mesma coisa ou se apenas parecem iguais.

Todo valor é um id, que é um número exclusivo relacionado ao local onde está armazenado na memória do computador.


5

Se você estiver usando o python 3.4.1, obterá uma resposta diferente para sua pergunta.

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

retorna:

1705950792   
1705950808  # increased by 16   
1705950824  # increased by 16

Os números inteiros -5para 256ter um ID de constante, e em encontrá-lo várias vezes o seu ID não muda, ao contrário de todos os outros números antes ou depois de que têm diferentes id é toda vez que você encontrá-lo. Os números de -5que 256têm de id em ordem crescente e diferem por 16.

O número retornado pela id()função é um id único dado a cada item armazenado na memória e é analogamente o mesmo que a localização da memória em C.


2

A resposta é praticamente nunca. Os IDs são usados ​​principalmente internamente para Python.

O programador Python comum provavelmente nunca precisará usar id()em seu código.


3
Talvez eu não seja normal, mas uso id()bastante. Dois casos de uso em minha mente: um dicionário de identidade (enrolado à mão, ad-hoc) e um custom repr()para um objeto onde a identidade é importante, mas o padrão reprnão é apropriado.

5
@delnan Eu não diria que esses são casos comuns.
Gareth Latty

2

O isoperador o usa para verificar se dois objetos são idênticos (em oposição a iguais). O valor real que é retornado id()quase nunca é usado para nada porque ele realmente não tem um significado e depende da plataforma.


2

É o endereço do objeto na memória, exatamente como diz o doc. No entanto, ele possui metadados anexados, propriedades do objeto e localização na memória são necessárias para armazenar os metadados. Portanto, ao criar sua variável chamada lista, você também cria metadados para a lista e seus elementos.

Então, a menos que você seja um guru absoluto na linguagem, você não pode determinar o id do próximo elemento de sua lista com base no elemento anterior, porque você não sabe o que a linguagem aloca junto com os elementos.


1
Na verdade, ser um guru do Python não será muito útil para prever qualquer objeto id(). Você precisaria estar intimamente familiarizado com os gerenciadores de memória (plural!) Em questão, saber seu estado exato em algum ponto no tempo e saber a ordem exata em que os objetos foram alocados. Em outras palavras: não vai acontecer.

Você é um guru absoluto do Python se souber absolutamente todas as suas nuances, incluindo os possíveis gerenciadores de memória.
Lajos Arpad

1
Conhecer Python e conhecer uma implementação específica (por exemplo, CPython) são duas coisas totalmente diferentes. E mesmo conhecer o CPython de dentro para fora não ajudará, pois existem vários gerenciadores de memória que o CPython chama que não fazem parte do CPython, mas sim do respectivo sistema operacional. E como eu disse antes, mesmo sabendo de todas essas coisas não Python não ajudará você, já que os endereços reais dependem do estado de tempo de execução dos gerenciadores de memória e às vezes são até aleatórios.

1
Sem mencionar que seria inútil saber, pois confiar em tal coisa seria confiar em um detalhe de implementação e, portanto, seria frágil e inflexível.
Gareth Latty

2

Eu tenho uma ideia de usar o valor de id()no registro.
É barato e bastante curto.
No meu caso utilizo o tornado e id()gostaria de ter uma âncora para agrupar mensagens espalhadas e misturadas arquivo por web socket.


0

Em python 3 id é atribuído a um valor, não a uma variável. Isso significa que se você criar duas funções como abaixo, todos os três ids serão iguais.

>>> def xyz():
...     q=123
...     print(id(q))
...
>>> def iop():
...     w=123
...     print(id(w))
>>> xyz()
1650376736
>>> iop()
1650376736
>>> id(123)
1650376736

Mesmo que isso contradiga as explicações anteriores, parece acontecer e não sei por quê. Alguma explicação? Por exemplo, x [0] = "abc" x [1] = "def" q = ["abc", "def"]. Id (x) == Id (q) é verdadeiro. Coincidência?
VMMF

0

Estou um pouco atrasado e vou falar sobre Python3. Para entender o que é id () e como funciona (e Python), considere o próximo exemplo:

>>> 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

Você precisa pensar em tudo do lado direito como objetos. Cada vez que você faz uma atribuição - você cria um novo objeto e isso significa um novo id. No meio você pode ver um objeto "selvagem" que é criado apenas para a função - id (1000). Portanto, seu tempo de vida é apenas para essa linha de código. Se você verificar a próxima linha - verá que, quando criamos uma nova variável x, ela tem o mesmo id que o objeto selvagem. Quase funciona como endereço de memória.


0

Cuidado (com relação à resposta logo abaixo) ... Isso só é verdade porque 123 está entre -5 e 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.