图片出不来请到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
![](https://i-blog.csdnimg.cn/blog_migrate/869ef4d6883067029698b706886f27d7.png)
看来我们所有的容器类型都是iterable的。那么它们是不是iterator呢?
![](https://i-blog.csdnimg.cn/blog_migrate/0ff75bd37dc24f25cdc15c7ac3c4e8dd.png)
它们都不是Iterator唉,但是iter()以后,就变成了Iterator了,是不是很神奇。下面我们要探究到底什么区分开了iterable和iterator。什么是iterable的呢?就是具有__iter()__魔法方法的对象。iterator是具有__iter__和__next__的对象,那么首先就不可避免的说到了iter()和next()两个函数。关于这里魔法方法的自动调用应该不用重复了吧
iter(a)就是自动调用a.__iter__,next()一样。
![](https://i-blog.csdnimg.cn/blog_migrate/795a3a12eb64ddcb7a681c51a463d7af.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b6b7e196d1c7ed72fefba090f5805642.png)
next()就是一个一个数据发送出来,直到后面没有数据了,就会报StopItration的异常。当然你还可以设置返回的内容
![](https://i-blog.csdnimg.cn/blog_migrate/9e0ab0af513edf61e05399fc487f08c5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8d9a4353942cbf382bd1fb18b456d584.png)
我这里就只展示一下list类型,其它的容器类型都是一样的。还有些对象没有__iter__方法,不是iterable
![](https://i-blog.csdnimg.cn/blog_migrate/4097d73cd4ebd1cb7ba14443b0d0cdf0.png)
其实python上面的判断是类似于一种傻瓜判断,有__next__方法和__iter__的类的就是按照上面的判断方法就被判断成是it,我们完全可以自己胡乱定义一个类。
![](https://i-blog.csdnimg.cn/blog_migrate/ebfa2d0dbb54a86421cf536e3d23102a.png)
下面这张图是说明__iter__的必要性。
![](https://i-blog.csdnimg.cn/blog_migrate/d924690184ff1c22a36f01da5c339c54.png)
当然这是我们自己没事干在这里乱写魔法方法而 没有任何功能实现。python自己是没有这么闲,它们内部写好的这些列表,元组等类型的魔法方法内部都是有语句,可以实现一定的功能的,python开发人员都封装好了,我么还可以猜测iter()的实质就是加一个__next__魔法方法而已。下面我们来深层次探究一下iterable和iterator之间的关系,其实从上面的定义就知道,没错,Iterator是Iterable的子类,并且它实现了__next__魔法方法。iterable需要__iter__来产生iterator,而iterator需要通过__new__来实现迭代。
![](https://i-blog.csdnimg.cn/blog_migrate/7c19f0cc716cc5f051702a2137347d54.png)
你是不是认为,上面的定义其实说起来就一句话iterable的其实就是你比较懒没有写__next__方法而已嘛,你要是勤劳一点,都写上__next__方法,那还哪有iterable呢?唉,不要急,存在即合理。看完下面这段代码,你会明白为什么都要存在
![](https://i-blog.csdnimg.cn/blog_migrate/543ba063e44d2843cafcd13fbc7de310.png)
看出区别了吗?你说我看到第二次for i in b什么都没有打印,但是也没有什么用啊,不知道这能得出什么结论啊,这是因为我们不了解for。下面我们就来说for其实做了一件什么事
![](https://i-blog.csdnimg.cn/blog_migrate/2d13b96dfe0f9c076150b88011c9cd24.png)
注意看结果a,b,c的位置,__iter__里面返回self是因为它自己就有__next__方法,已经是迭代器了
![](https://i-blog.csdnimg.cn/blog_migrate/02be05a09dfb0f18e0aff5b17719996f.png)
我前面没有加限制条件,你可以自己加的,可以在for循环里加,很简单我就不演示了
![](https://i-blog.csdnimg.cn/blog_migrate/853d69a12600970287fb026f7ceeb58a.png)
for相当于自动会调用iter()先生成一个iterator,然后通过next每次打印出来一个数据。这里回到上面我们看到a=[1,2,3]我们两次对a进行迭代,都没有问题,但是对b=iter(a)进行两次for循环迭代操作第二次什么都没有打印,为什么?不知道你们有没有联想到以前的文件指针。这里的迭代器iterator也有一个类似的指针,当迭代一次以后就指向了末尾,再进行迭代就什么都不发生,但是对于iterable对象没有这个问题,它每次相当于有一个自动回到开头的功能,使得iterable是可以反复利用的,而iterator则可以比喻成一个一次性用品。当然由于iterator是通过iter(iterable)来得到的,你可以重复iter得到多个iterator,这样就可以重复利用了。
![](https://i-blog.csdnimg.cn/blog_migrate/286e0c525051f8059e6347dea5a0e1f6.png)
那么有没有一种不需要iter内置函数的转换就直接是iterator呢?是有的,这就是我们下面要讲的很重要的一个概念
生成器
参考了http://bbs.fishc.com/thread-56023-1-1.html
![](https://i-blog.csdnimg.cn/blog_migrate/62114ce3c1c0305a0cd7098245b573ec.png)
回想前面我们所说的函数有关的一些说法,函数里的变量都是局部的,除了你用global或者nonlocal,又或者你用的是容器类型。局部变量有什么特征呢?就是调用结束,如果没有指针指向它,这个函数就会被初始化,这很好理解是吧。但是我为什么说没有指针指向它呢?是因为还有一个叫做闭包的一个东西。我们来看一段代码,我不会细讲,因为这都是以前的知识
![](https://i-blog.csdnimg.cn/blog_migrate/bf71a207aa52612a3470dc89d5f5ec08.png)
我们曾经还说过,函数都是有返回值的,如果没有return语句会自动返回None,并且python不能有多个返回值,但是可以返回一个容器类型哈,相当于变相返回了容器里的多个值,还有一点函数内只要执行到return语句(或者有异常)就会返回,不会执行会面的语句。这些以前我都用大量代码验证过了。下面我们就来看看用yield的生成器函数有什么不同。这种生成器在其它语言里也叫做协同程序。
![](https://i-blog.csdnimg.cn/blog_migrate/be2e7cdf164e70ffbfd6c75cecf96b9a.png)
对比下面的一般函数和带yield的函数
![](https://i-blog.csdnimg.cn/blog_migrate/b59ee748496a3b61fede747d41425e0e.png)
这里呢我更加倾向于把yield理解为一种中断式返回,什么意思呢?就是在函数里一旦遇到了yield,它会和遇到return一样返回,不同的是中断返回是保护了断点的,什么叫做保护了断点呢?就是说我就相当于看视频的暂停,我可能要去上厕所,我先暂停一下,回来我继续去厕所的时候看到的位置看,而不是从头看。然后呢,我们来看一看a1是不是生成器,注意看a1是有__next__和__iter__方法的。
![](https://i-blog.csdnimg.cn/blog_migrate/de275bc2318f0a9c7cbee3d2bf38daa0.png)
所以说用next来调用也可以理解。当然你可以隐藏next,也很简单,就是用for
![](https://i-blog.csdnimg.cn/blog_migrate/0ad26eae7efe9875556255aec2d3619a.png)
注意下面这种情形,结合前面说的yield是一种特殊的return,还有前面复习过的return应该可以理解,因为return是没有保护断点的,直接return就直接相当于关掉了视频了,就结束了,或者按照官方一点的话话说控制权已经完全交出去了。这种用yield的函数生成器上面说过也是iterator,所以也是一次性的,也可以通过类似于新建类实例的方法一样重复使用。
![](https://i-blog.csdnimg.cn/blog_migrate/249ccf6031e685dc90faa18aa64a5f58.png)
一般我们是配合while语句来使用这种函数处理无限序列。不是所有的类都能处理无限序列的,iterator是一个,上面的闭包也可以。
![](https://i-blog.csdnimg.cn/blog_migrate/c9c3f07d6895ea0242b685141a6a9fc1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e5efd01b3c0fc7e7d008b637f000c9d7.png)
你可以自己在for里限制条件,产生有限的项
![](https://i-blog.csdnimg.cn/blog_migrate/169d8bdffe1031f2172e8398b1ab586b.png)
当然你还可以这么改
![](https://i-blog.csdnimg.cn/blog_migrate/063aa62c2d20d5e04bb1e5f4a7d49c59.png)
不知道还有没有人记得前面讲过一个东西,叫做列表推导式,我们来看一看,看下面,你会发现集合,字典都是有推导式的,但是字符串和元组没有
![](https://i-blog.csdnimg.cn/blog_migrate/f5f7f07b9a2c604d4f696bb646c50f03.png)
实际上我们小括号括起来的看到了吗?是一个生成器generator。python设计的生成器是可以直接这么写的。那么同样它也是有一次性的问题。
![](https://i-blog.csdnimg.cn/blog_migrate/6dc0de12611112d7ce8da72ea8543d90.png)
下面我们就要做一些练习,练习是很重要的,绝对不能眼高手低,万事开头难,但是一旦你下定决心开始写代码,并且愿意花费时间去钻研代码,一定会在量变的积累下形成质变。重在坚持。
练习(其实同时也在复习前面的知识,还有综合运用前面的知识)
![](https://i-blog.csdnimg.cn/blog_migrate/7f477cc8c26d92dda76395002be2ffb7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a1962589ee0edb5d96dfd9386f14d443.png)
![](https://i-blog.csdnimg.cn/blog_migrate/decc46699c2146675d7a5c29f3734f65.png)
其实也是完全没有问题的,为什么呢?因为python的自动回收机制,当没有指针指向这个文件的时候文件会自动被关闭。但是为了保险起见,我们还是要随后关掉文件,如果你身边有程序员就会发现他们有个习惯,习惯性按Ctrl+S,不信你去观察一下,还有一种方法是什么呢?回忆一下,没错,就是with,如果你不熟悉with请回去复习一下了。
![](https://i-blog.csdnimg.cn/blog_migrate/ebcd9657908b996ee55f85dbe14a19c2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6d1d38a63781d443a058f2f538b3a893.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e97ac08d38dfd5a43956d008cf72cc3c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c0ea6b2a3b6c1c93822ce5ea73b4cac6.png)
先来学习一下ord(),就是返回一个字符的ASCII码
![](https://i-blog.csdnimg.cn/blog_migrate/93078f5132a4afdbd2e8da786fde3222.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d6613bbcd0a2580dfa093dab1e72d85f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6c077099b04ef53f3f4e2207b39f91c6.png)
3
![](https://i-blog.csdnimg.cn/blog_migrate/ea65c6a1534be934a62b904de845985f.png)
注意是所有子字符串,但是这道题并不难
![](https://i-blog.csdnimg.cn/blog_migrate/b8d4310c85ad358f8450602552f6b3aa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/91f6c8451ad44f136d0d0ade41c562e6.png)
4
![](https://i-blog.csdnimg.cn/blog_migrate/49719cd55c16ac5b8199ba3826b012e7.png)
我们这里就写一个循环进位的
![](https://i-blog.csdnimg.cn/blog_migrate/56a9bf37060756face32213ba6ea6823.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ff93f89b2dcd8deb650c79ecddda0e8f.png)
5
![](https://i-blog.csdnimg.cn/blog_migrate/baeb4eb7476015b449a530a12f7f667c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7fd907574209d618acf0d0c5eb09d329.png)
![](https://i-blog.csdnimg.cn/blog_migrate/28c9b1c39eac542d37234340333d7776.png)
如果我们只要求在Nstr类里计算,那么我们会有更简单的处理办法
![](https://i-blog.csdnimg.cn/blog_migrate/d617628a17b85533110091422a19f053.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f829e4d6ae07eb49283bc5341676b0f3.png)
6
![](https://i-blog.csdnimg.cn/blog_migrate/039557e7c630c97e5e9e4d55206b15b9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3555de9d4a9a57914aa1e5e843c1d821.png)
![](https://i-blog.csdnimg.cn/blog_migrate/40ae7b89c458de9a44099a03143d6aa1.png)
7
![](https://i-blog.csdnimg.cn/blog_migrate/c268165cb3bd7d5ba0a825771748cc5c.png)
继承上一题的思想
![](https://i-blog.csdnimg.cn/blog_migrate/bea37085af6f301d7d12c060ad47298f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/18b28a2914bfaf89b0fda74978a5955f.png)
8
![](https://i-blog.csdnimg.cn/blog_migrate/0b614f3438b3f0d2ebabceea7b479202.png)
![](https://i-blog.csdnimg.cn/blog_migrate/badb67318cd7a73a70e6caa9803875ab.png)
![](https://i-blog.csdnimg.cn/blog_migrate/48e5db71b181eca69cf4227b978d3e42.png)
9
![](https://i-blog.csdnimg.cn/blog_migrate/3f83a7e2ee148a4afff964e12ed7fbb2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/913db07ed7ec1825b97cd4056571abf0.png)
这道题很简单,可能你会疑惑__setattr__我们并没有写啊,为什么可以赋值?其实很简单Demo的基类Object是有__setattr__的。
![](https://i-blog.csdnimg.cn/blog_migrate/829ce1383edc97bc05f1a8bd5eec4005.png)
10.编写一个Counter类,可以返回实时对象有几个绑定属性
![](https://i-blog.csdnimg.cn/blog_migrate/e39d140db58241c038cd8689672de10c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/36b4d2eeb8ee80a599e6cca9e8a2341d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/79ac72c6c8b51112a967c4302a1ae295.png)
11
![](https://i-blog.csdnimg.cn/blog_migrate/e2ac1df9ec5e41c7999275c94ad1b337.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dc8174a8b882b20473d661a2d6c421ea.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4820d13e5262a34c3c81fddb9ac9c138.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2093bec6caa839994d7ed65351be4ab8.png)
12
![](https://i-blog.csdnimg.cn/blog_migrate/5ed07a2a0b42ff29951649eeb21058fc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/740992c041ddd7e24c3ef86aa2de6e5b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/986297ac704d4ff5f12ed5653c15a987.png)
![](https://i-blog.csdnimg.cn/blog_migrate/77c06878d020c7965c01bd2e5f2dfa37.png)
![](https://i-blog.csdnimg.cn/blog_migrate/14c83923ef6cbef6f99ff98f22c6b167.png)
13
![](https://i-blog.csdnimg.cn/blog_migrate/9349dfcf002fde01e7d44d47d89b4ddb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8df8d412625facca05fd0548af473252.png)
![](https://i-blog.csdnimg.cn/blog_migrate/96aa98156f80e96bfa0ecc3e0c885a42.png)
14
![](https://i-blog.csdnimg.cn/blog_migrate/71830c4e3eba0203f78573e0e7e9b2ca.png)
![](https://i-blog.csdnimg.cn/blog_migrate/104b03ec29f6faadeac47e42fe0659a3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0a1985c6dd308f7e5c8b52031b32d9ad.png)
![](https://i-blog.csdnimg.cn/blog_migrate/32709398de5d595a86c41d93abad22e6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0287f0769e43015ceff428d13f247492.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b865a6fcdf9ec9994b66b4e900a92834.png)
15
![](https://i-blog.csdnimg.cn/blog_migrate/db27a5b38aa9847af5af9a929d0a7fe7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/226214fdaaff20d89d015178d56d596b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1c86c277c2f1cf2964426c2726a83569.png)
16
![](https://i-blog.csdnimg.cn/blog_migrate/80354690b250ffd6d94a08c80b50cb1b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f45d5d3f3c32d72e5ad548addd946611.png)
![](https://i-blog.csdnimg.cn/blog_migrate/816b1de7d0a77265c0d5537a08734c51.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b80e7ca2af006f3bf5e27c4e90038d45.png)
其它的功能请自己去试
17
![](https://i-blog.csdnimg.cn/blog_migrate/4b40adcbad5a235428e2a87a8064dc5d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6b094f4668a0f1dc24ca7d85a45a9961.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6e89e2fad338af4a0fc02eeb89f7e520.png)
18
![](https://i-blog.csdnimg.cn/blog_migrate/152b59141183219098d866a9ec6aabd6.png)
注意看要求是不一样的,还有处理的是有顺序的序列,这样很好理解,不是序列根本没有索引。
![](https://i-blog.csdnimg.cn/blog_migrate/5bf18eadd425d102d248624b68f8029b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c28dd2c944d48bb18e9a215550fcdb40.png)
19
![](https://i-blog.csdnimg.cn/blog_migrate/995d7773ac6ecd40b2c36062d981c3a8.png)
提示一点,不要想用一个列表去存素数,这样你的内存会被挤爆。根据素数定理不精确的估计这个数有2e6/(ln(2e6))=137849,也很大对吧。这个我们其实也很容易迭代实现
![](https://i-blog.csdnimg.cn/blog_migrate/1d82bf5889a9f97de611bc7c75b7dd82.png)
![](https://i-blog.csdnimg.cn/blog_migrate/58e93971384661b8655952b634f097b6.png)
一共有148933个素数,比估计的还大,这很正常,素数定理只是一个概率估计。那么现在我要求必须用生成器实现。就是这样子,只是为了做练习而已。
![](https://i-blog.csdnimg.cn/blog_migrate/c07bfe7bbe6a76cf827b625f3e0163a0.png)
代码链接:https://pan.baidu.com/s/1LqBGwIs1wgabveP6rHLhew 密码:enk7