访问对象内存地址

发布于 2024-07-05 03:25:59 字数 251 浏览 12 评论 0原文

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

<__main__.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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

北城孤痞 2024-07-12 03:25:59

您可以使用内置'str<的'partition'方法获取任何对象的内存地址/位置/strong>' 类型。

下面是一个使用它来获取对象内存地址的示例:

Python 3.8.3 (default, May 27 2020, 02:08:17)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> object.__repr__(1)
'<int object at 0x7ca70923f0>'
>>> hex(int(object.__repr__(1).partition('object at ')[2].strip('>'), 16))
0x7ca70923f0
>>>

这里,我使用内置的 'object' class' '__repr__< /code>' 方法,使用 1 等对象/项目作为返回字符串的参数,然后我对该字符串进行分区,这将在我提供的字符串之前返回字符串的元组,我提供的字符串,然后是我提供的字符串后面的字符串,并且由于内存位置位于“object at”之后,因此我可以获得内存地址,因为它已将其与该部分分区。

然后,当内存地址作为返回元组中的第三项返回时,我可以使用元组中的索引 2 访问它。 但是,它在我获得的字符串中有一个直角括号作为后缀,因此我使用 'strip' 函数将其删除,这将返回不带尖括号的字符串。 然后我将结果字符串转换为以 16 为基数的整数,然后将其转换为十六进制数字。

You can get the memory address/location of any object by using the 'partition' method of the built-in 'str' type.

Here is an example of using it to get the memory address of an object:

Python 3.8.3 (default, May 27 2020, 02:08:17)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> object.__repr__(1)
'<int object at 0x7ca70923f0>'
>>> hex(int(object.__repr__(1).partition('object at ')[2].strip('>'), 16))
0x7ca70923f0
>>>

Here, I am using the built-in 'object' class' '__repr__' method with an object/item such as 1 as an argument to return the string and then I am partitioning that string which will return a tuple of the string before the string that I provided, the string that I provided and then the string after the string that I provided, and as the memory location is positioned after 'object at', I can get the memory address as it has partitioned it from that part.

And then as the memory address was returned as the third item in the returned tuple, I can access it with index 2 from the tuple. But then, it has a right angled bracket as a suffix in the string that I obtained, so I use the 'strip' function to remove it, which will return it without the angled bracket. I then transformed the resulted string into an integer with base 16 and then turn it into a hex number.

后知后觉 2024-07-12 03:25:59

虽然 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.

静待花开 2024-07-12 03:25:59

如果__repr__重载,您可以考虑__str__来查看变量的内存地址。

以下是 __repr__的详细信息>__str__,作者:StackOverflow 中的 Moshe Zadka

If the __repr__ is overloaded, you may consider __str__ to see the memory address of the variable.

Here is the details of __repr__ versus __str__ by Moshe Zadka in StackOverflow.

英雄似剑 2024-07-12 03:25:59

我知道这是一个老问题,但如果你现在还在用 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>'
愁以何悠 2024-07-12 03:25:59

有一种方法可以从“id”命令中恢复值,这里是 TL;DR。

ctypes.cast(memory_address,ctypes.py_object).value

来源

There is a way to recovery the value from the 'id' command, here it the TL;DR.

ctypes.cast(memory_address,ctypes.py_object).value

source

樱花细雨 2024-07-12 03:25:59

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

id(self)

You can get something suitable for that purpose with:

id(self)
甜宝宝 2024-07-12 03:25:59

实现相同的目标

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

使用 ctypes,您可以通过文档

addressof(C 实例) -> 整数
返回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

晨敛清荷 2024-07-12 03:25:59

Python 手册有关于 id()< 的说明/代码>:

返回对象的“身份”。
这是一个整数(或长整数)
保证是唯一的并且
该对象在其期间保持不变
寿命。 两个物体与
不重叠的生命周期可能有
相同的 id() 值。 (CPython实现细节:这是对象在内存中的地址。)

因此在 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. (CPython implementation detail: This is the address of the object in memory.)

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.

度的依靠╰つ 2024-07-12 03:25:59

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

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))
    )
半世晨晓 2024-07-12 03:25:59

只需使用

id(object)

Just use

id(object)
仅一夜美梦 2024-07-12 03:25:59

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

首先, id 仅返回:

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


在 CPython 中,这恰好是指向 PyObject 的指针 表示解释器中的对象,与 object.__repr__ 显示的内容相同。 但这只是 CPython 的一个实现细节,而不是一般 Python 的情况。 Jython 不处理指针,它处理 Java 引用(JVM 当然可能将其表示为指针,但您看不到它们,也不想看到它们,因为允许 GC 移动它们)。 PyPy 允许不同类型具有不同类型的 id,但最常见的只是您调用 id 的对象表的索引,这显然不会成为一个指针。 我不确定 IronPython,但我怀疑在这方面它更像是 Jython 而不是 CPython。 因此,在大多数 Python 实现中,无法获取该 repr 中显示的任何内容,即使获取也没有任何用处。


但是如果您只关心 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 代码怎么办? 您可以使用 调用完全相同的函数来自 ctypes 的 pythonapi


最后,其他一些答案提出了 ctypes.addressof。 这与这里无关。 这只适用于 ctypes 对象,例如 c_int32(可能还有一些类似内存缓冲区的对象,例如 numpy 提供的对象)。 而且,即使在那里,它也不会为您提供 c_int32 值的地址,而是为您提供 c_int32< 所对应的 C 级 int32 的地址。 /code> 结束。

话虽如此,通常情况下,如果您确实认为需要某个东西的地址,那么您首先不需要本机 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.

雄赳赳气昂昂 2024-07-12 03:25:59

只是为了回应 Torsten,我无法在常规 python 对象上调用 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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文