fny5jt9 发表于 2024-8-17 21:57:32

Python进阶:全面诠释高级特性之切片


    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">优秀</span><span style="color: black;">文案</span>,<span style="color: black;">第1</span>时间送达!</p><img src="https://p3-sign.toutiaoimg.com/pgc-image/S23LW5iHDqbxWy~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1723896120&amp;x-signature=n5DZDZ7W7jtyGUwuAtqFV9kpHec%3D" style="width: 50%; margin-bottom: 20px;">
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">众所周知,<span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">经过</span>索引值(或<span style="color: black;">叫作</span>下标)来<span style="color: black;">查询</span>序列类型(如字符串、列表、元组…)中的单个元素,<span style="color: black;">那样</span>,<span style="color: black;">倘若</span>要获取一个索引区间的元素该怎么办呢?</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">切片(slice)<span style="color: black;">便是</span>一种截取索引片段的技术,借助切片技术,<span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">非常</span>灵活地处理序列类型的对象。<span style="color: black;">一般</span><span style="color: black;">来讲</span>,切片的<span style="color: black;">功效</span><span style="color: black;">便是</span>截取序列对象,然而,<span style="color: black;">针对</span>非序列对象,<span style="color: black;">咱们</span><span style="color: black;">是不是</span>有办法做到切片操作呢?在<span style="color: black;">运用</span>切片的过程中,有什么要点值得<span style="color: black;">注重</span>,又有什么底层原理值得关注呢?本文将<span style="color: black;">重点</span>跟<span style="color: black;">大众</span><span style="color: black;">一块</span>来探讨这些内容,<span style="color: black;">期盼</span>我能与你<span style="color: black;">一起</span>学习进步。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">1、切片的<span style="color: black;">基本</span>用法</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">列表是 Python 中极为<span style="color: black;">基本</span>且重要的一种数据结构,<span style="color: black;">亦</span>是最能发挥切片的用处的一种数据结构,<span style="color: black;">因此</span>在前两节,我将以列表为例介绍切片的<span style="color: black;">有些</span><span style="color: black;">平常</span>用法。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">首要</span>是切片的书写形式: ;其中,i 是切片的<span style="color: black;">初始</span>索引值,为列表首位时可省略;i+n 是切片的结束位置,为列表末位时可省略;m <span style="color: black;">能够</span>不<span style="color: black;">供给</span>,默认值是1,<strong style="color: blue;">不<span style="color: black;">准许</span>为0</strong>,当m为负数时,列表翻转。<span style="color: black;">重视</span>:这些值都<span style="color: black;">能够</span>大于列表长度,不会报越界。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">切片的基本含义是:<strong style="color: blue;">从序列的第i位索<span style="color: black;">导致</span>,向右取到后n位元素为止,按m间隔过滤</strong>。</p><span style="color: black;">li</span> <span style="color: black;">=</span> <span style="color: black;"></span><span style="color: black;">#</span> <span style="color: black;">以下写法都<span style="color: black;">能够</span><span style="color: black;">暗示</span><span style="color: black;">全部</span>列表,其中</span> <span style="color: black;">X</span> <span style="color: black;">&gt;=</span> <span style="color: black;">len(li)</span><span style="color: black;">li</span> <span style="color: black;">==</span> <span style="color: black;">li</span> <span style="color: black;">==</span> <span style="color: black;">li[:X]</span> <span style="color: black;">==</span> <span style="color: black;">li[:]</span><span style="color: black;">==</span> <span style="color: black;">li[::]</span> <span style="color: black;">==</span> <span style="color: black;">li[-X:X]</span> <span style="color: black;">==</span> <span style="color: black;">li[-X:]</span><span style="color: black;">li</span> <span style="color: black;">==</span> <span style="color: black;"></span> <span style="color: black;"># 从1起,取5-1位元素</span><span style="color: black;">li == # 从1起,取5-1位元素,按2间隔过滤</span><span style="color: black;">li[-1:] == # 取倒数<span style="color: black;">第1</span>个元素</span><span style="color: black;">li[-4:-2] == # 从倒数第四起,取-2-(-4)=2位元素</span><span style="color: black;">li[:-2] == li[-len(li):-2]</span><span style="color: black;">== # 从头<span style="color: black;">起始</span>,取-2-(-len(li))=7位元素</span><span style="color: black;"># 步长为负数时,列表先翻转,再截取</span><span style="color: black;">li[::-1] == # 翻转<span style="color: black;">全部</span>列表</span><span style="color: black;">li[::-2] == # 翻转<span style="color: black;">全部</span>列表,再按2间隔过滤</span><span style="color: black;">li[:-5:-1] == # 翻转<span style="color: black;">全部</span>列表,取-5-(-len(li))=4位元素</span><span style="color: black;">li[:-5:-3] == # 翻转<span style="color: black;">全部</span>列表,取-5-(-len(li))=4位元素,再按3间隔过滤</span><span style="color: black;"># 切片的步长不<span style="color: black;">能够</span>为0</span><span style="color: black;">li[::0] # 报错(ValueError: slice step cannot be zero)</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">以上</span>的某些例子<span style="color: black;">针对</span>初学者(<span style="color: black;">乃至</span><span style="color: black;">非常多</span>老手)<span style="color: black;">来讲</span>,可能还<span style="color: black;">欠好</span>理解,<span style="color: black;">然则</span>它们都离不开切片的基本语法,<span style="color: black;">因此</span>为方便起见,我将它们<span style="color: black;">亦</span>归入<span style="color: black;">基本</span>用法中。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">针对</span>这些样例,我个人总结出两条经验:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">(1)牢牢记住公式,当<span style="color: black;">显现</span>缺省值时,<span style="color: black;">经过</span>想象把公式补全;</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">(2)索引为负且步长为正时,按倒数计算索引位置;索引为负且步长为负时,先翻转列表,再按倒数计算索引位置。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">2、切片的高级用法</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">通常</span>而言,切片操作的返回结果是一个新的独立的序列。以列表为例,列表切片后得到的还是一个列表,占用新的内存<span style="color: black;">位置</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当取出切片的结果时,它是一个独立对象,因此,<span style="color: black;">能够</span>将其用于赋值操作,<span style="color: black;">亦</span><span style="color: black;">能够</span>用于其它传递值的场景。<span style="color: black;">然则</span>,<strong style="color: blue;">切片只是浅拷贝</strong>,它拷贝的是原列表中元素的引用,<span style="color: black;">因此</span>,当存在变长对象的元素时,新列表将受制于原列表。</p>li = [<span style="color: black;">1</span>, <span style="color: black;">2</span>, <span style="color: black;">3</span>, <span style="color: black;">4</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">ls = li[::]</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">li == ls # True</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">id(li) == id(ls) # False</p>li.<span style="color: black;">append</span>(li[<span style="color: black;">2</span>:<span style="color: black;">4</span>]) # [<span style="color: black;">1</span>, <span style="color: black;">2</span>, <span style="color: black;">3</span>, <span style="color: black;">4</span>, [<span style="color: black;">3</span>, <span style="color: black;">4</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]]</p>ls.extend(ls[<span style="color: black;">2</span>:<span style="color: black;">4</span>]) # [<span style="color: black;">1</span>, <span style="color: black;">2</span>, <span style="color: black;">3</span>, <span style="color: black;">4</span>, <span style="color: black;">3</span>, <span style="color: black;">4</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p># 下例等价于判断li长度<span style="color: black;">是不是</span>大于<span style="color: black;">8</span><span style="color: black;">i</span>f(li[<span style="color: black;">8</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:]):</p><span style="color: black;">print</span>(<span style="color: black;">"not empty"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p><span style="color: black;">else</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p><span style="color: black;">print</span>(<span style="color: black;">"empty"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># 切片列表受制于原列表</p>lo = [<span style="color: black;">1</span>,[<span style="color: black;">1</span>,<span style="color: black;">1</span>],<span style="color: black;">2</span>,<span style="color: black;">3</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>lp = lo[:<span style="color: black;">2</span>] # [<span style="color: black;">1</span>, [<span style="color: black;">1</span>, <span style="color: black;">1</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]]</p>lo[<span style="color: black;">1</span>].<span style="color: black;">append</span>(<span style="color: black;">1</span>) # [<span style="color: black;">1</span>, [<span style="color: black;">1</span>, <span style="color: black;">1</span>, <span style="color: black;">1</span>], <span style="color: black;">2</span>, <span style="color: black;">3</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>lp # [<span style="color: black;">1</span>, [<span style="color: black;">1</span>, <span style="color: black;">1</span>, <span style="color: black;">1</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]]</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">因为</span>可见,将切片结果取出,它<span style="color: black;">能够</span><span style="color: black;">做为</span>独立对象<span style="color: black;">运用</span>,<span style="color: black;">然则</span><span style="color: black;">亦</span>要<span style="color: black;">重视</span>,<span style="color: black;">是不是</span>取出了变长对象的元素。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">切片既<span style="color: black;">能够</span><span style="color: black;">做为</span>独立对象被“取出”原序列,<span style="color: black;">亦</span><span style="color: black;">能够</span>留在原序列,<span style="color: black;">做为</span>一种占位符<span style="color: black;">运用</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">不久前,我介绍了几种拼接字符串的<span style="color: black;">办法</span>,其中三种格式化类的拼接<span style="color: black;">办法</span>(即 %、format()、template)<span style="color: black;">便是</span><span style="color: black;">运用</span>了占位符的思想。<span style="color: black;">针对</span>列表<span style="color: black;">来讲</span>,<span style="color: black;">运用</span>切片<span style="color: black;">做为</span>占位符,<span style="color: black;">一样</span>能够实现拼接列表的效果。<span style="color: black;">尤其</span><span style="color: black;">必须</span><span style="color: black;">重视</span>的是,给切片赋值的<span style="color: black;">必要</span>是可迭代对象。</p><span style="color: black;">li</span> <span style="color: black;">=</span> <span style="color: black;"></span><span style="color: black;">#</span> <span style="color: black;">在头部拼接</span><span style="color: black;">li[:0]</span> <span style="color: black;">=</span> <span style="color: black;"></span> <span style="color: black;"># </span><span style="color: black;"># 在末尾拼接</span><span style="color: black;">li = # </span><span style="color: black;"># 在中部拼接</span><span style="color: black;">li = # </span><span style="color: black;"># 给切片赋值的<span style="color: black;">必要</span>是可迭代对象</span><span style="color: black;">li[-1:-1] = 6 # (报错,TypeError: can only assign an iterable)</span><span style="color: black;">li[:0] = (9,) # </span><span style="color: black;">li[:0] = range(3) # </span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">以上</span>例子中,若将切片<span style="color: black;">做为</span>独立对象取出,那你会<span style="color: black;">发掘</span>它们都是空列表,即 li[:0]==li==li==,我将这种占位符<span style="color: black;">叫作</span>为“<strong style="color: blue;">纯占位符</strong>”,对纯占位符赋值,并不会破坏原有的元素,只会在特定的索引位置中拼接进新的元素。删除纯占位符时,<span style="color: black;">亦</span>不会影响列表中的元素。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">与“纯占位符”相对应,“<strong style="color: blue;">非纯占位符</strong>”的切片是非空列表,对它进行操作(赋值与删除),将会影响原始列表。<span style="color: black;">倘若</span>说纯占位符<span style="color: black;">能够</span>实现列表的拼接,<span style="color: black;">那样</span>,非纯占位符<span style="color: black;">能够</span>实现列表的替换。</p><span style="color: black;">li</span> <span style="color: black;">=</span> <span style="color: black;"></span><span style="color: black;">#</span> <span style="color: black;"><span style="color: black;">区别</span>位置的替换</span><span style="color: black;">li[:3]</span> <span style="color: black;">=</span> <span style="color: black;"></span> <span style="color: black;"># </span><span style="color: black;">li = # </span><span style="color: black;">li = # </span><span style="color: black;"># 非等长替换</span><span style="color: black;">li = # </span><span style="color: black;">li = # </span><span style="color: black;"># 删除元素</span><span style="color: black;">del li # </span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">切片占位符<span style="color: black;">能够</span>带步长,从而实现连续跨越性的替换或删除效果。<span style="color: black;">必须</span><span style="color: black;">重视</span>的是,这种用法只支持等长替换。</p>li = [<span style="color: black;">1</span>, <span style="color: black;">2</span>, <span style="color: black;">3</span>, <span style="color: black;">4</span>, <span style="color: black;">5</span>, <span style="color: black;">6</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>li[::<span style="color: black;">2</span>] = [<span style="color: black;">a</span>,<span style="color: black;">b</span>,<span style="color: black;">c</span>] # [<span style="color: black;">a</span>, <span style="color: black;">2</span>, <span style="color: black;">b</span>, <span style="color: black;">4</span>, <span style="color: black;">c</span>, <span style="color: black;">6</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>li[::<span style="color: black;">2</span>] = [<span style="color: black;">0</span>]*<span style="color: black;">3</span> # [<span style="color: black;">0</span>, <span style="color: black;">2</span>, <span style="color: black;">0</span>, <span style="color: black;">4</span>, <span style="color: black;">0</span>, <span style="color: black;">6</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>li[::<span style="color: black;">2</span>] = [<span style="color: black;">w</span>] # 报错,attempt to <span style="color: black;">assign</span> sequence of size <span style="color: black;">1</span> to extended slice of size <span style="color: black;">3</span>del li[::<span style="color: black;">2</span>] # [<span style="color: black;">2</span>, <span style="color: black;">4</span>, <span style="color: black;">6</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">3、自定义对象实现切片功能</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">切片是 Python 中最迷人最强大最 Amazing 的语言特性(几乎<span style="color: black;">无</span>之一),以上两小节虽然介绍了切片的<span style="color: black;">基本</span>用法与高级用法,但这些还不足以充分地展露切片的魅力,<span style="color: black;">因此</span>,在接下来的两章节中,<span style="color: black;">咱们</span>将聚焦于它的更高级用法。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">前两节内容都是基于原生的序列类型(如字符串、列表、元组……),<span style="color: black;">那样</span>,<span style="color: black;">咱们</span><span style="color: black;">是不是</span><span style="color: black;">能够</span>定义自己的序列类型并让它支持切片语法呢?更进一步,<span style="color: black;">咱们</span><span style="color: black;">是不是</span><span style="color: black;">能够</span>自定义其它对象(如字典)并让它支持切片呢?</p>
    <h2 style="color: black; text-align: left; margin-bottom: 10px;">3.1、魔术<span style="color: black;">办法</span>:`<strong style="color: blue;">getitem</strong>`</h2>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">想要使自定义对象支持切片语法并不难,只<span style="color: black;">必须</span>在定义类的时候给它实现魔术<span style="color: black;">办法</span> __getitem__<span style="color: black;">就可</span>。<span style="color: black;">因此</span>,<span style="color: black;">这儿</span>就先介绍一下这个<span style="color: black;">办法</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">语法:<strong style="color: blue;">object.__getitem__(self, key)</strong></p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">官方文档释义:Called to implement evaluation of self. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the<strong style="color: blue;">__getitem__</strong>method. If key is of an inappropriate type, TypeError may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. For mapping types, if key is missing (not in the container), KeyError should be raised.</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">概括翻译一下:__getitem__<span style="color: black;">办法</span>用于返回参数 key 所对应的值,这个 key <span style="color: black;">能够</span>是整型数值和切片对象,并且支持负数索引;<span style="color: black;">倘若</span> key 不是以上两种类型,就会抛 TypeError;<span style="color: black;">倘若</span>索引越界,会抛 IndexError ;<span style="color: black;">倘若</span>定义的是映射类型,当 key 参数不是其对象的键值时,则会抛 KeyError 。</p>
    <h2 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;">3.2、自定义序列实现切片功能</strong></h2>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">接下来,<span style="color: black;">咱们</span>定义一个简单的 MyList ,并给它加上切片功能。(PS:仅作演示,不<span style="color: black;">保准</span>其它功能的完备性)。</p><span style="color: black;">import</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> numbers</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">class MyList:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">def __init__(self, anylist):</p>self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> = anylist</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">def __len__(self):</p><span style="color: black;">return</span> len(self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">def __getitem__(self, index):</p>print(<span style="color: black;">"key is : "</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> + str(index))</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">cls = type(self)</p><span style="color: black;">if</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> isinstance(index, slice):</p>print(<span style="color: black;">"data is : "</span> + str(self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">))</p><span style="color: black;">return</span> cls(self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">elif isinstance(index, numbers.Integral):</p><span style="color: black;">return</span> self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"></p><span style="color: black;">else</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p>msg = <span style="color: black;">"{cls.__name__} indices must be integers"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">raise TypeError(msg.format(cls=cls))</p>l = MyList([<span style="color: black;">"My"</span>, <span style="color: black;">"name"</span>, <span style="color: black;">"is"</span>, <span style="color: black;">"Python猫"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">### 输出结果:</p>key <span style="color: black;">is</span> : <span style="color: black;">3</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Python猫</p>key <span style="color: black;">is</span> : slice(None, <span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, None)</p><span style="color: black;">data</span> <span style="color: black;">is</span> : [<span style="color: black;">My</span>, <span style="color: black;">name</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">]</p>&lt;__main__.MyList <span style="color: black;">object</span> at <span style="color: black;">0x0000019CD83A7A90</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">&gt;</p>key <span style="color: black;">is</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> : hi</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Traceback (most recent call last):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">...</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TypeError: MyList indices must be integers or slices</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">从输出结果来看,自定义的 MyList 既支持按索引<span style="color: black;">查询</span>,<span style="color: black;">亦</span>支持切片操作,这正是<span style="color: black;">咱们</span>的目的。</p>
    <h2 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;">3.3、自定义字典实现切片功能</strong></h2>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">切片是序列类型的特性,<span style="color: black;">因此</span>在上例中,<span style="color: black;">咱们</span>不<span style="color: black;">必须</span>写切片的<span style="color: black;">详细</span>实现<span style="color: black;">规律</span>。<span style="color: black;">然则</span>,<span style="color: black;">针对</span>其它非序列类型的自定义对象,就得自己实现切片<span style="color: black;">规律</span>。以自定义字典为例(PS:仅作演示,不<span style="color: black;">保准</span>其它功能的完备性):</p><span style="color: black;"><span style="color: black;">class</span> <span style="color: black;">MyDict</span>:</span><span style="color: black;"><span style="color: black;">def __init__</span></span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">(self):</p>self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> = {}</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">def __len__(self):</p><span style="color: black;">return</span> len(self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">def append(self, item):</p>self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> = item</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">def __getitem__(self, key):</p><span style="color: black;">if</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> isinstance(key, int):</p><span style="color: black;">return</span> self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"></p><span style="color: black;">if</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> isinstance(key, slice):</p>slicedkeys = list(self.<span style="color: black;">data</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">.keys)</p><span style="color: black;">return</span> {k: self.<span style="color: black;">data</span> <span style="color: black;">for</span> k <span style="color: black;">in</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> slicedkeys}</p><span style="color: black;">else</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">raise TypeError</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">d = MyDict</p>d.append(<span style="color: black;">"My"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>d.append(<span style="color: black;">"name"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>d.append(<span style="color: black;">"is"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>d.append(<span style="color: black;">"Python猫"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>print(d[<span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>print(d[:<span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>print(d[-<span style="color: black;">4</span>:-<span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>print(d[<span style="color: black;">hi</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">])</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">### 输出结果:</p><span style="color: black;">is</span>{<span style="color: black;">0</span>: <span style="color: black;">My</span>, <span style="color: black;">1</span>: <span style="color: black;">name</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">}</p>{<span style="color: black;">0</span>: <span style="color: black;">My</span>, <span style="color: black;">1</span>: <span style="color: black;">name</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">}</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Traceback (most recent call last):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">...</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">TypeError</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">上例的关键点在于将字典的键值取出,并对键值的列表做切片处理,其妙处在于,<span style="color: black;">不消</span>担心索引越界和负数索引,将字典切片转换<span style="color: black;">成为了</span>字典键值的切片,<span style="color: black;">最后</span>实现目的。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">4、迭代器实现切片功能</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">好了,介绍完<span style="color: black;">通常</span>的自定义对象<span style="color: black;">怎样</span>实现切片功能,<span style="color: black;">这儿</span>将迎来另一类非同<span style="color: black;">通常</span>的对象。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">迭代器是 Python 中独特的一种高级对象,它本身不具备切片功能,然而若能将它用于切片,这便仿佛是锦上添花,能达到如虎添翼的效果。<span style="color: black;">因此</span>,本节将隆重地介绍迭代器<span style="color: black;">怎样</span>实现切片功能。</p>
    <h2 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;">4.1、迭代与迭代器</strong></h2>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">首要</span>,有几个基本概念要澄清:迭代、可迭代对象、迭代器。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">迭代是一种遍历容器类型对象(例如字符串、列表、字典等等)的方式,例如,<span style="color: black;">咱们</span>说迭代一个字符串“abc”,指的<span style="color: black;">便是</span>从左往右依次地、逐个地取出它的<span style="color: black;">所有</span>字符的过程。(PS:汉语中迭代一词有循环反复、层层递进的意思,但 Python 中此词要理解成<strong style="color: blue;">单向水平线性</strong>的,<span style="color: black;">倘若</span>你不<span style="color: black;">熟练</span>它,我<span style="color: black;">意见</span>直接将其理解为遍历。)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">那样</span>,怎么写出迭代操作的指令呢?最通用的书写语法<span style="color: black;">便是</span> for 循环。</p># <span style="color: black;">for</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">循环实现迭代过程</p><span style="color: black;">for</span> <span style="color: black;">char</span> <span style="color: black;">in</span> <span style="color: black;">"abc"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p><span style="color: black;">print</span>(<span style="color: black;">char</span>, <span style="color: black;">end</span>=<span style="color: black;">" "</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># 输出结果:a b c</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">for 循环<span style="color: black;">能够</span>实现迭代的过程,<span style="color: black;">然则</span>,并非所有对象都<span style="color: black;">能够</span>用于 for 循环,例如,上例中若将字符串“abc”换成任意整型数字,则会报错:int object is not iterable .</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这句报错中的单词“iterable”指的是“可迭代的”,即 int 类型不是可迭代的。而字符串(string)类型是可迭代的,<span style="color: black;">一样</span>地,列表、元组、字典等类型,都是可迭代的。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">那怎么判断一个对象<span style="color: black;">是不是</span>可迭代呢?<span style="color: black;">为何</span>它们是可迭代的呢?怎么让一个对象可迭代呢?</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">要使一个对象可迭代,就要实现可迭代协议,即<span style="color: black;">必须</span>实现__iter__魔术<span style="color: black;">办法</span>,换言之,只要实现了这个魔术<span style="color: black;">办法</span>的对象都是可迭代对象。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">那怎么判断一个对象<span style="color: black;">是不是</span>实现了这个<span style="color: black;">办法</span>呢?除了<span style="color: black;">以上</span>的 for 循环外,我还<span style="color: black;">晓得</span>四种<span style="color: black;">办法</span>:</p># <span style="color: black;">办法</span><span style="color: black;">1</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:dir查看__iter__</p>dir(<span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) # <span style="color: black;">无</span>,略</p>dir(<span style="color: black;">"abc"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) # 有,略</p># <span style="color: black;">办法</span><span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:isinstance判断</p><span style="color: black;">import</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> collections</p>isinstance(<span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, collections.Iterable) # False</p>isinstance(<span style="color: black;">"abc"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, collections.Iterable) # True</p># <span style="color: black;">办法</span><span style="color: black;">3</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:hasattr判断</p>hasattr(<span style="color: black;">2</span>,<span style="color: black;">"__iter__"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) # False</p>hasattr(<span style="color: black;">"abc"</span>,<span style="color: black;">"__iter__"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) # True</p># <span style="color: black;">办法</span><span style="color: black;">4</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:用iter查看<span style="color: black;">是不是</span>报错</p>iter(<span style="color: black;">2</span>) # 报错:<span style="color: black;">int</span> <span style="color: black;">object</span> <span style="color: black;">is</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> not iterable</p>iter(<span style="color: black;">"abc"</span>) # &lt;str_iterator at <span style="color: black;">0x1e2396d8f28</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">&gt;</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">### PS:判断<span style="color: black;">是不是</span>可迭代,还<span style="color: black;">能够</span>查看<span style="color: black;">是不是</span>实现__getitem__,为方便描述,本文从略。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这几种<span style="color: black;">办法</span>中最值得一提的是 iter <span style="color: black;">办法</span>,它是 Python 的内置<span style="color: black;">办法</span>,其<span style="color: black;">功效</span>是<strong style="color: blue;">将可迭代对象变成迭代器</strong>。这句话<span style="color: black;">能够</span>解析出两层意思:(1)可迭代对象跟迭代器是两种东西;(2)可迭代对象能变成迭代器。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">实质</span>上,迭代器必然是可迭代对象,但可迭代对象不<span style="color: black;">必定</span>是迭代器。两者有多大的区别呢?</p><img src="https://p3-sign.toutiaoimg.com/pgc-image/SGCAA0q19uYIIw~noop.image?_iz=58558&amp;from=article.pc_detail&amp;lk3s=953192f4&amp;x-expires=1723896120&amp;x-signature=EGUw%2B2rv93A8Nn0eWIJOUp0BDwk%3D" style="width: 50%; margin-bottom: 20px;">
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">如上图蓝圈所示,普通可迭代对象与迭代器的最关键区别可概括为:<strong style="color: blue;">一同两<span style="color: black;">区别</span></strong>,<span style="color: black;">所说</span>“一同”,即两者都是可迭代的(__iter__),<span style="color: black;">所说</span>“两<span style="color: black;">区别</span>”,<span style="color: black;">就可</span>迭代对象在转化为迭代器后,它会丢失<span style="color: black;">有些</span>属性(__getitem__),<span style="color: black;">同期</span><span style="color: black;">亦</span><span style="color: black;">增多</span><span style="color: black;">有些</span>属性(__next__)。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">首要</span><span style="color: black;">瞧瞧</span><span style="color: black;">增多</span>的属性 __next__, 它是迭代器之<span style="color: black;">因此</span>是迭代器的关键,事实上,<span style="color: black;">咱们</span>正是把<span style="color: black;">同期</span>实现了__iter__<span style="color: black;">办法</span> 和__next__<span style="color: black;">办法</span>的对象定义为迭代器的。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">有了多出来的这个属性,可迭代对象不<span style="color: black;">必须</span>借助<span style="color: black;">外边</span>的 for 循环语法,就能实现自我的迭代/遍历过程。我发明了两个概念来描述这两种遍历过程(PS:为了易理解,<span style="color: black;">这儿</span><span style="color: black;">叫作</span>遍历,<span style="color: black;">实质</span><span style="color: black;">亦</span>可<span style="color: black;">叫作</span>为迭代):它遍历指的是<span style="color: black;">经过</span><span style="color: black;">外边</span>语法而实现的遍历,自遍历指的是<span style="color: black;">经过</span><span style="color: black;">自己</span><span style="color: black;">办法</span>实现的遍历。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">借助这两个概念,<span style="color: black;">咱们</span>说,可迭代对象<span style="color: black;">便是</span>能被“它遍历”的对象,而迭代器是<span style="color: black;">这里</span><span style="color: black;">基本</span>上,还能做到“自遍历”的对象。</p>ob1 = <span style="color: black;">"abc"</span>ob2 = iter(<span style="color: black;">"abc"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>ob3 = iter(<span style="color: black;">"abc"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># ob1它遍历</p><span style="color: black;">for</span> i <span style="color: black;">in</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> ob1:</p><span style="color: black;">print</span>(i, <span style="color: black;">end</span> = <span style="color: black;">" "</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) # a b c</p>for i <span style="color: black;">in</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> ob1:</p><span style="color: black;">print</span>(i, <span style="color: black;">end</span> = <span style="color: black;">" "</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) # a b c</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># ob1自遍历</p>ob1.__next__ # 报错: <span style="color: black;">str</span> object has no attribute <span style="color: black;">__next__</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># ob2它遍历</p><span style="color: black;">for</span> i <span style="color: black;">in</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> ob2:</p><span style="color: black;">print</span>(i, <span style="color: black;">end</span> = <span style="color: black;">" "</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) # a b c</p>for i <span style="color: black;">in</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> ob2:</p><span style="color: black;">print</span>(i, <span style="color: black;">end</span> = <span style="color: black;">" "</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) # 无输出</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># ob2自遍历</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">ob2.__next__ # 报错:StopIteration</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># ob3自遍历</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">ob3.__next__ # a</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">ob3.__next__ # b</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">ob3.__next__ # c</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">ob3.__next__ # 报错:StopIteration</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">经过</span><span style="color: black;">以上</span>例子可看出,迭代器的<span style="color: black;">优良</span>在于支持自遍历,<span style="color: black;">同期</span>,它的特点是单向非循环的,一旦完成遍历,再次调用就会报错。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">对此,我想到一个比方:普通可迭代对象就像是子弹匣,它遍历<span style="color: black;">便是</span>取出子弹,在完成操作后又装回去,<span style="color: black;">因此</span><span style="color: black;">能够</span>反复遍历(即多次调用for循环,返回相同结果);而迭代器就像是装载了子弹匣且不可拆卸的枪,进行它遍历<span style="color: black;">或</span>自遍历都是发射子弹,这是消耗性的遍历,是<span style="color: black;">没法</span>复用的(即遍历会有尽头)。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">写了这么多,稍微小结一下:<strong style="color: blue;">迭代是一种遍历元素的方式,<span style="color: black;">根据</span>实现方式划分,有<span style="color: black;">外边</span>迭代与内部迭代两种,支持外部迭代(它遍历)的对象<span style="color: black;">便是</span>可迭代对象,而<span style="color: black;">同期</span>还支持内部迭代(自遍历)的对象<span style="color: black;">便是</span>迭代器;<span style="color: black;">根据</span>消费方式划分,可分为复用型迭代与一次性迭代,普通可迭代对象是复用型的,而迭代器是一次性的。</strong></p>
    <h2 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;">4.2、迭代器切片</strong></h2>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">前面<span style="color: black;">说到</span>了“一同两<span style="color: black;">区别</span>”,最后的<span style="color: black;">区别</span>是,普通可迭代对象在转化成迭代器的过程中会丢失<span style="color: black;">有些</span>属性,其中关键的属性是 __getitem__。在前一节中,我<span style="color: black;">已然</span>介绍了这个魔术<span style="color: black;">办法</span>,并用它实现了自定义对象的切片特性。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">那样</span>问题来了:为啥迭代器不继承这个属性呢?</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">首要</span>,迭代器<span style="color: black;">运用</span>的是消耗型的遍历,这<span style="color: black;">寓意</span>着它充满不确定性,即其长度与索引键值对是动态衰减的,<span style="color: black;">因此</span>很难 get 到它的 item ,<span style="color: black;">亦</span>就<span style="color: black;">再也不</span><span style="color: black;">必须</span> __getitem__属性了。其次,若强行给迭代器加上这个属性,这并不<span style="color: black;">恰当</span>,正<span style="color: black;">所说</span>强扭的瓜不甜……</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">由此,新的问题来了:既然会丢失这么重要的属性(还<span style="color: black;">包含</span>其它未标识的属性),<span style="color: black;">为何</span>还要<span style="color: black;">运用</span>迭代器呢?</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">这个问题的答案在于,迭代器<span style="color: black;">持有</span>不可替代的强大的有用的功能,使得 Python 要如此设计它。限于篇幅,此处<span style="color: black;">再也不</span>展开,后续我会专门填坑此<span style="color: black;">专题</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">还没完,死缠烂打的问题来了:能否令迭代器<span style="color: black;">持有</span>这个属性呢,即令迭代器继续支持切片呢?</p><span style="color: black;">hi</span> = <span style="color: black;">"欢迎关注公众号:Python猫"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">it = iter(hi)</p><span style="color: black;"># 普通切片</span><span style="color: black;">hi[-7:] # Python猫</span><span style="color: black;"># 反例:迭代器切片</span><span style="color: black;">it[-7:] # 报错:str_iterator object is not subscriptable</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">迭代器<span style="color: black;">由于</span>缺少__getitem__,<span style="color: black;">因此呢</span><span style="color: black;">不可</span><span style="color: black;">运用</span>普通的切片语法。想要实现切片,无非两种思路:一是自己造轮子,写实现的<span style="color: black;">规律</span>;二是找到封装好的轮子。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Python 的 itertools 模块<span style="color: black;">便是</span><span style="color: black;">咱们</span>要找的轮子,用它<span style="color: black;">供给</span>的<span style="color: black;">办法</span>可<span style="color: black;">容易</span>实现迭代器切片。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">import itertools</p># 例<span style="color: black;">1</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:简易迭代器</p>s = iter(<span style="color: black;">"123456789"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p><span style="color: black;">for</span> x <span style="color: black;">in</span> itertools.islice(s, <span style="color: black;">2</span>, <span style="color: black;">6</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">):</p>print(x, end = <span style="color: black;">" "</span>) # 输出:<span style="color: black;">3</span> <span style="color: black;">4</span> <span style="color: black;">5</span> <span style="color: black;">6</span><span style="color: black;">for</span> x <span style="color: black;">in</span> itertools.islice(s, <span style="color: black;">2</span>, <span style="color: black;">6</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">):</p>print(x, end = <span style="color: black;">" "</span>) # 输出:<span style="color: black;">9</span># 例<span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:斐波那契数列迭代器</p><span style="color: black;">class</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> Fib:</p>def __init__(<span style="color: black;">self</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">):</p><span style="color: black;">self</span>.a, <span style="color: black;">self</span>.b = <span style="color: black;">1</span>, <span style="color: black;">1</span>def __iter__(<span style="color: black;">self</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">):</p><span style="color: black;">while</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> True:</p>yield <span style="color: black;">self</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">.a</p>self.a, <span style="color: black;">self</span>.b = <span style="color: black;">self</span>.b, <span style="color: black;">self</span>.a + <span style="color: black;">self</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">.b</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">f = iter(Fib)</p><span style="color: black;">for</span> x <span style="color: black;">in</span> itertools.islice(f, <span style="color: black;">2</span>, <span style="color: black;">6</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">):</p>print(x, end = <span style="color: black;">" "</span>) # 输出:<span style="color: black;">2</span> <span style="color: black;">3</span> <span style="color: black;">5</span> <span style="color: black;">8</span><span style="color: black;">for</span> x <span style="color: black;">in</span> itertools.islice(f, <span style="color: black;">2</span>, <span style="color: black;">6</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">):</p>print(x, end = <span style="color: black;">" "</span>) # 输出:<span style="color: black;">34</span> <span style="color: black;">55</span> <span style="color: black;">89</span> <span style="color: black;">144</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">itertools 模块的 islice <span style="color: black;">办法</span>将迭代器与切片完美结合,<span style="color: black;">最终</span>回答了前面的问题。然而,迭代器切片跟普通切片相比,前者有<span style="color: black;">非常多</span>局限性。<span style="color: black;">首要</span>,这个<span style="color: black;">办法</span>不是“纯函数”(纯函数需遵守“相同输入得到相同输出”的原则);其次,它只支持正向切片,且不支持负数索引,这都<span style="color: black;">是由于</span>迭代器的损耗性所决定的。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">那样</span>,我不禁要问:itertools 模块的切片<span style="color: black;">办法</span>用了什么实现<span style="color: black;">规律</span>呢?下方是官网<span style="color: black;">供给</span>的源码:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">def islice(iterable, *args):</p># islice(<span style="color: black;">ABCDEFG</span>, <span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) --&gt; A B</p># islice(<span style="color: black;">ABCDEFG</span>, <span style="color: black;">2</span>, <span style="color: black;">4</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) --&gt; C D</p># islice(<span style="color: black;">ABCDEFG</span>, <span style="color: black;">2</span>, <span style="color: black;">None</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) --&gt; C D E F G</p># islice(<span style="color: black;">ABCDEFG</span>, <span style="color: black;">0</span>, <span style="color: black;">None</span>, <span style="color: black;">2</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) --&gt; A C E G</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">s = slice(*args)</p># 索引区间是[<span style="color: black;">0</span>,sys.maxsize],默认步长是<span style="color: black;">1</span>start, stop, step = s.start or <span style="color: black;">0</span>, s.stop or sys.maxsize, s.step or <span style="color: black;">1</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">it = iter(range(start, stop, step))</p><span style="color: black;">try</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">nexti = next(it)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">except StopIteration:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># Consume *iterable* up to the *start* position.</p><span style="color: black;">for</span> i, element <span style="color: black;">in</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">zip(range(start), iterable):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">pass</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">return</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">try:</p><span style="color: black;">for</span> i, element <span style="color: black;">in</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> enumerate(iterable):</p><span style="color: black;">if</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> i == nexti:</p><span style="color: black;">yield</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> element</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">nexti = next(it)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">except StopIteration:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># Consume to *stop*.</p><span style="color: black;">for</span> i, element <span style="color: black;">in</span> zip(range(i + <span style="color: black;">1</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">, stop), iterable):</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">pass</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">islice <span style="color: black;">办法</span>的索引方向是受限的,但它<span style="color: black;">亦</span><span style="color: black;">供给</span>了一种可能性:即<span style="color: black;">准许</span>你对一个无穷的(在系统支持范围内)迭代器进行切片的能力。这是迭代器切片最具想象力的用途场景。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">除此之外,迭代器切片还有一个很实在的应用场景:读取文件对象中给定行数范围的数据。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">咱们</span><span style="color: black;">晓得</span>,从文件中读取内容<span style="color: black;">重点</span>有两种<span style="color: black;">办法</span>:read 适合读取内容较少的<span style="color: black;">状况</span>,<span style="color: black;">或</span>是<span style="color: black;">必须</span>一次性处理<span style="color: black;">所有</span>内容的<span style="color: black;">状况</span>;而 readlines 适用性更广,<span style="color: black;">由于</span>它是迭代地读取内容,既减少内存压力,又方便逐行对数据处理。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">虽然 readlines 有迭代读取的<span style="color: black;">优良</span>,但它是从头到尾逐行读取,若文件有几千行,而<span style="color: black;">咱们</span>只想要读取<span style="color: black;">少许</span>特定行(例如第1000-1009行),那它还是效率太低了。<span style="color: black;">思虑</span>到<strong style="color: blue;">文件对象天然<span style="color: black;">便是</span>迭代器</strong>,<span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">运用</span>迭代器切片先行截取,<span style="color: black;">而后</span>再处理,如此效率将大大地<span style="color: black;">提高</span>。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"># test.txt 文件内容</p><span style="color: black;">猫</span><span style="color: black;">Python猫</span><span style="color: black;">python is a cat.</span><span style="color: black;">this is the end.</span>from itertools<span style="color: black;">import</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> islice</p>with <span style="color: black;">open</span>(<span style="color: black;">test.txt</span>,<span style="color: black;">r</span>,encoding=<span style="color: black;">utf-8</span>) <span style="color: black;">as</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> f:</p>print(hasattr(f, <span style="color: black;">"__next__"</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)) # 判断<span style="color: black;">是不是</span>迭代器</p>content = islice(f, <span style="color: black;">2</span>, <span style="color: black;">4</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p><span style="color: black;">for</span> line <span style="color: black;">in</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> content:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">print(line.strip)</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">### 输出结果:</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">True</p>python <span style="color: black;">is</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> a cat.</p><span style="color: black;">this</span> <span style="color: black;">is</span>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> the end.</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">本节内容较多,简单回顾一下:迭代器是一种特殊的可迭代对象,可用于它遍历与自遍历,但遍历过程是损耗型的,不具备循环复用性,<span style="color: black;">因此呢</span>,迭代器本身不支持切片操作;<span style="color: black;">经过</span>借助 itertools 模块,<span style="color: black;">咱们</span>能实现迭代器切片,将两者的<span style="color: black;">优良</span>相结合,其<span style="color: black;">重点</span>用途在于截取大型迭代器(如无限数列、超大文件等等)的片段,实现<span style="color: black;">精细</span>的处理,从而大大地<span style="color: black;">提高</span>性能与效率。</p>
    <h1 style="color: black; text-align: left; margin-bottom: 10px;">5、小结</h1>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">最后总结一下,切片是 Python 的一种高级特性,常用于截取序列类型的元素,但并不局限于此,本文<span style="color: black;">重点</span>介绍了它的<span style="color: black;">基本</span>用法、高级用法(如占位符用法)、自定义对象切片、以及迭代器切片等<span style="color: black;">运用</span>内容。除此之外,切片还有更广阔多样的<span style="color: black;">运用</span>场景,例如 Numpy 的多维切片、内存视图切片、异步迭代器切片等等,都值得<span style="color: black;">咱们</span>去探索一番。</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">源自</span>:Python猫</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">作者:豌豆花下猫</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">回复下方<strong style="color: blue;">「关键词」</strong>,获取<span style="color: black;">优秀</span>资源</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">回复关键词「 <strong style="color: blue;">pybook03</strong>」,立即获取主页君与小伙伴<span style="color: black;">一块</span>翻译的《Think Python 2e》电子版</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">回复关键词「<strong style="color: blue;">入门资料</strong>」,立即获取主页君整理的 10 本 Python 入门书的电子版</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">回复关键词「<strong style="color: blue;">m</strong>」,立即获取Python精选<span style="color: black;">优秀</span><span style="color: black;">文案</span>合集</p>
    <p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;">回复关键词「」,将数字替换成 0 及以上数字,有惊<span style="color: black;">爱好</span>礼哦~</strong></p>




nqkk58 发表于 2024-9-27 19:46:08

说得好啊!我在外链论坛打滚这么多年,所谓阅人无数,就算没有见过猪走路,也总明白猪肉是啥味道的。

nqkk58 发表于 2024-9-28 18:24:58

楼主发的这篇帖子,我觉得非常有道理。

7wu1wm0 发表于 2024-11-11 23:56:39

谢谢、感谢、感恩、辛苦了、有你真好等。
页: [1]
查看完整版本: Python进阶:全面诠释高级特性之切片