字符串是在c 中实现的,所以如果您对c 和python-c-api 不太了解,答案就不是那么直截了当,但无论如何我都会尽力而为:
如果您直接调用__getslice__,您将使用string_slice:
static PyObject *
string_slice(PyStringObject *a, Py_ssize_t i, Py_ssize_t j)
/* j -- may be negative! */
{
if (i < 0)
i = 0;
if (j < 0)
j = 0; /* Avoid signed/unsigned bug in next line */
if (j > Py_SIZE(a))
j = Py_SIZE(a);
if (i == 0 && j == Py_SIZE(a) && PyString_CheckExact(a)) {
/* It's the same as a */
Py_INCREF(a);
return (PyObject *)a;
}
if (j < i)
j = i;
return PyString_FromStringAndSize(a->ob_sval + i, j-i);
}
这里i 是开始索引,j 是停止索引。如果 stop 小于零,它将被设置为 0 (if (j < 0) j = 0;),然后因为它小于 start,它将被设置为 start (if (j < i) j = i;)。所以你最终会得到 start=10 和 stop=10,这只是一个空字符串。
但如果你使用[],你会调用string_subscript(我将只包括该方法的相关部分):
static PyObject*
string_subscript(PyStringObject* self, PyObject* item)
{
/* ... */
if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength, cur, i;
/* ... */
if (_PySlice_Unpack(item, &start, &stop, &step) < 0) {
return NULL;
}
slicelength = _PySlice_AdjustIndices(PyString_GET_SIZE(self), &start,
&stop, step);
/* ... */
if (step == 1) {
return PyString_FromStringAndSize(
PyString_AS_STRING(self) + start,
slicelength);
}
/* ... */
}
/* ... */
}
这正确使用_PySlice_AdjustIndices 调整索引(类似于PySlice_AdjustIndices)。该函数会将 -1 的停止转换为 len(string) - 1 的停止:
Py_ssize_t PySlice_AdjustIndices(Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t step)
假设指定长度的序列,调整开始/结束切片索引。超出范围的索引以与正常切片处理一致的方式进行裁剪。
实际调用的函数可能与该函数不同。但我相信文档适用于两者。
但是你通常不应该直接调用__*__ 方法。所以我不知道这是否是 Python 中的错误或预期用途(据我所知,它可能是针对某些类型的切片的优化函数)。
但是 __getslice__ 很久以前就被弃用了 - 最好完全远离它。