手把手教你学python第十六讲(魔法方法收尾和练习)

图片出不来请到https://www.bilibili.com/read/cv328084

经过重重艰难,终于来到了魔法方法。我先预告一下,后面就是爬虫了。加油。推荐一个总结的比较好的内置函数的中文网站http://www.cnblogs.com/sesshoumaru/category/894935.html。现在网上的python教程真的是铺天盖地,那么我建议你只要下定决心学python了,当然现在最好学3,因为2.7很快就不更新了,还有就是选定一个教程就从头到尾坚持跟。

迭代器

参考了https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143178254193589df9c612d2449618ea460e7a672a366000和

http://python.jobbole.com/81916/以及http://blog.chinaunix.net/uid-15174104-id-4172583.html有很多改动和整合。

我们先来看两个概念,可迭代对象,我们称之为iterable。还有一个叫做迭代器,iterator。

我们可以通过下面的代码来判断一个对象是不是iterable

手把手教你学python第十六讲(魔法方法收尾和练习)

看来我们所有的容器类型都是iterable的。那么它们是不是iterator呢?

手把手教你学python第十六讲(魔法方法收尾和练习)

它们都不是Iterator唉,但是iter()以后,就变成了Iterator了,是不是很神奇。下面我们要探究到底什么区分开了iterable和iterator。什么是iterable的呢?就是具有__iter()__魔法方法的对象。iterator是具有__iter__和__next__的对象,那么首先就不可避免的说到了iter()和next()两个函数。关于这里魔法方法的自动调用应该不用重复了吧

iter(a)就是自动调用a.__iter__,next()一样。

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

next()就是一个一个数据发送出来,直到后面没有数据了,就会报StopItration的异常。当然你还可以设置返回的内容

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

我这里就只展示一下list类型,其它的容器类型都是一样的。还有些对象没有__iter__方法,不是iterable

手把手教你学python第十六讲(魔法方法收尾和练习)

其实python上面的判断是类似于一种傻瓜判断,有__next__方法和__iter__的类的就是按照上面的判断方法就被判断成是it,我们完全可以自己胡乱定义一个类。

手把手教你学python第十六讲(魔法方法收尾和练习)

下面这张图是说明__iter__的必要性。

手把手教你学python第十六讲(魔法方法收尾和练习)

当然这是我们自己没事干在这里乱写魔法方法而 没有任何功能实现。python自己是没有这么闲,它们内部写好的这些列表,元组等类型的魔法方法内部都是有语句,可以实现一定的功能的,python开发人员都封装好了,我么还可以猜测iter()的实质就是加一个__next__魔法方法而已。下面我们来深层次探究一下iterable和iterator之间的关系,其实从上面的定义就知道,没错,Iterator是Iterable的子类,并且它实现了__next__魔法方法。iterable需要__iter__来产生iterator,而iterator需要通过__new__来实现迭代。

手把手教你学python第十六讲(魔法方法收尾和练习)

你是不是认为,上面的定义其实说起来就一句话iterable的其实就是你比较懒没有写__next__方法而已嘛,你要是勤劳一点,都写上__next__方法,那还哪有iterable呢?唉,不要急,存在即合理。看完下面这段代码,你会明白为什么都要存在

手把手教你学python第十六讲(魔法方法收尾和练习)

看出区别了吗?你说我看到第二次for i in b什么都没有打印,但是也没有什么用啊,不知道这能得出什么结论啊,这是因为我们不了解for。下面我们就来说for其实做了一件什么事

手把手教你学python第十六讲(魔法方法收尾和练习)

注意看结果a,b,c的位置,__iter__里面返回self是因为它自己就有__next__方法,已经是迭代器了

手把手教你学python第十六讲(魔法方法收尾和练习)

我前面没有加限制条件,你可以自己加的,可以在for循环里加,很简单我就不演示了

手把手教你学python第十六讲(魔法方法收尾和练习)

for相当于自动会调用iter()先生成一个iterator,然后通过next每次打印出来一个数据。这里回到上面我们看到a=[1,2,3]我们两次对a进行迭代,都没有问题,但是对b=iter(a)进行两次for循环迭代操作第二次什么都没有打印,为什么?不知道你们有没有联想到以前的文件指针。这里的迭代器iterator也有一个类似的指针,当迭代一次以后就指向了末尾,再进行迭代就什么都不发生,但是对于iterable对象没有这个问题,它每次相当于有一个自动回到开头的功能,使得iterable是可以反复利用的,而iterator则可以比喻成一个一次性用品。当然由于iterator是通过iter(iterable)来得到的,你可以重复iter得到多个iterator,这样就可以重复利用了。

手把手教你学python第十六讲(魔法方法收尾和练习)

那么有没有一种不需要iter内置函数的转换就直接是iterator呢?是有的,这就是我们下面要讲的很重要的一个概念

生成器

参考了http://bbs.fishc.com/thread-56023-1-1.html

手把手教你学python第十六讲(魔法方法收尾和练习)

回想前面我们所说的函数有关的一些说法,函数里的变量都是局部的,除了你用global或者nonlocal,又或者你用的是容器类型。局部变量有什么特征呢?就是调用结束,如果没有指针指向它,这个函数就会被初始化,这很好理解是吧。但是我为什么说没有指针指向它呢?是因为还有一个叫做闭包的一个东西。我们来看一段代码,我不会细讲,因为这都是以前的知识

