为什么python切片中允许使用非整数内置类型?

时间:2016-09-11 04:59:22

标签: python python-3.x slice python-internals

我只是改善了必须支持切片的library的测试覆盖率,并且我注意到切片可以包含非整数类型:

>>> slice(1, "2", 3.0)
slice(1, '2', 3.0)
>>> sl = slice(1, "2", 3.0)
>>> [1,2,3][sl]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: slice indices must be integers or None or have an __index__ method

这可能只是我的静态输入背景,但我觉得很奇怪,没有__index__的内置类型可以在没有TypeError的情况下传入。为什么会这样?我是否正确假设允许任意类型以支持实现__index__的类型的鸭子类型?由于最常用案例的性能原因,是否缺乏类型检查?

PEP 357之前,示例中的切片是无效的吗?

2 个答案:

答案 0 :(得分:4)

第三方库可能希望为自己的对象实现切片,并且核心语言没有理由将这些第三方库限制为仅使用整数或类似整数的对象(即,类型提供{的对象{1}}方法)在他们的切片中。以下是在切片中使用非整数的包的两个值得注意的例子:在NumPy中,一些对象接受一个复杂的步骤,例如:

__index__

在Pandas中,您可以按标签切片>>> import numpy >>> numpy.mgrid[0:2:5j] array([ 0. , 0.5, 1. , 1.5, 2. ]) Series个对象。该标签可以是字符串,也可以是Dataframe对象(例如)。

datetime

因此,在构造包含非整数的切片时,核心语言引发异常是没有意义的;这将打破上述图书馆。相反,如果切片组件(start,stop,step)不是合适的类型,实际的切片操作应该引发异常。

答案 1 :(得分:2)

  

我是否正确地假设允许任意类型以支持实现__index__的类型的鸭子类型?

在初始化slice对象时,为什么要限制传递的类型没有实际的理由。正如PEP 357的理性中所述,numpy及其使用的数字类型无法从对象继承,因此对传递的类型进行严格issubclass检查会使它们无法用作索引值。因此,如果它定义了适当的方法(__index__),则使用鸭子打字,它可以使用。

另请注意,仅在应用切片时强制执行此操作(__index__的存在)(如您所见,TypeError期间__getitem__被提升,即{{3}调用list_subscript以尝试获取传递的值时的操作。

PySlice_GetIndicesEx对其接受的类型没有任何歧视,所有PyObject都可以适用,可以从其签名中看出来:

PyObject *
PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
{
   /* rest omitted */
  

PEP 357之前,示例中的切片是无效的吗?

我刚刚构建了一个2.4版本的Python并对其进行了测试(如果我没有弄错的话,PEP 357中出现2.5),再次检查参数是否为数字是在初始化期间但未在调用__getitem__时完成;唯一不同的是异常消息,它没有通知__index__ dunder(当时显然不存在):

Python 2.4 (#1, Sep 11 2016, 18:13:11) 
[GCC 5.4.0 20160609] on linux4
Type "help", "copyright", "credits" or "license" for more information.
>>> s = slice(0, Ellipsis)
>>> [1, 2, 3][s]
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: slice indices must be integers