There are two .py files
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)
An exception occurred while running the test1 script, like this:
StopIteration
I need to return an object address in a script, and get the object by object address in another script.
Remarks: Is this idea feasible?
Thank you very much!
What you're attempting is Undefined Behavior. Here's a simpler example:
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.")
Output:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q057805717]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.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:\Work\Dev\StackOverflow\q057805717]> echo %errorlevel% -1073741819 [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q057805717]> "e:\Work\Dev\VEnvs\py_064_02.07.15_test0\Scripts\python.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.
As seen, the program:
Why?
The most obvious way of getting around this, is to take the object (whose address you want to return) outside of the function, so that it's still valid when its address will be used. Here's your example (I kept it all in one file, but you can split it in 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.")
Output:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q057805717]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.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.
Notes:
_ctypes.PyObj_FromPtr
might not be available in future Python versions, or its behavior might change without notice