После просмотра беседы на форуме из многих лет назад, которая никогда не была решена, мне стало интересно, как правильно создать кортеж, который ссылался на себя. Технически это очень плохая идея, поскольку кортежи должны быть неизменными. Как может неизменный объект, возможно, содержать себя? Однако этот вопрос не касается лучших практик, а является запросом о том, что возможно в 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')
Предыдущая функция была разработана для доступа к C API Python, сохраняя при этом внутренние структуры и типы данных. Однако при запуске функции обычно генерируется следующая ошибка. По неизвестным процессам до этого можно было создать саморегуляционный кортеж.
Вопрос: Как должна быть изменена функция 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
>>>
Изменить: Вот два разных диалога с интерпретатором, которые несколько запутывают. Приведенный выше код представляется правильным, если я правильно понимаю документацию. Однако нижеприведенные беседы кажутся как конфликтующими друг с другом, так и с функцией 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
>>>