通过ctypes复制生成器:解决访问冲突及生成器类型转换问题
生成器复制:解决访问冲突与类型转换问题
我尝试通过传入frame对象调用PyGen_New来复制生成器,最初遇到以下访问冲突错误:
Traceback (most recent call last): File "C:\test.py", line 19, in <module> frame = Frame(gen.gi_code) ^^^^^^^^^^^^^^^^^^ File "C:\test.py", line 11, in Frame return ctypes.pythonapi.PyFrame_New( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ OSError: exception: access violation reading 0x0000000000000008
初始使用的代码:
from types import CodeType, FrameType import ctypes ctypes.pythonapi.PyThreadState_Get.argtypes = None ctypes.pythonapi.PyThreadState_Get.restype = ctypes.POINTER(ctypes.c_ulong) ctypes.pythonapi.PyFrame_New.restype = ctypes.POINTER(ctypes.py_object) def Frame(code_obj: CodeType, globals: dict = None, locals: dict = None) -> FrameType: """Instantiates a FrameType object""" return ctypes.pythonapi.PyFrame_New( ctypes.pythonapi.PyThreadState_Get(), ctypes.cast(id(code_obj), ctypes.POINTER(ctypes.c_int)), globals, locals, ) gen = (i for i in range(3)) frame = Frame(gen.gi_code) ctypes.pythonapi.PyGen_New.restype = ctypes.POINTER(ctypes.py_object) new_gen = ctypes.pythonapi.PyGen_New( ctypes.cast(id(frame), ctypes.POINTER(ctypes.c_void_p)) ) for value in new_gen: print(value)
注:已知CPython未设计支持生成器复制与序列化,无需告知相关风险;本次聚焦解决当前访问冲突错误及后续生成器类型转换的具体方案,不追求通用适配;知晓这是使用C层实现细节,无需赘述。代码运行于Python 3.11.9版本。
更新:访问冲突已解决,类型转换待处理
下述代码解决了访问冲突错误,但仍需解决如何将结果转换为实际生成器类型的问题:
from types import CodeType, FrameType import ctypes ctypes.pythonapi.PyFrame_New.argtypes = ( ctypes.POINTER(ctypes.c_ulong), ctypes.POINTER(ctypes.c_ulong), ctypes.py_object, ctypes.py_object ) ctypes.pythonapi.PyFrame_New.restype = ctypes.py_object ctypes.pythonapi.PyThreadState_Get.argtypes = None ctypes.pythonapi.PyThreadState_Get.restype = ctypes.POINTER(ctypes.c_ulong) def Frame(code_obj: CodeType, globals: dict = {}, locals: dict = {}) -> FrameType: """Instantiates a FrameType object""" return ctypes.pythonapi.PyFrame_New( ctypes.pythonapi.PyThreadState_Get(), ctypes.cast(id(code_obj), ctypes.POINTER(ctypes.c_ulong)), globals, locals ) gen = (i for i in range(3)) frame = Frame(gen.gi_code) ctypes.pythonapi.PyGen_New.argtypes = [ctypes.POINTER(ctypes.py_object)] ctypes.pythonapi.PyGen_New.restype = ctypes.POINTER(ctypes.py_object) new_gen = ctypes.pythonapi.PyGen_New( ctypes.cast(id(frame), ctypes.POINTER(ctypes.py_object)) ) ## 以下代码无法运行 ## for value in new_gen: print(value)
内容的提问来源于stack exchange,提问作者Ben Tonks
相关产品推荐
相关产品推荐

