访问对象存储器地址

问题:访问对象存储器地址

当您object.__repr__()在Python中调用该方法时,您会得到类似以下的信息:

<__main__.Test object at 0x2aba1c0cf890> 

如果您过载了__repr__(),还有什么方法可以保留该内存地址,然后调用super(Class, obj).__repr__()并重新分配它呢?

When you call the object.__repr__() method in Python you get something like this back:

<__main__.Test object at 0x2aba1c0cf890> 

Is there any way to get a hold of the memory address if you overload __repr__(), other then calling super(Class, obj).__repr__() and regexing it out?


回答 0

Python的手册已经这样说id()

返回一个对象的“身份”,这是一个整数(或长整数),在该对象的生存期内保证是唯一且恒定的。两个不重叠生存期的对象可能具有相同的id()值。 (实施说明:这是对象的地址。)

因此,在CPython中,这将是对象的地址。但是,没有任何其他Python解释器的此类保证。

请注意,如果您正在编写C扩展名,则可以完全访问Python解释器的内部,包括直接访问对象的地址。

The Python manual has this to say about id():

Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value. (Implementation note: this is the address of the object.)

So in CPython, this will be the address of the object. No such guarantee for any other Python interpreter, though.

Note that if you’re writing a C extension, you have full access to the internals of the Python interpreter, including access to the addresses of objects directly.


回答 1

您可以通过以下方式重新实现默认代表:

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

You could reimplement the default repr this way:

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

回答 2

只需使用

id(object)

Just use

id(object)

回答 3

这里有一些其他答案未涵盖的问题。

首先,id仅返回:

对象的“身份”。这是一个整数(或长整数),在该对象的生存期内,此整数保证是唯一且恒定的。具有非重叠生存期的两个对象可能具有相同的id()值。


在CPython中,这恰好是指向PyObject解释器中代表对象的指针,这与on上的东西相同,显然不会成为指针。我不确定IronPython,但我怀疑在这方面,它更像是Jython,而不是CPython。因此,在大多数Python实现中,无法获得显示在其中的任何内容,如果您这样做了,则毫无用处。object.__repr__显示。但这只是CPython的实现细节,而不是一般Python的真实情况。Jython不处理指针,它处理Java引用(JVM当然可以将其表示为指针,但是您看不到它们,并且也不想这样做,因为允许GC来回移动它们)。PyPy让不同类型的对象具有不同的种类id,但最一般的只是对您已调用的对象表的索引idrepr


但是,如果您只关心CPython怎么办?毕竟,这是一个很普通的情况。

好吧,首先,您可能会注意到这id是一个整数; *如果您想要该0x2aba1c0cf890字符串而不是数字46978822895760,则必须自己设置其格式。在幕后,我相信object.__repr__最终使用printf%p格式,你没有从Python的有……但你总是可以做到这一点:

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则正是您所需要的。

如果您正在编写纯Python代码怎么办?您可以使用pythonapifrom 调用完全相同的函数ctypes


最后,提出了其他一些答案ctypes.addressof。这与这里无关。这仅适用于ctypes类似的对象c_int32(可能还有一些类似内存缓冲区的对象,如所提供的对象numpy)。而且,即使在那儿,它也没有为您提供c_int32值的地址,而是为您提供int32c_int32包装的C级地址。

话虽这么说,但通常情况下,如果您确实认为自己需要某个东西的地址,那么首先就不需要原生Python对象,而是想要一个ctypes对象。

There are a few issues here that aren’t covered by any of the other answers.

First, id only returns:

the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.


In CPython, this happens to be the pointer to the PyObject that represents the object in the interpreter, which is the same thing that object.__repr__ displays. But this is just an implementation detail of CPython, not something that’s true of Python in general. Jython doesn’t deal in pointers, it deals in Java references (which the JVM of course probably represents as pointers, but you can’t see those—and wouldn’t want to, because the GC is allowed to move them around). PyPy lets different types have different kinds of id, but the most general is just an index into a table of objects you’ve called id on, which is obviously not going to be a pointer. I’m not sure about IronPython, but I’d suspect it’s more like Jython than like CPython in this regard. So, in most Python implementations, there’s no way to get whatever showed up in that repr, and no use if you did.


But what if you only care about CPython? That’s a pretty common case, after all.

Well, first, you may notice that id is an integer;* if you want that 0x2aba1c0cf890 string instead of the number 46978822895760, you’re going to have to format it yourself. Under the covers, I believe object.__repr__ is ultimately using printf‘s %p format, which you don’t have from Python… but you can always do this:

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

* In 3.x, it’s an int. In 2.x, it’s an int if that’s big enough to hold a pointer—which is may not be because of signed number issues on some platforms—and a long otherwise.

Is there anything you can do with these pointers besides print them out? Sure (again, assuming you only care about CPython).

All of the C API functions take a pointer to a PyObject or a related type. For those related types, you can just call PyFoo_Check to make sure it really is a Foo object, then cast with (PyFoo *)p. So, if you’re writing a C extension, the id is exactly what you need.

What if you’re writing pure Python code? You can call the exact same functions with pythonapi from ctypes.


Finally, a few of the other answers have brought up ctypes.addressof. That isn’t relevant here. This only works for ctypes objects like c_int32 (and maybe a few memory-buffer-like objects, like those provided by numpy). And, even there, it isn’t giving you the address of the c_int32 value, it’s giving you the address of the C-level int32 that the c_int32 wraps up.

That being said, more often than not, if you really think you need the address of something, you didn’t want a native Python object in the first place, you wanted a ctypes object.


回答 4

仅作为对Torsten的回应,我无法调用addressof()常规的python对象。此外,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

Just in response to Torsten, I wasn’t able to call addressof() on a regular python object. Furthermore, id(a) != addressof(a). This is in CPython, don’t know about anything else.

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

回答 5

使用ctypes,您可以使用

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

说明文件:

addressof(C instance) -> integer
返回C实例内部缓冲区的地址

请注意,在CPython中,当前是id(a) == ctypes.addressof(a),但是ctypes.addressof应返回每个Python实现的真实地址,如果

  • 支持ctypes
  • 内存指针是一个有效的概念。

编辑:添加了有关ctypes解释器独立性的信息

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


回答 6

您可以通过以下方式获得适合该目的的东西:

id(self)

You can get something suitable for that purpose with:

id(self)

回答 7

我知道这是一个老问题,但是如果您现在仍在使用python 3编程,我实际上发现如果它是字符串,那么有一种非常简单的方法可以做到这一点:

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

字符串转换也不影响内存中的位置:

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

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

回答 8

虽然确实id(object)可以在默认的CPython实现中获取对象的地址,但这通常是无用的……您无法纯Python代码中的地址进行任何操作。

实际上,唯一可以使用该地址的时间是来自C扩展库…在这种情况下,获取对象的地址很简单,因为Python对象始终作为C指针传递。

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.