• Fluent Python: Slice


      Pyhton中序列类型支持切片功能,比如list:

    >>> numbers = [1, 2, 3, 4, 5]
    >>> numbers[1:3]
    [2, 3]

    tuple也是序列类型,同样支持切片。

    (一)我们是否可以使自定义类型支持切片呢?

    在Python中创建功能完善的序列类型不需要使用继承,只要实现符合序列协议的方法就可以,Python的序列协议需要__len__, __getitem__两个方法,比如如下的Vector类:

    from array import array
    
    
    class Vector:
        type_code = 'd'
    
        def __init__(self, compoments):
            self.__components = array(self.type_code, compoments)
    
        def __len__(self):
            return len(self.__components)
    
        def __getitem__(self, index):
            return self.__components[index]

    我们在控制台查看下切片功能:

    >>> v1 = Vector([1, 2, 3])
    >>> v1[1]
    2.0
    >>> v1[1:2]
    array('d', [2.0])

    在这里我们将序列协议委托给self.__compoments(array的实例),只需要实现__len__和__getitem__,就可以支持切片功能了。

    (二)那么Python的切片工作原理又是怎样的呢?

    我们通过一个简单的例子来查看slice的行为:

    class MySequence:
        def __getitem__(self, index):
            return index
    >>> s1 = MySequence()
    >>> s1[1]
    1
    >>> s1[1:4]
    slice(1, 4, None)
    >>> s1[1:4:2]
    slice(1, 4, 2)
    >>> s1[1:4:2, 7:9]
    (slice(1, 4, 2), slice(7, 9, None))

    我们看到:

    (1)输入整数时,__getitem__返回的是整数

    (2)输入1:4表示法时,返回的slice(1, 4, None)

    (3)输入1:4:2表示法,返回slice(1, 4, 2)

    (4)[]中有逗号,__getitem__收到的是元组

    现在我们来仔细看看slice本身:

    >>> slice
    <class 'slice'>
    >>> dir(slice)
    ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge
    __', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
    '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr_
    _', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'indices', 'star
    t', 'step', 'stop']

    我们看到了熟悉的start, stop, step属性,还有一个不熟悉的indices,用help查看下(Pyhon的控制台是很有价值的工具,我们常常使用dir,help命令获得帮助):

    Help on method_descriptor:
    
    indices(...)
        S.indices(len) -> (start, stop, stride)
    
        Assuming a sequence of length len, calculate the start and stop
        indices, and the stride length of the extended slice described by
        S. Out of bounds indices are clipped in a manner consistent with the
        handling of normal slices.

    这里的indices能用于优雅的处理缺失索引和负数索引,以及长度超过目标序列长度的切片,这个方法会整顿输入的slice元组,把start, stop, step都变成非负数,且落在指定长度序列的边界内:

    比如:

    >>> slice(None, 10, 2).indices(5)  # 目标序列长度为5,自动将stop整顿为5
    (0, 5, 2)
    >>> slice(-1, None, None).indices(5)  # 将start = -1, stop = None , step = None 整顿为(4, 5, 1)
    (4, 5, 1)

    如果没有底层序列作为代理,使用这个方法能节省大量时间

    上面了解了slice的工作原理,我们使用它重新实现Vector类的__getitem__方法:

    from array import array
    from numbers import Integral
    
    
    class Vector:
        type_code = 'd'
    
        def __init__(self, compoments):
            self.__components = array(self.type_code, compoments)
    
        def __len__(self):
            return len(self.__components)
    
        def __getitem__(self, index):
            cls = type(self)
            if isinstance(slice, index):
                return cls(self.__components[index])  #  使用cls的构造方法返回Vector的实例
            elif isinstance(Integral, index):
                return self.__components[index]
            else:
                raise TypeError("{} indices must be integers or slices".format(cls))
  • 相关阅读:
    beego学习笔记(4):开发文档阅读(1)
    go的匿名组合
    beego学习笔记(3)
    beego学习笔记(2)
    python发送post请求发送json数据时,报415的原因和处理方法。
    Kali Linux的安装
    linux下配置mysql的远程访问
    selenium学习笔记
    Fiddler使用方法简介
    使用webdriver打开本地浏览器--python版
  • 原文地址:https://www.cnblogs.com/z-joshua/p/7620041.html
Copyright © 2020-2023  润新知