id () 함수는 무엇에 사용됩니까?


99

Python 2 문서를 읽고 id()함수를 발견했습니다 .

객체의 "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은 객체가 malloc 및 해제 될 때 스크램블되는 힙에서 할당합니다.
tdelaney

파이썬 숫자는 단순한 데이터 조각이 아닙니다. 내부적으로 long을 사용하여 시작한 다음 값이 너무 커지면 BigNumber 스타일 표현으로 자동 승격하는 객체입니다.
Gareth Latty 2013 년

답변:


156

귀하의 게시물에는 몇 가지 질문이 있습니다.

함수에서 반환 된 숫자는 무엇입니까?

" 수명 동안이 객체에 대해 고유하고 상수가 보장되는 정수 (또는 긴 정수)입니다. " (Python 표준 라이브러리-내장 함수) 고유 한 숫자입니다. 그 이상도 그 이하도 아닙니다. Python 객체에 대한 사회 보장 번호 또는 직원 ID 번호로 생각하십시오.

C의 메모리 주소와 동일합니까?

개념적으로는 그렇습니다. 둘 다 평생 동안 우주에서 독특함을 보장한다는 점에서 그렇습니다. 그리고 파이썬의 특정 구현에서는 실제로 해당 C 객체의 메모리 주소입니다.

그렇다면 데이터 유형의 크기만큼 숫자가 즉시 증가하지 않는 이유는 무엇입니까 (정수라고 가정합니다)?

목록은 배열이 아니고 목록 요소는 객체가 아니라 참조이기 때문입니다.

우리는 언제 실제로 id( )기능을 사용 합니까?

거의 없습니다. id()(또는 이에 상응하는) is연산자 가 사용됩니다 .


우리는 여기에 같은 데모 목적에 일반적으로 ID를 ()를 사용 stackoverflow.com/questions/17246693/...
Nabin

49

그것은 메모리에있는 물체 의 위치 에 대한 정체입니다 .

이 예는 개념을 좀 더 이해하는 데 도움이 될 수 있습니다.

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은 해당 메모리 위치를 참조합니다.


9
그러나 -5에서 256 범위를 초과하는 숫자를 사용하면 fii 변수에 대해 동일한 ID를 얻지 못합니다.
saurav

매우 흥미 롭습니다. 더 많이 공유 할 수 있습니까?
jouell

3
나는 이것이 대부분의 숫자에 대해 사실이 아니기 때문에이 대답은 오해의 소지가 있다고 생각합니다. "is"연산자가 정수로 예기치 않게 동작하는 것을 참조하십시오 .
kevinji 19

8

id()참조되는 객체의 주소를 반환하지만 (CPython에서) 파이썬 목록이 C 배열과 매우 다르다는 사실에서 혼란이 발생합니다. 파이썬 목록에서 모든 요소는 참조 입니다. 그래서 당신이하는 일은이 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 코드로 돌아가는 불투명 핸들을 만드는 데 편리한 함수를 찾았습니다 . 이렇게하면 사전을 사용하여 해당 핸들에서 객체를 쉽게 찾을 수 있으며 고유함이 보장됩니다.


7

Rob의 대답 (위에서 가장 많이 투표)이 맞습니다. 어떤 상황에서는 ID를 사용하는 것이 개체를 비교하고 어떤 개체가 개체를 참조하는지 찾을 수 있기 때문에 유용하다는 점을 추가하고 싶습니다.

나중에는 일반적으로 변경 가능한 객체가 매개 변수로 전달되어 클래스를 말하고 클래스의 로컬 변수에 할당되는 이상한 버그를 디버그하는 데 도움이됩니다. 이러한 개체를 변경하면 클래스의 변수가 변경됩니다. 이것은 동시에 여러 가지가 변경되는 이상한 행동으로 나타납니다.

최근에 한 텍스트 입력 필드의 텍스트를 편집하면 입력 한대로 다른 텍스트를 변경하는 Python / Tkinter 앱에서이 문제가 발생했습니다. :)

다음은 해당 참조가있는 위치를 추적하기 위해 함수 id ()를 사용하는 방법에 대한 예입니다. 이것은 가능한 모든 경우를 포괄하는 솔루션은 아니지만 아이디어를 얻을 수 있습니다. 다시 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'}

변수 이름의 밑줄은 이름 충돌을 방지하는 데 사용됩니다. 함수는 "fromwhere"인수를 사용하므로 참조 검색을 시작할 위치를 알 수 있습니다. 이 인수는 주어진 네임 스페이스의 모든 이름을 나열하는 함수로 채워집니다. Globals ()는 그러한 함수 중 하나입니다.


훌륭한 설명!
Neeraj Verma

