我第一次使用 next 获取迭代器中的元素时,会抛出异常



有两个.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:没有崩溃,但"重建"的对象是垃圾

为什么?

  1. custom_object是在func中创建
  2. 正在返回其地址
  3. 但是当函数返回时,对象也会被安排删除(在下一步之前可能会也可能不会发生,具体取决于gc(
  4. 使用对象地址(这是一个悬空指针(

解决此问题的最明显方法是将对象(要返回其地址(置于函数之外,以便在使用其地址时它仍然有效。这是您的示例(我将其全部保存在一个文件中,但您可以将其拆分为 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实现中是"万物之父"(指针(

最新更新