我从一个看起来很严肃的来源下载了一个Sage脚本。但它在我的电脑上无法运行,快速调试显示一个问题是因为某些时候,作者在处理n个元素的列表时,将其从1到n编号(而“正常”的Python和(因此)Sage的编号是0..n-1)。
我错过了什么?有没有全局变量隐藏在某处改变了这种约定,就像APL一样?
感谢您的帮助(尽管我的英语和CSish都很薄弱,但我希望我的问题很清楚...)
我从一个看起来很严肃的来源下载了一个Sage脚本。但它在我的电脑上无法运行,快速调试显示一个问题是因为某些时候,作者在处理n个元素的列表时,将其从1到n编号(而“正常”的Python和(因此)Sage的编号是0..n-1)。
我错过了什么?有没有全局变量隐藏在某处改变了这种约定,就像APL一样?
感谢您的帮助(尽管我的英语和CSish都很薄弱,但我希望我的问题很清楚...)
Python(包括sage)的列表始终从0开始编号,无法更改。
查看CPython源代码,在http://hg.python.org/cpython/file/70274d53c1dd/Objects/listobject.c的第449行:
static PyObject *
list_item(PyListObject *a, Py_ssize_t i)
{
if (i < 0 || i >= Py_SIZE(a)) {
if (indexerr == NULL) {
indexerr = PyString_FromString(
"list index out of range");
if (indexerr == NULL)
return NULL;
}
PyErr_SetObject(PyExc_IndexError, indexerr);
return NULL;
}
Py_INCREF(a->ob_item[i]);
return a->ob_item[i];
}
class Array(object):
def __init__(self, items: list) -> None:
self.items = items
def __repr__(self) -> str:
return '{}({})'.format(self.__class__.__name__, self.items)
def __len__(self) -> int:
return len(self.items)
def __contains__(self, item: any) -> bool:
return item in self.items
def __getitem__(self, key: int) -> any:
return self.items[key - 1]
def __setitem__(self, key: int, value: any) -> None:
self.items[key - 1] = value
def __delitem__(self, key: int) -> None:
del self.items[key - 1]
我也曾经面临同样的问题,想实现从1开始的索引方法。我想要实现插入排序算法,该算法如下所示:
由于我们已经知道Python列表从0开始,所以我做了以下更改:
A = ['dummy',5,2,6,4,1,3]
for j in range(2,len(A)):
key = A[j]
i=j-1
while i>0 and A[i]>key:
A[i+1] = A[i]
i = i-1
A[i+1] = key
A.pop(0)
print A
我只是在索引0中添加了一个“虚拟”的值,按照算法进行了所有操作,然后又将“虚拟”值删除。这只是一种欺骗方法。
我建议像这样子类化collections.abc.MutableSequence,因为一旦协议(在本例中为:__getitem__
、__setitem__
、__delitem__
、__len__
、insert
)被实现,所有列表方法都应该适用于自定义序列类型。
我想出的解决方案使用了collections.abc.MutableSequence和一个列表包装器(_lst)以及一个帮助类组件,它对除了它是可下标访问的之外的任何东西都不知道,即它实现了__getitem__
来处理索引修改。
import collections.abc
class _IndexComponent:
def __getitem__(self, index):
if index == 0: raise IndexError("Index 0 is a lie.")
if index > 0: return index -1
else: return index
class OneList(collections.abc.MutableSequence):
def __init__(self, init: list = None) -> None:
self._index_comp = _IndexComponent()
self._lst = []
if not init is None: # and isinstance(init, list)?
self._lst.extend(init)
def __getitem__(self, index: int) -> any:
return self._lst[self._index_comp[index]]
def __setitem__(self, index: int, val: any) -> None:
self._lst[self._index_comp] = val
def __delitem__(self, index: int) -> None:
del self._lst[self._index_comp[index]]
def __len__(self) -> int:
return len(self._lst)
def insert(self, index: int, val: any) -> None:
self._lst.insert(self._index_comp[index], val)
def __repr__(self) -> str:
return f"{self._lst}"
现在举例说明pop函数,尽管它没有明确实现:
ol = OneList([1,2,3,4])
print(ol.pop(1))
ol.pop(0) # IndexError
不过,这种感觉有点混乱,如果有人分享更好的解决方案,我会很感激。
l = [] l.extend([]) print(l)
In [1]: index_0 = ['foo', 'bar', 'quux']
In [2]: index_1 = [None] + index_0
In [3]: index_1[1]
Out[3]: 'foo'
In [4]: index_1[1:]
Out[4]: ['foo', 'bar', 'quux']