5

나는 파이썬으로 시작하고 있으며 대화 형 쉘을 사용할 때 내 변수가 동일한 것에 할당되었는지 또는 동일하게 보이는지 확인하기 위해 id를 사용합니다.

모든 값은 컴퓨터의 메모리에 저장된 위치와 관련된 고유 번호 인 ID입니다.


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

정수 는 상수 ID -5256가지며 여러 번 찾을 때마다 ID가 다른 다른 모든 숫자와 달리 ID가 변경되지 않습니다. 에서 오는 숫자 는 오름차순으로 ID -5256가지며 16.

id()함수가 반환하는 숫자는 메모리에 저장된 각 항목에 부여 된 고유 한 ID이며 C의 메모리 위치와 유사합니다.


2

대답은 거의 없습니다. ID는 주로 Python 내부에서 사용됩니다.

평균적인 파이썬 프로그래머는 아마도 id()코드에서 사용할 필요가 없을 것입니다 .


3
아마도 평균은 아니지만 id()꽤 많이 사용 합니다. 내 머리 위에 두 가지 사용 사례 : (수작업, 임시) ID dict와 repr()ID가 중요하지만 기본값 repr이 적절하지 않은 개체에 대한 사용자 지정 .

5
@delnan 나는 그것들이 일반적인 경우라고 주장하지 않을 것입니다.
Gareth Latty 2013 년

2

is연산자 (동일 대조적으로) 두 물체가 동일한 지 확인하는 데 이용한다. 반환 된 실제 값은 id()실제로 의미가없고 플랫폼에 따라 다르기 때문에 거의 사용되지 않습니다.


2

문서가 말한 그대로 메모리에있는 객체의 주소입니다. 그러나 메타 데이터가 첨부되어 있으며, 메타 데이터를 저장하려면 객체의 속성과 메모리의 위치가 필요합니다. 따라서 list라는 변수를 만들 때 목록 및 해당 요소에 대한 메타 데이터도 만듭니다.

따라서 언어에 대한 절대적인 전문가가 아니라면 이전 요소를 기반으로 목록의 다음 요소 ID를 결정할 수 없습니다. 언어가 요소와 함께 무엇을 할당하는지 모르기 때문입니다.


1
사실, 파이썬 전문가가된다는 것은 어떤 객체의 id(). 문제의 메모리 관리자 (복수형!)에 대해 잘 알고 있어야하고, 특정 시점에서 정확한 상태를 알고, 객체가 할당 된 정확한 순서를 알아야합니다. 즉, 일어나지 않을 것입니다.

가능한 메모리 관리자를 포함하여 모든 뉘앙스를 절대적으로 알고 있다면 당신은 절대적인 Python 전문가입니다.
Lajos Arpad 2013 년

1
Python을 알고 특정 구현 (예 : CPython)을 아는 것은 완전히 다른 두 가지입니다. CPython의 일부가 아니라 각 운영 체제의 일부인 CPython이 호출하는 여러 메모리 관리자 가 있기 때문에 CPython을 완전히 아는 것조차 도움 이되지 않습니다. 그리고 이전에 말했듯이 실제 주소는 메모리 관리자의 런타임 상태에 따라 다르며 때로는 무작위로 지정되기 때문에 Python이 아닌 모든 것을 아는 것조차 도움이되지 않습니다.

1
말할 것도없이, 그러한 것에 의존하는 것은 구현 세부 사항에 의존하고 따라서 깨지기 쉽고 유연하지 않기 때문에 아는 것은 쓸모가 없습니다.
Gareth Latty 2013 년

2

id()로깅에의 값을 사용하는 아이디어가 있습니다 .
저렴하고 아주 짧습니다.
제 경우에는 토네이도를 사용 id()하고 웹 소켓별로 파일에 흩어져 있고 혼합 된 메시지를 그룹화하는 앵커를 갖고 싶습니다.


0

파이썬 3에서 id는 변수가 아닌 값에 할당됩니다. 즉, 아래와 같이 두 개의 함수를 만들면 세 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)가 True입니다. 우연의 일치?
VMMF

0

조금 늦었고 Python3에 대해 이야기하겠습니다. id ()가 무엇이며 어떻게 작동하는지 이해하려면 다음 예제를 고려하십시오.

>>> 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를 의미합니다. 중간에는 함수 id (1000)에 대해서만 생성 된 "야생"객체를 볼 수 있습니다. 따라서 수명은 해당 코드 줄에만 해당됩니다. 다음 줄을 확인하면 새 변수 x를 만들 때 해당 야생 개체와 동일한 ID를 갖는 것을 볼 수 있습니다. 거의 메모리 주소처럼 작동합니다.


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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.