development

객체 메모리 주소 접근

big-blog 2020. 6. 10. 07:53
반응형

객체 메모리 주소 접근


object.__repr__()파이썬 에서 메소드 를 호출하면 다음과 같은 것을 얻습니다.

<__main__.Test object at 0x2aba1c0cf890> 

과부하 __repr__(), 메모리 호출 super(Class, obj).__repr__()및 정규화 이외 의 메모리 주소를 보유 할 수있는 방법이 있습니까?


파이썬 매뉴얼 에 대해 할 말이이있다 id():

객체의 "정체성"을 반환합니다. 이는 수명 동안이 객체에 대해 고유하고 일정하게 보장되는 정수 (또는 긴 정수)입니다. 겹치지 않는 수명을 가진 두 객체는 ​​동일한 id () 값을 가질 수 있습니다. (구현 정보 : 이것은 객체의 주소입니다.)

CPython에서는 이것이 객체의 주소가 될 것입니다. 그러나 다른 파이썬 인터프리터에 대해서는 그러한 보장이 없습니다.

C 확장을 작성하는 경우 객체 주소에 직접 액세스하는 것을 포함하여 Python 인터프리터의 내부에 대한 모든 액세스 권한이 있습니다.


이 방법으로 기본 repr을 다시 구현할 수 있습니다.

def __repr__(self):
    return '<%s.%s object at %s>' % (
        self.__class__.__module__,
        self.__class__.__name__,
        hex(id(self))
    )

그냥 사용

id(object)

여기에 다른 답변으로는 다루지 않는 몇 가지 문제가 있습니다.

먼저 다음 id만 반환합니다.

객체의 "정체성". 이것은 수명 동안이 개체에 대해 고유하고 일정하게 보장되는 정수 (또는 긴 정수)입니다. 겹치지 않는 수명을 가진 두 개체의 id()이 동일 할 수 있습니다 .


CPython에서 이것은 PyObject인터프리터의 객체를 나타내는 포인터에 대한 포인터 이며 이는 object.__repr__표시 되는 것과 동일 합니다. 그러나 이것은 CPython의 구현 세부 사항 일뿐, 일반적으로 Python에서는 사실이 아닙니다. 자이 썬은 포인터를 다루지 않고 자바 참조를 처리한다 (물론 JVM은 포인터로 표현할 수 있지만 GC는 포인터를 움직일 수 있기 때문에 원하지 않는다). PyPy는 서로 다른 유형이 서로 다른 종류를 가질 수 id있지만 가장 일반적인 것은 호출 한 객체 테이블에 대한 인덱스 일뿐입니다.idon, 이것은 분명히 포인터가 될 수 없습니다. IronPython에 대해서는 잘 모르겠지만 CPython과 비교하여 Jython과 더 비슷하다고 생각합니다. 따라서 대부분의 Python 구현에서는 그 안에 표시된 것을 얻을 수있는 방법이 repr없으며 사용하지 않으면 사용할 수 없습니다.


그러나 CPython에만 관심이 있다면 어떨까요? 결국 꽤 일반적인 경우입니다.

먼저, 그것이 id정수임을 알 수 있습니다 . * 0x2aba1c0cf890숫자 대신 해당 문자열 을 원하면 46978822895760직접 형식을 지정해야합니다. 엄밀히 말하면, 나는 object.__repr__궁극적으로 printf%p형식을 사용하고 있다고 생각 합니다. 파이썬에는 없습니다 ...하지만 항상 이렇게 할 수 있습니다 :

format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')

* 3.x에서는 int입니다. 2.x에서는 int포인터를 잡기에 충분할 정도로 큰 경우입니다 (일부 플랫폼에서는 부호있는 숫자 문제가 아닐 수도 있음) long.

인쇄하는 것 외에이 포인터로 할 수있는 일이 있습니까? 물론 (CPython에만 관심이 있다고 가정).

모든 C API 함수 PyObject는 관련 유형 또는 관련 유형에 대한 포인터를 사용합니다 . 이러한 관련 유형의 경우 호출 PyFoo_Check하여 그것이 실제로 Foo객체 인지 확인한 다음로 캐스팅 할 수 (PyFoo *)p있습니다. 따라서 C 확장을 작성하는 경우 id꼭 필요한 것입니다.

순수한 파이썬 코드를 작성한다면 어떨까요? pythonapifrom 와 동일한 함수를 호출 할 수 있습니다 ctypes.


마지막으로, 다른 답변들 중 몇 가지가 나타났습니다 ctypes.addressof. 여기에는 관련이 없습니다. 이것은 ctypes같은 객체 c_int32(및 아마도 제공하는 것과 같은 메모리 버퍼와 같은 객체) 에서만 작동합니다 numpy. 그리고, 심지어 거기, 당신에게의 주소를 제공하지 않는 c_int32당신에게 C 레벨의 주소를주고, 값이 int32(가) 것을 c_int32래핑합니다.

당신이 정말로 무언가의 주소가 필요하다고 생각한다면, 처음에는 네이티브 파이썬 객체를 원하지 않았고 객체를 원했습니다 ctypes.


Torsten에 대한 응답으로 addressof()일반 파이썬 객체 를 호출 할 수 없었습니다 . 또한 id(a) != addressof(a). 이것은 CPython에 있으며 다른 것에 대해서는 모른다.

>>> from ctypes import c_int, addressof
>>> a = 69
>>> addressof(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: invalid type
>>> b = c_int(69)
>>> addressof(b)
4300673472
>>> id(b)
4300673392

With ctypes, you can achieve the same thing with

>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L

Documentation:

addressof(C instance) -> integer
Return the address of the C instance internal buffer

Note that in CPython, currently id(a) == ctypes.addressof(a), but ctypes.addressof should return the real address for each Python implementation, if

  • ctypes is supported
  • memory pointers are a valid notion.

Edit: added information about interpreter-independence of ctypes


You can get something suitable for that purpose with:

id(self)

While it's true that id(object) gets the object's address in the default CPython implementation, this is generally useless... you can't do anything with the address from pure Python code.

The only time you would actually be able to use the address is from a C extension library... in which case it is trivial to get the object's address since Python objects are always passed around as C pointers.


I know this is an old question but if you're still programming, in python 3 these days... I have actually found that if it is a string, then there is a really easy way to do this:

>>> spam.upper
<built-in method upper of str object at 0x1042e4830>
>>> spam.upper()
'YO I NEED HELP!'
>>> id(spam)
4365109296

string conversion does not affect location in memory either:

>>> spam = {437 : 'passphrase'}
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
>>> str(spam)
"{437: 'passphrase'}"
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'

참고URL : https://stackoverflow.com/questions/121396/accessing-object-memory-address

반응형