何年も前のフォーラムで解決されなかった会話を見た後、自分自身を参照するタプルを正しく作成するにはどうすればよいのか疑問に思いました。技術的には、タプルは不変であると想定されているため、これは非常に悪い考えです。不変オブジェクトはどのようにしてそれ自体を含むことができるでしょうか?ただし、この質問はベストプラクティスに関するものではなく、Pythonで何が可能かに関する質問です。
import ctypes
def self_reference(array, index):
if not isinstance(array, tuple):
raise TypeError('array must be a tuple')
if not isinstance(index, int):
raise TypeError('index must be an int')
if not 0 <= index < len(array):
raise ValueError('index is out of range')
address = id(array)
obj_refcnt = ctypes.cast(address, ctypes.POINTER(ctypes.c_ssize_t))
obj_refcnt.contents.value += 1
if ctypes.cdll.python32.PyTuple_SetItem(ctypes.py_object(array),
ctypes.c_ssize_t(index),
ctypes.py_object(array)):
raise RuntimeError('PyTuple_SetItem signaled an error')
以前の関数は、内部構造とデータ型を念頭に置いてPythonのCAPIにアクセスするように設計されていました。ただし、通常、関数の実行時に次のエラーが発生します。未知のプロセスを通じて、以前は同様の手法で自己参照タプルを作成することが可能でした。
質問:self_reference
常に一貫して機能するように関数をどのように変更する必要がありますか?
>>> import string
>>> a = tuple(string.ascii_lowercase)
>>> self_reference(a, 2)
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <module>
self_reference(a, 2)
File "C:/Users/schappell/Downloads/srt.py", line 15, in self_reference
ctypes.py_object(array)):
WindowsError: exception: access violation reading 0x0000003C
>>>
編集:これは、通訳との2つの異なる会話で、やや混乱を招きます。ドキュメントを正しく理解していれば、上記のコードは正しいように見えます。ただし、下の会話は互いに競合しているように見え、self_reference
上の機能も競合しているように見えます。
会話1:
Python 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
on win32
Type "copyright", "credits" or "license()" for more information.
>>> from ctypes import *
>>> array = tuple(range(10))
>>> cast(id(array), POINTER(c_ssize_t)).contents.value
1
>>> cast(id(array), POINTER(c_ssize_t)).contents.value += 1
>>> cast(id(array), POINTER(c_ssize_t)).contents.value
2
>>> array
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> cdll.python32.PyTuple_SetItem(c_void_p(id(array)), 0,
c_void_p(id(array)))
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
cdll.python32.PyTuple_SetItem(c_void_p(id(array)), 0,
c_void_p(id(array)))
WindowsError: exception: access violation reading 0x0000003C
>>> cdll.python32.PyTuple_SetItem(c_void_p(id(array)), 0,
c_void_p(id(array)))
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
cdll.python32.PyTuple_SetItem(c_void_p(id(array)), 0,
c_void_p(id(array)))
WindowsError: exception: access violation reading 0x0000003C
>>> array
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> cdll.python32.PyTuple_SetItem(c_void_p(id(array)), 0,
c_void_p(id(array)))
0
>>> array
((<NULL>, <code object __init__ at 0x02E68C50, file "C:\Python32\lib
kinter\simpledialog.py", line 121>, <code object destroy at 0x02E68CF0,
file "C:\Python32\lib kinter\simpledialog.py", line 171>, <code object
body at 0x02E68D90, file "C:\Python32\lib kinter\simpledialog.py",
line 179>, <code object buttonbox at 0x02E68E30, file "C:\Python32\lib
kinter\simpledialog.py", line 188>, <code object ok at 0x02E68ED0, file
"C:\Python32\lib kinter\simpledialog.py", line 209>, <code object
cancel at 0x02E68F70, file "C:\Python32\lib kinter\simpledialog.py",
line 223>, <code object validate at 0x02E6F070, file "C:\Python32\lib
kinter\simpledialog.py", line 233>, <code object apply at 0x02E6F110, file
"C:\Python32\lib kinter\simpledialog.py", line 242>, None), 1, 2, 3, 4,
5, 6, 7, 8, 9)
>>>
会話2:
Python 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
on win32
Type "copyright", "credits" or "license()" for more information.
>>> from ctypes import *
>>> array = tuple(range(10))
>>> cdll.python32.PyTuple_SetItem(c_void_p(id(array)), c_ssize_t(1),
c_void_p(id(array)))
0
>>> array
(0, (...), 2, 3, 4, 5, 6, 7, 8, 9)
>>> array[1] is array
True
>>>