手把手教你学python第十六讲(魔法方法收尾和练习)

我们曾经还说过,函数都是有返回值的,如果没有return语句会自动返回None,并且python不能有多个返回值,但是可以返回一个容器类型哈,相当于变相返回了容器里的多个值,还有一点函数内只要执行到return语句(或者有异常)就会返回,不会执行会面的语句。这些以前我都用大量代码验证过了。下面我们就来看看用yield的生成器函数有什么不同。这种生成器在其它语言里也叫做协同程序。

手把手教你学python第十六讲(魔法方法收尾和练习)

对比下面的一般函数和带yield的函数

手把手教你学python第十六讲(魔法方法收尾和练习)

这里呢我更加倾向于把yield理解为一种中断式返回,什么意思呢?就是在函数里一旦遇到了yield,它会和遇到return一样返回,不同的是中断返回是保护了断点的,什么叫做保护了断点呢?就是说我就相当于看视频的暂停,我可能要去上厕所,我先暂停一下,回来我继续去厕所的时候看到的位置看,而不是从头看。然后呢,我们来看一看a1是不是生成器,注意看a1是有__next__和__iter__方法的。

手把手教你学python第十六讲(魔法方法收尾和练习)

所以说用next来调用也可以理解。当然你可以隐藏next,也很简单,就是用for

手把手教你学python第十六讲(魔法方法收尾和练习)

注意下面这种情形,结合前面说的yield是一种特殊的return,还有前面复习过的return应该可以理解,因为return是没有保护断点的,直接return就直接相当于关掉了视频了,就结束了,或者按照官方一点的话话说控制权已经完全交出去了。这种用yield的函数生成器上面说过也是iterator,所以也是一次性的,也可以通过类似于新建类实例的方法一样重复使用。

手把手教你学python第十六讲(魔法方法收尾和练习)

一般我们是配合while语句来使用这种函数处理无限序列。不是所有的类都能处理无限序列的,iterator是一个,上面的闭包也可以。

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

你可以自己在for里限制条件,产生有限的项

手把手教你学python第十六讲(魔法方法收尾和练习)

当然你还可以这么改

手把手教你学python第十六讲(魔法方法收尾和练习)

不知道还有没有人记得前面讲过一个东西,叫做列表推导式,我们来看一看,看下面,你会发现集合,字典都是有推导式的,但是字符串和元组没有

手把手教你学python第十六讲(魔法方法收尾和练习)

实际上我们小括号括起来的看到了吗?是一个生成器generator。python设计的生成器是可以直接这么写的。那么同样它也是有一次性的问题。

手把手教你学python第十六讲(魔法方法收尾和练习)

下面我们就要做一些练习,练习是很重要的,绝对不能眼高手低,万事开头难,但是一旦你下定决心开始写代码,并且愿意花费时间去钻研代码,一定会在量变的积累下形成质变。重在坚持。

练习(其实同时也在复习前面的知识,还有综合运用前面的知识)

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)



手把手教你学python第十六讲(魔法方法收尾和练习)

其实也是完全没有问题的,为什么呢?因为python的自动回收机制,当没有指针指向这个文件的时候文件会自动被关闭。但是为了保险起见,我们还是要随后关掉文件,如果你身边有程序员就会发现他们有个习惯,习惯性按Ctrl+S,不信你去观察一下,还有一种方法是什么呢?回忆一下,没错,就是with,如果你不熟悉with请回去复习一下了。

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

先来学习一下ord(),就是返回一个字符的ASCII码

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

3

手把手教你学python第十六讲(魔法方法收尾和练习)

注意是所有子字符串,但是这道题并不难

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

4

手把手教你学python第十六讲(魔法方法收尾和练习)

我们这里就写一个循环进位的

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

5

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

如果我们只要求在Nstr类里计算,那么我们会有更简单的处理办法

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

6

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

7

手把手教你学python第十六讲(魔法方法收尾和练习)

继承上一题的思想

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

8

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

9

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

这道题很简单,可能你会疑惑__setattr__我们并没有写啊,为什么可以赋值?其实很简单Demo的基类Object是有__setattr__的。

手把手教你学python第十六讲(魔法方法收尾和练习)

10.编写一个Counter类,可以返回实时对象有几个绑定属性

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

11

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

12

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

13

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

14

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

15

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

16

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

其它的功能请自己去试

17

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

18

手把手教你学python第十六讲(魔法方法收尾和练习)

注意看要求是不一样的,还有处理的是有顺序的序列,这样很好理解,不是序列根本没有索引。

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

19

手把手教你学python第十六讲(魔法方法收尾和练习)

提示一点,不要想用一个列表去存素数,这样你的内存会被挤爆。根据素数定理不精确的估计这个数有2e6/(ln(2e6))=137849,也很大对吧。这个我们其实也很容易迭代实现

手把手教你学python第十六讲(魔法方法收尾和练习)


手把手教你学python第十六讲(魔法方法收尾和练习)

一共有148933个素数,比估计的还大,这很正常,素数定理只是一个概率估计。那么现在我要求必须用生成器实现。就是这样子,只是为了做练习而已。

手把手教你学python第十六讲(魔法方法收尾和练习)

代码链接:https://pan.baidu.com/s/1LqBGwIs1wgabveP6rHLhew 密码:enk7