有两个.py文件
test.py
# coding=utf-8
from itertools import chain
def task():
c = [1, 21, 31, 4, 51, 61, 71]
d = ['a1', 'b1', 'c', 'd', 'e1', 'f', 'g1']
e = chain(c, d)
return id(e)
test1.py
# coding=utf-8
from test import task
import _ctypes
obj_id = task()
tk = _ctypes.PyObj_FromPtr(int(obj_id))
next(tk)
运行 test1 脚本时发生异常,如下所示:
StopIteration
我需要在脚本中返回一个对象地址,并在另一个脚本中按对象地址获取对象。
备注:这个想法可行吗?
谢谢!
你正在尝试的是UndefinedBehavior。下面是一个更简单的示例:
code00.py:
#!/usr/bin/env python3
import sys
import _ctypes
def func():
custom_object = [1, 2]
return id(custom_object)
def main():
addr = func()
print("Address: {0:d} (0x{1:016X})".format(addr, addr))
o = _ctypes.PyObj_FromPtr(addr)
print(type(o))
print(o)
print(dir(o))
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}n".format(" ".join(item.strip() for item in sys.version.split("n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("nDone.")
输出:
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq057805717]> "e:WorkDevVEnvspy_064_03.07.03_test0Scriptspython.exe" code00.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 Address: 2221013745352 (0x000002051EBC3EC8) <class 'list'> [cfati@CFATI-5510-0:e:WorkDevStackOverflowq057805717]> echo %errorlevel% -1073741819 [cfati@CFATI-5510-0:e:WorkDevStackOverflowq057805717]> "e:WorkDevVEnvspy_064_02.07.15_test0Scriptspython.exe" code00.py Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] 64bit on win32 Address: 57931144 (0x000000000373F588) <type 'list'> [[...]] ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] Done.
如图所示,该程序:
- 蟒蛇3:崩溃
- Python 2:没有崩溃,但"重建"的对象是垃圾
为什么?
- custom_object是在func中创建 的
- 正在返回其地址
- 但是当函数返回时,对象也会被安排删除(在下一步之前可能会也可能不会发生,具体取决于gc(
- 使用对象地址(这是一个悬空指针(
解决此问题的最明显方法是将对象(要返回其地址(置于函数之外,以便在使用其地址时它仍然有效。这是您的示例(我将其全部保存在一个文件中,但您可以将其拆分为 2(。
code01.py:
#!/usr/bin/env python3
import sys
import _ctypes
import itertools
c = [1, 21, 31, 4, 51, 61, 71]
d = ["a1", "b1", "c", "d", "e1", "f", "g1"]
custom_object = itertools.chain(c, d)
def func():
global custom_object
return id(custom_object)
def main():
addr = func()
print("Address: {0:d} (0x{1:016X})".format(addr, addr))
o = _ctypes.PyObj_FromPtr(addr)
print(type(o))
print(o)
print(dir(o))
try:
while True:
print(next(o))
except StopIteration:
pass
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}n".format(" ".join(item.strip() for item in sys.version.split("n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("nDone.")
输出:
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq057805717]> "e:WorkDevVEnvspy_064_03.07.03_test0Scriptspython.exe" code01.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 Address: 1519278021096 (0x00000161BC06D9E8) <class 'itertools.chain'> <itertools.chain object at 0x000002B3795337F0> ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 'from_iterable'] 1 21 31 4 51 61 71 a1 b1 c d e1 f g1 Done.
说明:
- 这解决了您当前的问题。但无论如何,这个问题有点不寻常。你为什么需要它?应该有其他(更清洁(的方法来实现你的目标。这是设计错误或XY问题的信号。检查 [SO]:是否可以取消引用变量 id?
- 你不依赖[Python 3.Docs]:ctypes - Python公共API的外部函数库,这意味着
_ctypes.PyObj_FromPtr
在未来的 Python版本中可能不可用,或者它的行为可能会在不通知的情况下发生变化- 通常ctypes函数仅适用于ctypes对象。有点奇怪的是,这个对象正在处理任何类型的对象(尽管它返回了一个PyObject(在CPython实现中是"万物之父"(指针(