str.__getslice__ 负止损未按预期工作
str.__getslice__ is not working as expected with negative stop
我正在尝试 运行 遵循 python 2.7 中的代码:
foo = "python is awesome"
print foo[10:16]
print foo.__getslice__(10,16)
print foo[10:-1]
print foo.__getslice__(10,-1)
除最后一个打印的 "awsome"
外全部。但是 foo.__getslice__(10,-1)
返回了一个空字符串。为什么会这样?
字符串是在c so the answer isn't that straight-forward to understand if you don't know much about c and the 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)
Adjust start/end slice indices assuming a sequence of the specified length. Out of bounds indices are clipped in a manner consistent with the handling of normal slices.
实际调用的函数可能与那个函数不同。但我相信文档适用于两者。
但您通常不应直接调用 __*__
方法。所以我不知道这是 Python 中的错误还是预期用途(据我所知,它可能是针对某些类型切片的优化函数)。
然而 __getslice__
很久以前就被弃用了 - 最好完全远离它。
我正在尝试 运行 遵循 python 2.7 中的代码:
foo = "python is awesome"
print foo[10:16]
print foo.__getslice__(10,16)
print foo[10:-1]
print foo.__getslice__(10,-1)
除最后一个打印的 "awsome"
外全部。但是 foo.__getslice__(10,-1)
返回了一个空字符串。为什么会这样?
字符串是在c so the answer isn't that straight-forward to understand if you don't know much about c and the 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)
Adjust start/end slice indices assuming a sequence of the specified length. Out of bounds indices are clipped in a manner consistent with the handling of normal slices.
实际调用的函数可能与那个函数不同。但我相信文档适用于两者。
但您通常不应直接调用 __*__
方法。所以我不知道这是 Python 中的错误还是预期用途(据我所知,它可能是针对某些类型切片的优化函数)。
然而 __getslice__
很久以前就被弃用了 - 最好完全远离它。