├── 100 ├── 101.md ├── 102.md ├── 103.md ├── 104.md ├── 105.md ├── 106.md ├── 107.md ├── 108.md ├── 109.md ├── 110.md ├── 111.md ├── 112.md ├── 113.md ├── 114.md ├── 115.md ├── 116.md ├── 117.md ├── 118.md ├── 119.md ├── 120.md ├── 121.md ├── 122.md ├── 123.md ├── 124.md ├── 125.md ├── 126.md ├── 127.md ├── 128.md ├── 129.md ├── 130.md ├── 131.md └── README.md ├── 200 ├── 201.md ├── 202.md ├── 203.md ├── 204.md ├── 205.md ├── 206.md ├── 207.md ├── 208.md ├── 209.md ├── 210.md ├── 211.md ├── 212.md ├── 213.md ├── 214.md ├── 215.md ├── 216.md ├── 217.md ├── 218.md ├── 219.md ├── 220.md ├── 221.md ├── 222.md ├── 223.md ├── 224.md ├── 225.md ├── 226.md ├── README.md └── images │ ├── 224_1.png │ ├── 224_2.png │ └── 224_3.png ├── 300 ├── 301.md ├── 302.md ├── 303.md ├── 304.md ├── 305.md ├── 306.md ├── 307.md ├── 308.md ├── 309.md ├── 311.md ├── 312.md ├── 313.md ├── 314.md └── README.md ├── 400 ├── 401.md ├── 402.md ├── 403.md └── README.md ├── 500 ├── 501.md ├── 502.md ├── 503.md └── README.md ├── .gitignore ├── 001.md ├── README.md ├── SUMMARY.md ├── assets ├── 12801.png ├── python.png ├── wechat.jpg ├── weixin.png └── 支付宝.jpg ├── book.json ├── codes ├── 105-1.py ├── 105.py ├── 106-1.py ├── 109.py ├── 111-1.py ├── 118-1.py ├── 129-1.py ├── 129-2.py ├── 130.txt ├── 131.txt ├── 204-1.py ├── 204-2.py ├── 205-1.py ├── 205-2.py ├── 205-3.py ├── 208.txt ├── 213-1.py ├── 213-2.py ├── 217.py ├── 219-2.py ├── 220-2.py ├── 220.py ├── 221.py ├── 225.py ├── __init__.py ├── hello.py ├── mmmm.py ├── request_url.py ├── template │ ├── index.html │ ├── user.html │ └── userscontroller.py └── temploop │ ├── index.html │ └── index.py ├── cover.jpg ├── cover.psd ├── cover_small.jpg └── reading ├── 01.md ├── Python现在成为美国名校中最流行的编程入门语言.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /100/101.md: -------------------------------------------------------------------------------- 1 | ## Python安装 2 | 3 | 任何高级语言都是需要一个自己的编程环境的,这就好比写字一样,需要有纸和笔,在计算机上写东西,也需要有文字处理软件,比如各种名称的OFFICE。笔和纸以及office软件,就是写东西的硬件或软件,总之,那些文字只能写在那个上边,才能最后成为一篇文章。那么编程也是,要有个什么程序之类的东西,要把程序写到那个上面,才能形成最后类似文章那样的东西。 4 | 5 | 刚才又有了一个术语——“程序”,什么是程序?本文就不讲了。如果列为观众不是很理解这个词语,请上网google一下。 6 | 7 | **注:推荐一种非常重要的学习方法** 8 | 9 | 在我这里看文章的零基础朋友,乃至于非零基础的朋友,不要希望在这里学到很多高深的python语言技巧。 10 | 11 | “靠,那看你胡扯吗?” 12 | 13 | 非也。重要的是学会一些方法。比如刚才给大家推荐的“上网google一下”,就是非常好的学习方法。互联网的伟大之处,不仅仅在于打打游戏、看看养眼的照片或者各种视频之类的,当然,在某国很长时间互联网等于娱乐网,我忠心希望从读本文的朋友开始,互联网不仅仅是娱乐网,还是知识网和创造网。扯远了,拉回来。在学习过程中,如果遇到一点点疑问,都不要放过,思考一下、尝试一下之后,不管有没有结果,还都要google一下。 14 | 15 | 列为看好了,我上面写的很清楚,是google一下,不是让大家去用那个什么度来搜索,那个搜索是专用搜索八卦、假药、以及各种穿的很节俭的女孩子照片的。如果你真的要提高自己的技术视野并且专心研究技术问题,请用google。当然,我知道你在用的时候时候困难的,做为一个要在技术上有点成就的人,一定要学点上网的技术的,你懂得。 16 | 17 | 什么?你不懂?你的确是我的读者:零基础。那就具体来问我吧,不管是加入QQ群还是微博,都可以。 18 | 19 | 欲练神功,挥刀自宫。神功是有前提地。 20 | 21 | 要学python,不用自宫。python不用那么残忍的前提,但是,也需要安装点东西才能用。 22 | 23 | 所需要安装的东西,都在这个页面里面:www.python.org/downloads/ 24 | 25 | > www.python.org是python的官方网站,如果你的英语足够使用,那么自己在这里阅读,可以获得非常多的收获。 26 | 27 | 在python的下载页面里面,显示出python目前有两大类,一类是python3.x.x,另外一类是python2.7.x。可以说,python3是未来,它比python2.7有进步。但是,现在,还有很多东西没有完全兼容python3。更何况,如果学了python2.7,对于python3,也只是某些地方的小变化了。 28 | 29 | 所以,我这里是用python2.7为例子来讲授的。 30 | 31 | ## Linux系统的安装 32 | 33 | 看官所用的计算机是什么操作系统的?自己先弄懂。如果是Linux某个发行版,就跟我同道了。并且我恭喜你,因为以后会安装更多的一些python库(模块),在这种操作系统下,操作非常简单,当然,如果是iOS,也一样,因为都是UNIX下的蛋。只是widows有点另类了。 34 | 35 | 不过,没关系,python就是跨平台的。 36 | 37 | 我以ubutu 12.04为例,所有用这个操作系统的朋友(肯定很少啦),你们肯定会在shell中输入python,如果看到了> >,并且显示出python的版本信息,恭喜你,因为你的系统已经自带了python的环境。的确,ubuntu内置了python环境。 38 | 39 | 我非要自己安装一遍不可。那就这么操作吧: 40 | 41 | #下载源码,目前最新版本是2.7.8,如果以后换了,可以在下面的命令中换版本号 42 | #源码也可以在网站上下载,具体见前述下载页面 43 | wget http://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz 44 | 45 | #解压源码包 46 | tar -zxvf Python-2.7.8.tgz 47 | 48 | #编译 49 | cd Python-2.7.8 50 | ./configure --prefix=/usr/local #指定了目录 51 | make&&make install 52 | 53 | 以上步骤,是我从网上找来的,供参考。因为我的机器早就安装了,不想折腾。安装好之后,进入shell,输入python,会看到如下: 54 | 55 | qw@qw-Latitude-E4300:~$ python 56 | Python 2.7.6 (default, Nov 13 2013, 19:24:16) 57 | [GCC 4.6.3] on linux2 58 | Type "help", "copyright", "credits" or "license" for more information. 59 | > > 60 | 61 | 恭喜你,安装成功了。我用的是python2.7.6,或许你的版本号更高。 62 | 63 | ## windows系统的安装 64 | 65 | 到[下载页面里面](https://www.python.org/download/releases/2.7.8/)找到windows安装包,下载之,比如下载了这个文件:python-2.7.8.msi。然后就是不断的“下一步”,即可完成安装。 66 | 67 | 特别注意,安装完之后,需要检查一下,在环境变量是否有python。 68 | 69 | > 如果还不知道什么是windows环境变量,以及如何设置。不用担心,请google一下,搜索:"windows 环境变量"就能找到如何设置了。 70 | 71 | 以上搞定,在cmd中,输入python,得到跟上面类似的结果,就说明已经安装好了。 72 | 73 | ## Mac OS X系统的安装 74 | 75 | 其实根本就不用再写怎么安装了,因为用Mac OS X 的朋友,肯定是高手中的高高手了,至少我一直很敬佩那些用Mac OS X 并坚持没有更换为windows的。麻烦用Mac OS X 的朋友自己网上搜吧,跟前面unbutu差不多。 76 | 77 | 如果按照以上方法,顺利安装成功,只能说明幸运,无它。如果没有安装成功,这是提高自己的绝佳机会,因为只有遇到问题才能解决问题,才能知道更深刻的道理,不要怕,有google,它能帮助列为看官解决所有问题。当然,加入QQ群或者通过微博,问我也可以。 78 | 79 | 就一般情况而言,Linux和Mac OS x系统都已经安装了某种python的版本,打开就可以使用。但是windows是肯定不安装的。除了可以用上面所说的方法安装,还有一个更省事的方法,就是安装:ActivePython 80 | 81 | ## 用ActivePython安装 82 | 83 | 这个ActivePython是一个面向好多种操作系统的Python 套件,它包含了一个完整的 Python 发布、一个适用于 Python 编程的 IDE 以及一些 Python的。有兴趣的看官可以到其官网浏览:[http://www.activestate.com](http://www.activestate.com/activepython) 84 | 85 | ## 用源码安装 86 | 87 | python是开源的,它的源码都在网上。有高手朋友,如果愿意用源码来安装,亦可,请到:[https://www.python.org/ftp/python/](https://www.python.org/ftp/python/),下载源码安装。 88 | 89 | 简单记录一下我的安装方法(我是在linux系统中做的): 90 | 91 | 1. 获得root权限 92 | 2. 到上述地址下载某种版本的python: wget https://www.python.org/ftp/python/2.7.8/Python-2.7.8.tgz 93 | 3. 解压缩:tar xfz Python-2.7.8.tgz 94 | 4. 进入该目录:cd Python-2.7.8 95 | 5. 配置: ./configure 96 | 6. 在上述文件夹内运行:make,然后运行:make install 97 | 7. 祝你幸运 98 | 8. 安装完毕 99 | 100 | OK!已经安装好之后,马上就可以开始编程了。 101 | 102 | 最后喊一句在一个编程视频课程广告里面看到的口号,很有启发:“我们程序员,不求通过,但求报错”。 103 | -------------------------------------------------------------------------------- /100/102.md: -------------------------------------------------------------------------------- 1 | ## 集成开发环境(IDE) 2 | 3 | 当安装好python之后,其实就已经可以进行开发了。下面我们开始写第一行python代码。 4 | 5 | ## 值得纪念的时刻:Hello world 6 | 7 | 如果是用windows,请打开CMD,并执行python。 8 | 9 | 如果是UNIX类的,就运行shell,并执行python。 10 | 11 | 都会出现如下内容: 12 | 13 | Python 2.7.6 (default, Nov 13 2013, 19:24:16) 14 | [GCC 4.6.3] on linux2 15 | Type "help", "copyright", "credits" or "license" for more information. 16 | >>> 17 | 18 | 在>>>后面输入下面内容,并按回车。这就是见证奇迹的时刻。从这一刻开始,一个从来不懂编程的你,就跨入了程序员行列,不管你的工作是不是编程,你都已经是程序员了,其标志就是你已经用代码向这个世界打招呼了。 19 | 20 | >>> print "Hello, World" 21 | Hello, World 22 | 23 | 每个程序员,都曾经经历过这个伟大时刻,不经历这个伟大时刻的程序员不是伟大的程序员。为了纪念这个伟大时刻,理解其伟大之所在,下面执行分解动作: 24 | 25 | >说明:在下面的分解动作中,用到了一个符号:#,就是键盘上数字3上面的那个井号,通过按下shift,然后按3,就得到了。这个符号,在python编程中,表示注释。所谓注释,就是在计算机不执行,只是为了说明某行语句表达什么意思。 26 | 27 | #看到“>>>”符号,表示python做好了准备,当代你向她发出指令,让她做什么事情 28 | >>> 29 | 30 | #print,意思是打印。在这里也是这个意思,是要求python打印什么东西 31 | >>> print 32 | 33 | #"Hello,World"是打印的内容,注意,量变的双引号,都是英文状态下的。引号不是打印内容,它相当于一个包裹,把打印的内容包起来,统一交给python。 34 | >>> print "Hello, World" 35 | 36 | #上面命令执行的结果。python接收到你要求她所做的事情:打印Hello,World,于是她就老老实实地执行这个命令,丝毫不走样。 37 | Hello, World 38 | 39 | 祝贺,伟大的程序员。 40 | 41 | >笑一笑:有一个程序员,自己感觉书法太烂了,于是立志继承光荣文化传统,购买了笔墨纸砚。在某天,开始练字。将纸铺好,拿起笔蘸足墨水,挥毫在纸上写下了两个打字:Hello World 42 | 43 | 从此,进入了程序员行列,但是,看官有没有感觉,程序员用的这个工具,就是刚才打印Hello,World的那个cmd或者shell,是不是太简陋了?你看美工妹妹用的Photoshop,行政妹妹用的word,出纳妹妹用的Excel,就连坐在老板桌后面的那个家伙还用一个PPT播放自己都不相信的新理念呢,难道我们伟大的程序员,就用这么简陋的工具写出旷世代码吗? 44 | 45 | 当然不是。软件是谁开发的?程序员。程序员肯定会先为自己打造好用的工具,这也叫做近水楼台先得月。 46 | 47 | IDE就是程序员的工具。 48 | 49 | ## 集成开发环境 50 | 51 | IDE的全称是:Integrated Development Environment,简称IDE,也稱為Integration Design Environment、Integration Debugging Environment,翻译成中文叫做“集成开发环境”,在台湾那边叫做“整合開發環境”。它是一種輔助程式開發人員開發軟體的應用軟體。 52 | 53 | 下面就直接抄[维基百科上的说明了](http://zh.wikipedia.org/zh/%E9%9B%86%E6%88%90%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83): 54 | 55 | >IDE通常包括程式語言編輯器、自動建立工具、通常還包括除錯器。有些IDE包含編譯器/直譯器,如微软的Microsoft Visual Studio,有些则不包含,如Eclipse、SharpDevelop等,这些IDE是通过调用第三方编译器来实现代码的编译工作的。有時IDE還會包含版本控制系統和一些可以設計圖形用戶界面的工具。許多支援物件導向的現代化IDE還包括了類別瀏覽器、物件檢視器、物件結構圖。雖然目前有一些IDE支援多種程式語言(例如Eclipse、NetBeans、Microsoft Visual Studio),但是一般而言,IDE主要還是針對特定的程式語言而量身打造(例如Visual Basic)。 56 | 57 | 看不懂,没关系,看图,认识一下,混个脸熟就好了。所谓有图有真相。 58 | 59 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10201.png) 60 | 61 | 上面的图显示的是微软的提供的名字叫做Microsoft Visual Studio的IDE。用C#进行编程的程序员都用它。 62 | 63 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10202.png) 64 | 65 | 上图是在苹果电脑中出现的名叫XCode的IDE。 66 | 67 | 要想了解更多IDE的信息,推荐阅读维基百科中的词条 68 | 69 | - 英文词条:[Integrated development environment](http://en.wikipedia.org/wiki/Integrated_development_environment) 70 | - 中文词条:[集成开发环境](http://zh.wikipedia.org/zh/%E9%9B%86%E6%88%90%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83) 71 | 72 | ## Python的IDE 73 | 74 | google一下:python IDE,会发现,能够进行python编程的IDE还真的不少。东西一多,就开始无所适从了。所有,有不少人都问用哪个IDE好。可以看看[这个提问,还列出了众多IDE的比较](http://stackoverflow.com/questions/81584/what-ide-to-use-for-python)。 75 | 76 | >顺便向列为看客推荐一个非常好的开发相关网站:[stackoverflow.com](http://stackoverflow.com/) 77 | >在这里可以提问,可以查看答案。一般如果有问题,先在这里查找,多能找到非常满意的结果,至少有很大启发。 78 | >在某国有时候有地方可能不能访问,需要科学上网。好东西,一定不会让你容易得到,也不会让任何人都得到。 79 | 80 | 那么做为零基础的学习者,用什么好呢? 81 | 82 | 既然是零基础,就别瞎折腾了,就用Python自带的IDLE。原因就是:简单。 83 | 84 | Windows的朋友操作:“开始”菜单->“所有程序”->“Python 2.x”->“IDLE(Python GUI)”来启动IDLE。启动之后,大概看到这样一个图 85 | 86 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10203.png) 87 | 88 | 注意:看官所看到的界面中显示版本跟这个图不同,因为安装的版本区别。大致模样差不多。 89 | 90 | 其它操作系统的用户,也都能在找到idle这个程序,启动之后,跟上面一样的图。 91 | 92 | 后面我们所有的编程,就在这里完成了。这就是伟大程序员用的第一个IDE。 93 | 94 | 磨刀不误砍柴工。IDE已经有了,伟大程序员就要开始从事伟大的编程工作了。且看下回分解。 95 | -------------------------------------------------------------------------------- /100/103.md: -------------------------------------------------------------------------------- 1 | >For I am not ashamed of the gospel; it is the power of God for salvation to everyone who has faith, to the Jew first and also to the Greek. For in it the righteousness of God is revealed through faith for faith; s it is written,"The one who is righteous will live by faith" 2 | 3 | ## 用Python计算 4 | 5 | 一提到计算机,当然现在更多人把她叫做电脑,这两个词都是指computer。不管什么,只要提到她,普遍都会想到她能够比较快地做加减乘除,甚至乘方开方等。乃至于,有的人在口语中区分不开计算机和计算器。 6 | 7 | 那么,做为零基础学习这,也就从计算小学数学题目开始吧。因为从这里开始,数学的基础知识列为肯定过关了。 8 | 9 | ## 复习 10 | 11 | 还是先来重温一下伟大时刻,打印hello world. 12 | 13 | 打开电脑,让python idle运行起来,然后输入: 14 | 15 | >>> print 'Hello, World' 16 | Hello, World 17 | 18 | 细心的看官,是否注意到,我在这里用的是单引号,[上次](102.md)用的是双引号。两者效果一样,也就是在这种情况下,单引号和双引号是一样的效果,一定要是成对出现的,不能一半是单引号,另外一半是双引号。 19 | 20 | ## 四则运算 21 | 22 | 按照下面要求,在ide中运行,看看得到的结果和用小学数学知识运算之后得到的结果是否一致 23 | ```python 24 | >>> 2+5 25 | 7 26 | >>> 5-2 27 | 3 28 | >>> 10/2 29 | 5 30 | >>> 5*2 31 | 10 32 | >>> 10/5+1 33 | 3 34 | >>> 2*3-4 35 | 2 36 | ``` 37 | 上面的运算中,分别涉及到了四个运算符号:加(+)、减(-)、乘(*)、除(/) 38 | 39 | 另外,我相信看官已经发现了一个重要的公理: 40 | 41 | ### 在计算机中,四则运算和小学数学中学习过的四则运算规则是一样的 42 | 43 | 要不说人是高等动物呢,自己发明的东西,一定要继承自己已经掌握的知识,别跟自己的历史过不去。伟大的科学家们,在当初设计计算机的时候就想到列为现在学习的需要了,一定不能让后世子孙再学新的运算规则,就用小学数学里面的好了。感谢那些科学家先驱者,泽被后世。 44 | 45 | 下面计算三个算术题,看看结果是什么 46 | 47 | - 4 + 2 48 | - 4.0 + 2 49 | - 4.0 + 2.0 50 | 51 | 看官可能愤怒了,这么简单的题目,就不要劳驾计算机了,太浪费了。 52 | 53 | 别着急,还是要在ide中运算一下,然后看看结果,有没有不一样?要仔细观察哦。 54 | ```python 55 | >>> 4+2 56 | 6 57 | >>> 4.0+2 58 | 6.0 59 | >>> 4.0+2.0 60 | 6.0 61 | ``` 62 | 不一样的地方是:第一个式子结果是6,后面两个是6.0。 63 | 64 | 现在我们就要引入两个数据类型:整数和浮点数 65 | 66 | 对这两个的定义,不用死记硬背,google一下。记住爱因斯坦说的那句话:书上有的我都不记忆(是这么的说?好像是,大概意思,反正我也不记忆)。后半句他没说,我补充一下:忘了就google。 67 | 68 | 定义1:类似4、-2、129486655、-988654、0这样形式的数,称之为整数 69 | 70 | 定义2:类似4.0、-2.0、2344.123、3.1415926这样形式的数,称之为浮点数 71 | 72 | 比较好理解,整数,就是小学学过的整数;浮点数,就是小数。如果整数写成小数形式,比如4写成4.0,也就变成了浮点数。 73 | 74 | 爱学习,就要有探索精神。看官在网上google一下整数,会发现还有另外一个词:长整数(型)。顾名思义,就是比较长的整数啦。在有的语言中,把这个做为单独一类区分开,但是,在python中,我们不用管这个了。只要是整数,就只是整数,不用区分长短(以前版本区分),因为区分没有什么意思,而且跟小学学过的数学知识不协调。 75 | 76 | 还有一个问题,需要向看官交代一下,眼前可能用不到,但是会总有一些人用这个来忽悠你,当他忽悠你的时候,下面的知识就用到了。 77 | 78 | **整数溢出问题** 79 | 80 | 这里有一篇专门讨论这个问题的文章,推荐阅读:[整数溢出](http://zhaoweizhuanshuo.blog.163.com/blog/static/148055262201093151439742/) 81 | 82 | 对于其它语言,整数溢出是必须正视的,但是,在python里面,看官就无忧愁了,原因就是python为我们解决了这个问题,请阅读拙文:[大整数相乘](https://github.com/qiwsir/algorithm/blob/master/big_int.md) 83 | 84 | ok!看官可以在IDE中实验一下大整数相乘。 85 | 86 | >>> 123456789870987654321122343445567678890098876*1233455667789990099876543332387665443345566 87 | 152278477193527562870044352587576277277562328362032444339019158937017801601677976183816L 88 | 89 | 看官是幸运的,python解忧愁,所以,选择学习python就是珍惜光阴了。 90 | 91 | 上面计算结果的数字最后有一个L,就表示这个数是一个长整数,不过,看官不用管这点,反正是python为我们搞定了。 92 | 93 | 在结束本节之前,有两个符号需要看官牢记(不记住也没关系,可以随时google,只不过记住后使用更方便) 94 | 95 | - 整数,用int表示,来自单词:integer 96 | - 浮点数,用float表示,就是单词:float 97 | 98 | 可以用一个命令:type(object)来检测一个数是什么类型。 99 | 100 | >>> type(4) 101 | #4是int,整数 102 | >>> type(5.0) 103 |  #5.0是float,浮点数 104 | type(988776544222112233445566778899887766554433221133344455566677788998776543222344556678) 105 | #是长整数,也是一个整数 106 | 107 | ## 几个常见函数 108 | 109 | 在这里就提到函数,因为这个东西是经常用到的。什么是函数?如果看官不知道此定义,可以去google。貌似是初二数学讲的了。 110 | 111 | 有几个常用的函数,列一下,如果记不住也不要紧,知道有这些就好了,用的时候就google。 112 | 113 | **求绝对值** 114 | ```python 115 | >>> abs(10) 116 | 10 117 | >>> abs(-10) 118 | 10 119 | >>> abs(-1.2) 120 | 1.2 121 | ``` 122 | **四舍五入** 123 | ```python 124 | >>> round(1.234) 125 | 1.0 126 | >>> round(1.234,2) 127 | 1.23 128 | 129 | >>> #如果不清楚这个函数的用法,可以使用下面方法看帮助信息 130 | >>> help(round) 131 | 132 | Help on built-in function round in module __builtin__: 133 | 134 | round(...) 135 | round(number[, ndigits]) -> floating point number 136 | 137 | Round a number to a given precision in decimal digits (default 0 digits). 138 | This always returns a floating point number. Precision may be negative. 139 | ``` 140 | **幂函数** 141 | 142 | >>> pow(2,3) #2的3次方 143 | 8 144 | 145 | **math模块**(对于模块可能还有点陌生,不过不要紧,先按照下面代码实验一下,慢慢就理解了) 146 | ```python 147 | >>> import math #引入math模块 148 | >>> math.floor(32.8) #取整,不是四舍五入 149 | 32.0 150 | >>> math.sqrt(4) #开平方 151 | 2.0 152 | ``` 153 | 154 | ## 总结 155 | 156 | - python里的加减乘除按照小学数学规则执行 157 | - 不用担心大整数问题,python会自动处理 158 | - type(object)是一个有用的东西 159 | -------------------------------------------------------------------------------- /100/104.md: -------------------------------------------------------------------------------- 1 | >"I give you a new commandment, that you love one another. Just as I have loved you, you also should love one another. By this everyone will know that you are my disciples, if you have love for one another."(JOHN14:34-35) 2 | 3 | ## 啰嗦的除法 4 | 5 | 除法啰嗦,不仅是python。 6 | 7 | ## 整数除以整数 8 | 9 | 看官请在进入python交互模式之后(以后在本教程中,可能不再重复这类的叙述,只要看到>>>,就说明是在交互模式下,这个交互模式,看官可以在ide中,也可以像我一样直接在shell中运行python进入交互模式),练习下面的运算: 10 | ```python 11 | >>> 2/5 12 | 0 13 | >>> 2.0/5 14 | 0.4 15 | >>> 2/5.0 16 | 0.4 17 | >>> 2.0/5.0 18 | 0.4 19 | ``` 20 | 看到没有?麻烦出来了(这是在python2.x中),如果从小学数学知识除法,以上四个运算结果都应该是0.4。但我们看到的后三个符合,第一个居然结果是0。why? 21 | 22 | 因为,在python(严格说是python2.x中,python3会有所变化,具体看官要了解,可以去google)里面有一个规定,像2/5中的除法这样,是要取整(就是去掉小数,但不是四舍五入)。2除以5,商是0(整数),余数是2(整数)。那么如果用这种形式:2/5,计算结果就是商那个整数。或者可以理解为:**整数除以整数,结果是整数(商)**。 23 | 24 | 继续实验,验证这个结论: 25 | ```python 26 | >>> 5/2 27 | 2 28 | >>> 6/3 29 | 2 30 | >>> 5/2 31 | 2 32 | >>> 6/2 33 | 3 34 | >>> 7/2 35 | 3 36 | >>> 8/2 37 | 4 38 | >>> 9/2 39 | 4 40 | ``` 41 | **注意:**这里是得到整数商,而不是得到含有小数位的结果后“四舍五入”。例如5/2,得到的是商2,余数1,最终5/2=2。并不是对2.5进行四舍五入。 42 | 43 | ##浮点数与整数相除 44 | 45 | 列位看官注意,这个标题和上面的标题格式不一样,上面的标题是“整数除以整数”,如果按照风格一贯制的要求,本节标题应该是“浮点数除以整数”,但没有,现在是“浮点数与整数相除”,其含义是: 46 | 47 | >假设:x除以y。其中 x 可能是整数,也可能是浮点数;y可能是整数,也可能是浮点数。 48 | 49 | 出结论之前,还是先做实验: 50 | ```python 51 | >>> 9.0/2 52 | 4.5 53 | >>> 9/2.0 54 | 4.5 55 | >>> 9.0/2.0 56 | 4.5 57 | >>> 8.0/2 58 | 4.0 59 | >>> 8/2.0 60 | 4.0 61 | >>> 8.0/2.0 62 | 4.0 63 | ``` 64 | 归纳,得到规律:**不管是被除数还是除数,只要有一个数是浮点数,结果就是浮点数。**所以,如果相除的结果有余数,也不会像前面一样了,而是要返回一个浮点数,这就跟在数学上学习的结果一样了。 65 | ```python 66 | >>> 10.0/3 67 | 3.3333333333333335 68 | ``` 69 | 这个是不是就有点搞怪了,按照数学知识,应该是3.33333...,后面是3的循环了。那么你的计算机就停不下来了,满屏都是3。为了避免这个,python武断终结了循环,但是,可悲的是没有按照“四舍五入”的原则终止。 70 | 71 | 关于无限循环小数问题,小学都学习了,但是这可不是一个简单问题,看看[维基百科的词条:0.999...](http://zh.wikipedia.org/wiki/0.999%E2%80%A6),会不会有深入体会呢? 72 | 73 | 总之,要用python,就得遵循她的规定,前面两条规定已经明确了。 74 | 75 | >补充一个资料,供有兴趣的朋友阅读:[浮点数算法:争议和限制](https://docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues) 76 | 77 | **说明:**以上除法规则,是针对python2,在python3中,将5/2和5.0/2等同起来了。不过,如果要得到那个整数部分的上,可以用另外一种方式:地板除. 78 | 79 | >>> 9/2 80 | 4 81 | >>> 9//2 82 | 4 83 | 84 | python总会要提供多种解决问题的方案的,这是她的风格。 85 | 86 | ##引用模块解决除法--启用轮子 87 | 88 | python之所以受人欢迎,一个很重重要的原因,就是轮子多。这是比喻啦。就好比你要跑的快,怎么办?光天天练习跑步是不行滴,要用轮子。找辆自行车,就快了很多。还嫌不够快,再换电瓶车,再换汽车,再换高铁...反正你可以选择的很多。但是,这些让你跑的快的东西,多数不是你自己造的,是别人造好了,你来用。甚至两条腿也是感谢父母恩赐。正是因为轮子多,可以选择的多,就可以以各种不同速度享受了。 89 | 90 | python就是这样,有各种各样别人造好的轮子,我们只需要用。只不过那些轮子在python里面的名字不叫自行车、汽车,叫做“模块”,有人承接别的语言的名称,叫做“类库”、“类”。不管叫什么名字把。就是别人造好的东西我们拿过来使用。 91 | 92 | 怎么用?可以通过两种形式用: 93 | 94 | - 形式1:import module-name。import后面跟空格,然后是模块名称,例如:import os 95 | - 形式2:from module1 import module11。module1是一个大模块,里面还有子模块module11,只想用module11,就这么写了。比如下面的例子: 96 | 97 | 不啰嗦了,实验一个: 98 | 99 | >>> from __future__ import division 100 | >>> 5/2 101 | 2.5 102 | >>> 9/2 103 | 4.5 104 | >>> 9.0/2 105 | 4.5 106 | >>> 9/2.0 107 | 4.5 108 | 109 | 注意了,引用了一个模块之后,再做除法,就不管什么情况,都是得到浮点数的结果了。 110 | 111 | 这就是轮子的力量。 112 | 113 | ##关于余数 114 | 115 | 前面计算5/2的时候,商是2,余数是1 116 | 117 | 余数怎么得到?在python中(其实大多数语言也都是),用`%`符号来取得两个数相除的余数. 118 | 119 | 实验下面的操作: 120 | ```python 121 | >>> 5%2 122 | 1 123 | >>> 9%2 124 | 1 125 | >>> 7%3 126 | 1 127 | >>> 6%4 128 | 2 129 | >>> 5.0%2 130 | 1.0 131 | ``` 132 | 符号:%,就是要得到两个数(可以是整数,也可以是浮点数)相除的余数。 133 | 134 | 前面说python有很多人见人爱的轮子(模块),她还有丰富的内建函数,也会帮我们做不少事情。例如函数`divmod()` 135 | 136 | >>> divmod(5,2) #表示5除以2,返回了商和余数 137 | (2, 1) 138 | >>> divmod(9,2) 139 | (4, 1) 140 | >>> divmod(5.0,2) 141 | (2.0, 1.0) 142 | 143 | ##四舍五入 144 | 145 | 最后一个了,一定要坚持,今天的确有点啰嗦了。要实现四舍五入,很简单,就是内建函数:`round()` 146 | 147 | 动手试试: 148 | 149 | >>> round(1.234567,2) 150 | 1.23 151 | >>> round(1.234567,3) 152 | 1.235 153 | >>> round(10.0/3,4) 154 | 3.3333 155 | 156 | 简单吧。越简单的时候,越要小心,当你遇到下面的情况,就有点怀疑了: 157 | 158 | >>> round(1.2345,3) 159 | 1.234 #应该是:1.235 160 | >>> round(2.235,2) 161 | 2.23 #应该是:2.24 162 | 163 | 哈哈,我发现了python的一个bug,太激动了。 164 | 165 | 别那么激动,如果真的是bug,这么明显,是轮不到我的。为什么?具体解释看这里,下面摘录官方文档中的一段话: 166 | 167 | >**Note:** 168 | >The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See [Floating Point Arithmetic: Issues and Limitations](https://docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues) for more information. 169 | 170 | 原来真的轮不到我。(垂头丧气状。) 171 | 172 | 似乎除法的问题到此要结束了,其实远远没有,不过,做为初学者,至此即可。还留下了很多话题,比如如何处理循环小数问题,我肯定不会让有探索精神的朋友失望的,在我的github中有这样一个轮子,如果要深入研究,[可以来这里尝试](https://github.com/qiwsir/algorithm/blob/master/divide.py)。 173 | -------------------------------------------------------------------------------- /100/105.md: -------------------------------------------------------------------------------- 1 | ## 开始真正编程 2 | 3 | 通过对四则运算的学习,已经初步接触了Python中内容,如果看官是零基础的学习者,可能有点迷惑了。难道在IDE里面敲几个命令,然后看到结果,就算编程了?这也不是那些能够自动运行的程序呀? 4 | 5 | 的确。到目前位置,还不能算编程,只能算会用一些指令(或者叫做命令)来做点简单的工作。并且看官所在的那个IDE界面,也是输入指令用的。 6 | 7 | 列位稍安勿躁,下面我们就学习如何编写一个真正的程序。工具还是那个IDLE,但是,请大家谨记,对于一个真正的程序来讲,用什么工具是无所谓的,只要能够把指令写进去,比如用记事本也可以。 8 | 9 | 我去倒杯茶,列位先认真读一读下面一段,关于程序的概念,内容来自维基百科: 10 | 11 | - 先阅读一段英文的:[computer program and source code](http://en.wikipedia.org/wiki/Computer_program),看不懂不要紧,可以跳过去,直接看下一条。 12 | 13 | >A computer program, or just a program, is a sequence of instructions, written to perform a specified task with a computer.[1] A computer requires programs to function, typically executing the program's instructions in a central processor.[2] The program has an executable form that the computer can use directly to execute the instructions. The same program in its human-readable source code form, from which executable programs are derived (e.g., compiled), enables a programmer to study and develop its algorithms. A collection of computer programs and related data is referred to as the software. 14 | 15 | >Computer source code is typically written by computer programmers.[3] Source code is written in a programming language that usually follows one of two main paradigms: imperative or declarative programming. Source code may be converted into an executable file (sometimes called an executable program or a binary) by a compiler and later executed by a central processing unit. Alternatively, computer programs may be executed with the aid of an interpreter, or may be embedded directly into hardware. 16 | 17 | >Computer programs may be ranked along functional lines: system software and application software. Two or more computer programs may run simultaneously on one computer from the perspective of the user, this process being known as multitasking. 18 | 19 | - [计算机程序](http://zh.wikipedia.org/wiki/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F) 20 | 21 | >计算机程序(Computer Program)是指一组指示计算机或其他具有信息处理能力装置每一步动作的指令,通常用某种程序设计语言编写,运行于某种目标体系结构上。打个比方,一个程序就像一个用汉语(程序设计语言)写下的红烧肉菜谱(程序),用于指导懂汉语和烹饪手法的人(体系结构)来做这个菜。 通常,计算机程序要经过编译和链接而成为一种人们不易看清而计算机可解读的格式,然后运行。未经编译就可运行的程序,通常称之为脚本程序(script)。 22 | 23 | 碧螺春,是我最喜欢的了。有人要送礼给我,请别忘记了。难道我期望列位看官会送吗?哈哈哈 24 | 25 | 废话少说,开始说程序。程序,简而言之,就是指令的集合。但是,有的程序需要编译,有的不需要。python编写的程序就不需要,因此她也被称之为脚本程序。特别提醒列位,不要认为编译的就好,不编译的就不好;也不要认为编译的就“高端”,不编译的就属于“低端”。有一些做了很多年程序的程序员或者其它什么人,可能会有这样的想法,这是毫无根据的。 26 | 27 | 不争论。用得妙就是好。 28 | 29 | ## 用IDLE的编程环境 30 | 31 | 操作:File->New window 32 | 33 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10501.png) 34 | 35 | 这样,就出现了一个新的操作界面,在这个界面里面,看不到用于输入指令的提示符:>>>,这个界面有点像记事本。说对了,本质上就是一个记事本,只能输入文本,不能直接在里面贴图片。 36 | 37 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10502.png) 38 | 39 | ## 写两个大字:Hello,World 40 | 41 | Hello,World.是面向世界的标志,所以,写任何程序,第一句一定要写这个,因为程序员是面向世界的,绝对不畏缩在某个局域网内,所以,所以看官要会科学上网,才能真正与世界Hello。 42 | 43 | 直接上代码,就这么一行即可。 44 | 45 | print "Hello,World" 46 | 47 | 如下图的样式 48 | 49 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10503.png) 50 | 51 | 前面说过了,程序就是指令的集合,现在,这个程序里面,就一条指令。一条指令也可以成为集合。 52 | 53 | 注意观察,菜单上有一个RUN,点击这个菜单,在下拉的里面选择Run Moudle 54 | 55 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10504.png) 56 | 57 | 会弹出对话框,要求把这个文件保存,这就比较简单了,保存到一个位置,看官一定要记住这个位置,并且取个文件名,文件名是以.py为扩展名的。 58 | 59 | 都做好之后,点击确定按钮,就会发现在另外一个带有>>>的界面中,就自动出来了Hello,World两个大字。 60 | 61 | 成功了吗?成功了也别兴奋,因为还没有到庆祝的时候。 62 | 63 | 在这种情况系,我们依然是在IDLE的环境中实现了刚才那段程序的自动执行,如果脱离这个环境呢? 64 | 65 | 下面就关闭IDLE,打开shell(如果看官在使用苹果的 Mac OS 操作系统或者某种linux发行版的操作系统,比如我使用的是ubuntu),或者打开cmd(windows操作系统的用户,特别提醒用windows的用户,使用windows不是你的错,错就错在你只会使用鼠标点来点去,而不想也不会使用命令,更不想也不会使用linux的命令,还梦想成为优秀程序员。),通过命令的方式,进入到你保存刚才的文件目录。 66 | 67 | 下图是我保存那个文件的地址,我把那个文件命名为105.py,并保存在一个文件夹中。 68 | 69 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10505.png) 70 | 71 | 然后在这个shell里面,输入:python 105.py 72 | 73 | 上面这句话的含义就是告诉计算机,给我运行一个python语言编写的程序,那个程序文件的名称是105.py 74 | 75 | 我的计算机我做主。于是它给我乖乖地执行了这条命令。如下图: 76 | 77 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10506.png) 78 | 79 | 还在沉默?可以欢呼了,德国队7:1胜巴西对,列看官中,不管是德国队还是巴西队的粉丝,都可以欢呼,因为你在程序员道路上迈出了伟大的第二步。顺便预测一下,本届世界杯最终冠军应该是:中国队。(还有这么扯的吗?) 80 | 81 | ## 解一道题目 82 | 83 | 请计算:19+2*4-8/2 84 | 85 | 代码如下: 86 | 87 | #coding:utf-8 88 | 89 | """ 90 | 请计算:19+2*4-8/2 91 | """ 92 | 93 | a = 19+2*4-8/2 94 | print a 95 | 96 | 提醒初学者,别复制这段代码,而是要一个字一个字的敲进去。然后保存(我保存的文件名是:105-1.py)。 97 | 98 | 在shell或者cmd中,执行:python (文件名.py) 99 | 100 | 执行结果如下图: 101 | 102 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/10507.png) 103 | 104 | 上面代码中,第一行,不能少,本文件是能够输入汉字的,否则汉字无法输入。 105 | 106 | 好像还是比较简单。 107 | 108 | 别着急。复杂的在后面呢。 109 | -------------------------------------------------------------------------------- /100/108.md: -------------------------------------------------------------------------------- 1 | ## 玩转字符串(2) 2 | 3 | 上一章中已经讲到连接两个字符串的一种方法。复习一下: 4 | ```python 5 | >>> a= 'py' 6 | >>> b= 'thon' 7 | >>> a+b 8 | 'python' 9 | ``` 10 | 既然这是一种方法,言外之意,还有另外一种方法。 11 | 12 | ### 连接字符串的方法2 13 | 14 | 在说方法2之前,先说明一下什么是占位符,此前在讲解变量(参数)的时候,提到了占位符,这里对占位符做一个比较严格的定义: 15 | 16 | 来自[百度百科](http://baike.baidu.com/view/873819.htm)的定义: 17 | 18 | >顾名思义,占位符就是先占住一个固定的位置,等着你再往里面添加内容的符号。 19 | 20 | 根据这个定义,在python里面规定了一些占位符,通过这些占位符来说明那个位置应该填写什么类型的东西,这里暂且了解两个占位符:%d——表示那个位置是整数,%s——表示那个位置应该是字符串。下面看一个具体实例: 21 | ```python 22 | >>> print "one is %d"%1 23 | one is 1 24 | ``` 25 | 要求打印(print)的内容中,有一个%d占位符,就是说那个位置应该放一个整数。在第二个%后面,跟着的就是那个位置应该放的东西。这里是一个整数1。我们做下面的操作,就可以更清楚了解了: 26 | ```python 27 | >>> a=1 28 | >>> type(a) 29 | #a是整数 30 | >>> b="1" 31 | >>> type(b) 32 | #b是字符串 33 | >>> print "one is %d"%a 34 | one is 1 35 | >>> print "one is %d"%b #报错了,这个占位符的位置应该放整数,不应该放字符串。 36 | Traceback (most recent call last): 37 | File "", line 1, in 38 | TypeError: %d format: a number is required, not str 39 | ``` 40 | 同样道理,%s对应的位置应该放字符串,但是,如果放了整数,也可以。只不过是已经转为字符串对待了。但是不赞成这么做。在将来,如果使用mysql(一种数据库)的时候,会要求都用%s做为占位符,这是后话,听听有这么回事即可。 41 | ```python 42 | >>> print "one is %s"%b 43 | one is 1 44 | >>> print "one is %s"%a #字符串是包容的 45 | one is 1 46 | ``` 47 | 好了。啰嗦半天,占位符是不是理解了呢?下面我们就用占位符来连接字符串。是不是很有意思? 48 | ```python 49 | >>> a = "py" 50 | >>> b = "thon" 51 | >>> print "%s%s"%(a,b) #注 52 | python 53 | ``` 54 | **注:**仔细观察,如果两个占位符,要向这两个位置放东西,代表的东西要写在一个圆括号内,并且中间用逗号(半角)隔开。 55 | 56 | ##字符串复制 57 | 58 | 有一个变量,连接某个字符串,也想让另外一个变量,也连接这个字符串。一种方法是把字符串再写一边,这种方法有点笨拙,对于短的到无所谓了。但是长的就麻烦了。这里有一种字符串复制的方法: 59 | ```python 60 | >>> a = "My name is LaoQi. I like python and can teach you to learn it." 61 | >>> print a 62 | My name is LaoQi. I like python and can teach you to learn it. 63 | >>> b = a 64 | >>> print b 65 | My name is LaoQi. I like python and can teach you to learn it. 66 | >>> print a 67 | My name is LaoQi. I like python and can teach you to learn it. 68 | ``` 69 | 70 | 复制非常简单,类似与赋值一样。可以理解为那个字符串本来跟a连接着,通过b=a,a从自己手里分处一股绳子给了b,这样两者都可以指向那个字符串了。 71 | 72 | ## 字符串长度 73 | 74 | 要向知道一个字符串有多少个字符,一种方法是从头开始,盯着屏幕数一数。哦,这不是计算机在干活,是键客在干活。键客,不是剑客。剑客是以剑为武器的侠客;而键客是以键盘为武器的侠客。当然,还有贱客,那是贱人的最高境界,贱到大侠的程度,比如岳不群之流。 75 | 76 | 键客这样来数字符串长度: 77 | ```python 78 | >>> a="hello" 79 | >>> len(a) 80 | 5 81 | ``` 82 | 使用的是一个函数len(object)。得到的结果就是该字符串长度。 83 | ```python 84 | >>> m = len(a) #把结果返回后赋值给一个变量 85 | >>> m 86 | 5 87 | >>> type(m) #这个返回值(变量)是一个整数型 88 | 89 | ``` 90 | ## 字符大小写的转换 91 | 92 | 对于英文,有时候要用到大小写转换。最有名驼峰命名,里面就有一些大写和小写的参合。如果有兴趣,可以来这里看[自动将字符串转化为驼峰命名形式的方法](https://github.com/qiwsir/algorithm/blob/master/string_to_hump.md)。 93 | 94 | 在python中有下面一堆内建函数,用来实现各种类型的大小写转化 95 | 96 | - S.upper() #S中的字母大写 97 | - S.lower() #S中的字母小写 98 | - S.capitalize() #首字母大写 99 | - S.istitle() #单词首字母是否大写的,且其它为小写,**注**网友白羽毛指出,这里表述不准确。非常感谢他。为了让看官对这些大小写问题有更深刻理解,我从新写下面的例子,请看官审查。再次感谢白羽毛。 100 | - S.isupper() #S中的字母是否全是大写 101 | - S.islower() #S中的字母是否全是小写 102 | 103 | 看例子: 104 | ```python 105 | >>> a = "qiwsir,python" 106 | >>> a.upper() #将小写字母完全变成大写字母 107 | 'QIWSIR,PYTHON' 108 | >>> a #原数据对象并没有改变 109 | 'qiwsir,python' 110 | >>> b = a.upper() 111 | >>> b 112 | 'QIWSIR,PYTHON' 113 | >>> c = b.lower() #将所有的小写字母变成大写字母 114 | >>> c 115 | 'qiwsir,python' 116 | 117 | >>> a 118 | 'qiwsir,python' 119 | >>> a.capitalize() #把字符串的第一个字母变成大写 120 | 'Qiwsir,python' 121 | >>> a #原数据对象没有改变 122 | 'qiwsir,python' 123 | >>> b = a.capitalize() #新建立了一个 124 | >>> b 125 | 'Qiwsir,python' 126 | 127 | >>> a = "qiwsir,github" #这里的问题就是网友白羽毛指出的,非常感谢他。 128 | >>> a.istitle() 129 | False 130 | >>> a = "QIWSIR" #当全是大写的时候,返回False 131 | >>> a.istitle() 132 | False 133 | >>> a = "qIWSIR" 134 | >>> a.istitle() 135 | False 136 | >>> a = "Qiwsir,github" #如果这样,也返回False 137 | >>> a.istitle() 138 | False 139 | >>> a = "Qiwsir" #这样是True 140 | >>> a.istitle() 141 | True 142 | >>> a = 'Qiwsir,Github' #这样也是True 143 | >>> a.istitle() 144 | True 145 | 146 | >>> a = "Qiwsir" 147 | >>> a.isupper() 148 | False 149 | >>> a.upper().isupper() 150 | True 151 | >>> a.islower() 152 | False 153 | >>> a.lower().islower() 154 | True 155 | ``` 156 | 顺着白羽毛网友指出的,再探究一下,可以这么做: 157 | ```python 158 | >>> a = "This is a Book" 159 | >>> a.istitle() 160 | False 161 | >>> b = a.title() #这样就把所有单词的第一个字母转化为大写 162 | >>> b 163 | 'This Is A Book' 164 | >>> a.istitle() #判断每个单词的第一个字母是否为大写 165 | False 166 | ``` 167 | 168 | 字符串问题,看来本讲还不能结束。下一讲继续。有看官可能要问了,上面这些在实战中怎么用?我正想为你的,请键客设计一种实战情景,能不能用上所学。 169 | -------------------------------------------------------------------------------- /100/109.md: -------------------------------------------------------------------------------- 1 | ## 玩转字符串(3) 2 | 3 | 字符串是一个很长的话题,纵然现在开始第三部分,但是也不能完全说尽。因为字符串是自然语言中最复杂的东西,也是承载功能最多的,计算机高级语言编程,要解决自然语言中的问题,让自然语言中完成的事情在计算机上完成,所以,也不得不有更多的话题。 4 | 5 | 字符串就是一个话题中心。 6 | 7 | ### 给字符串编号 8 | 9 | 在很多很多情况下,我们都要对字符串中的每个字符进行操作(具体看后面的内容),要准确进行操作,必须做的一个工作就是把字符进行编号。比如一个班里面有50名学生,如果这些学生都有学号,老师操作他们将简化很多。比如不用专门找每个人名字,直接通过学号知道谁有没有交作业。 10 | 11 | 在python中按照这样的顺序对字符串进行编号:从左边第一个开始是0号,向下依次按照整数增加,为1、2...,直到最后一个,在这个过程中,所有字符,包括空格,都进行变好。例如: 12 | 13 | Hello,wor ld 14 | 15 | 对于这个字符串,从左向右的变好依次是: 16 | 17 | |0|1|2|3|4|5|6|7|8|9|10|11| 18 | 19 | |H|e|l|l|o|,|w|o|r| |l |d | 20 | 21 | 在班级了,老师只要喊出学生的学号,自动有对应的学生站起来。在python里面如何把某个编号所对应的字符调出来呢?看代码: 22 | ```python 23 | >>> a = "Hello,wor ld" 24 | >>> len(a) #字符串的长度是12,说明公有12个字符,最后一个字符编号是11 25 | 12 26 | >>> a[0] 27 | 'H' 28 | >>> a[3] 29 | 'l' 30 | >>> a[9] 31 | ' ' 32 | >>> a[11] 33 | 'd' 34 | >>> a[5] 35 | ',' 36 | ``` 37 | 特别说明,编号是从左边开始,第一个是0。 38 | 39 | 能不能从右边开始编号呢?可以。这么人见人爱的python难道这点小要求都不满足吗? 40 | ```python 41 | >>> a[-1] 42 | 'd' 43 | >>> a[11] 44 | 'd' 45 | >>> a[-12] 46 | 'H' 47 | >>> a[-3] 48 | ' ' 49 | ``` 50 | 看到了吗?如果从右边开始,第一个编号是-1,这样就跟从左边区分开了。也就是a[-1]和a[11]是指向同一个字符。 51 | 52 | 不管从左边开始还是从右边开始,都能准确找到某个字符。看官喜欢从哪边开始就从哪边开始,或者根据实际使用情况,需要从哪边开始就从哪边开始。 53 | 54 | ### 字符串截取 55 | 56 | 有了编号,不仅仅能够找出某个字符,还能在字符串中取出一部分来。比如,从“hello,wor ld”里面取出“llo”。可以这样操作 57 | ```python 58 | >>> a[2:5] 59 | 'llo' 60 | ``` 61 | 这就是截取字符串的一部分,**注意:**所截取部分的第一个字符(l)对应的编号是(2),从这里开始;结束的字符是(o),对应编号是(4),但是结束的编号要增加1,不能是4,而是5.这样截取到的就是上面所要求的了。 62 | 63 | 试一试,怎么截取到",wor" 64 | 65 | 也就是说,截取a[n,m],其中n>> a[:] #表示截取全部 70 | 'Hello,wor ld' 71 | >>> a[3:] #表示从a[3]开始,一直到字符串的最后 72 | 'lo,wor ld' 73 | >>> a[:4] #表示从字符串开头一直到a[4]前结束 74 | 'Hell' 75 | ``` 76 | ### 去掉字符串两头的空格 77 | 78 | 这个功能,在让用户输入一些信息的时候非常有用。有的朋友喜欢输入结束的时候敲击空格,比如让他输入自己的名字,输完了,他来个空格。有的则喜欢先加一个空格,总做的输入的第一个字前面应该空两个格。 79 | 80 | 好吧,这些空格是没用的。python考虑到有不少人可能有这个习惯,因此就帮助程序员把这些空格去掉。 81 | 82 | 方法是: 83 | 84 | - S.strip() 去掉字符串的左右空格 85 | - S.lstrip() 去掉字符串的左边空格 86 | - S.rstrip() 去掉字符串的右边空格 87 | 88 | 看官在看下面示例之前,请先自己用上面的内置函数,是否可以? 89 | ```python 90 | >>> b=" hello " 91 | >>> b 92 | ' hello ' 93 | >>> b.strip() 94 | 'hello' 95 | >>> b 96 | ' hello ' 97 | >>> b.lstrip() 98 | 'hello ' 99 | >>> b.rstrip() 100 | ' hello' 101 | ``` 102 | ## 练习 103 | 104 | 学编程,必须做练习,通过练习熟悉各种情况下的使用。 105 | 106 | 下面共同做一个练习:输入用户名,计算机自动向这个用户打招呼。代码如下: 107 | ```python 108 | #coding:utf-8 109 | 110 | print "please write your name:" 111 | name=raw_input() 112 | print "Hello,%s"%name 113 | ``` 114 | 这段代码中的raw_input()的含义,就是要用户输入内容,所输入的内容是一个字符串。 115 | 116 | 其实,上面这段代码存在这改进的地方,比如,如果用户输入的是小写,是不是要将名字的首字母变成大写呢?如果有空格,是不是要去掉呢?等等。或许还有别的,看看能不能在这个练习中,将以前学习过的东西综合应用一下? 117 | -------------------------------------------------------------------------------- /100/111.md: -------------------------------------------------------------------------------- 1 | ## 从if开始语句的征程 2 | 3 | 一般编程的教材,都是要把所有的变量类型讲完,然后才讲语句。这种讲法,其实不符合学习的特点。学习,就是要循序渐进的。在这点上,我可以很吹一通了,因为我做过教师,研究教育教学,算是有一点心得的。所以,我在这里就开始讲授语句。 4 | 5 | ##什么是语句 6 | 7 | 在前面,我们已经写了一些.py的文件,这些文件可以用python来运行。那些文件,就是由语句组成的程序。 8 | 9 | 为了能够严谨地阐述这个概念,我还是要抄一段[维基百科中的词条:命令式编程](http://zh.wikipedia.org/wiki/%E6%8C%87%E4%BB%A4%E5%BC%8F%E7%B7%A8%E7%A8%8B) 10 | 11 | >命令式编程(英语:Imperative programming),是一种描述电脑所需作出的行为的编程范型。几乎所有电脑的硬件工作都是指令式的;几乎所有电脑的硬件都是设计来运行机器码,使用指令式的风格来写的。较高级的指令式编程语言使用变量和更复杂的语句,但仍依从相同的范型。 12 | 13 | >运算语句一般来说都表现了在存储器内的数据进行运算的行为,然后将结果存入存储器中以便日后使用。高级命令式编程语言更能处理复杂的表达式,可能会产生四则运算和函数计算的结合。 14 | 15 | 一般所有高级语言,都包含如下语句,Python也不例外: 16 | 17 | - 循环语句:容许一些语句反复运行数次。循环可依据一个默认的数目来决定运行这些语句的次数;或反复运行它们,直至某些条件改变。 18 | - 条件语句:容许仅当某些条件成立时才运行某个区块。否则,这个区块中的语句会略去,然后按区块后的语句继续运行。 19 | - 无条件分支语句容许运行顺序转移到程序的其他部分之中。包括跳跃(在很多语言中称为Goto)、副程序和Procedure等。 20 | 21 | 循环、条件分支和无条件分支都是控制流程。 22 | 23 | ##if语句 24 | 25 | 谈到语句,不要被吓住。看下面的例子先: 26 | 27 | if a==4: 28 | print "it is four" 29 | else: 30 | print "it is no four" 31 | 32 | 逐句解释一番,注意看注释。在这里给列为看官提醒,在写程序的是由,一定要写必要的注释,同时在阅读程序的时候,也要注意看注释。 33 | 34 | if a==4: #如果变量a==4是真的,a==4为True,就 35 | print "it is four" #打印“it is four”。 36 | else: #否则,即a==4是假的,a==4为False,就 37 | print "it is not four" #打印“it is not four”。 38 | 39 | 以上几句话,就完成了一个条件判断,在不同条件下做不同的事情。因此,if语句,常被翻译成“条件语句”。 40 | 41 | 条件语句的基本样式结构: 42 | 43 | if 条件1: 44 | 执行的内容1 45 | elif 条件2: 46 | 执行的内容2 47 | elif 条件3: 48 | 执行的内容3 49 | else: 50 | 执行的内容4 51 | 52 | 执行的内容1、内容2,等,称之为语句块。elif用于多个条件时使用,可以没有。另外,也可以只有if,而没有else。 53 | 54 | **提醒:**每个执行的内容,均以缩进四个空格方式。 55 | 56 | 例1:输入一个数字,并输出输入的结果,如果这个数字大于10,那么同时输出大于10,如果小于10,同时输出提示小于10,如果等于10,就输出表扬的一句话。 57 | 58 | 从这里开始,我们的代码就要越来越接近于一个复杂的判断过程了。为了让我们的思维能够更明确上述问题的解决流程,在程序开发过程中,常常要画流程图。什么是流程图,我从另外一个角度讲,就是要让思维过程可视化,简称“思维可视化”。顺便自吹自擂一下,我从2004年就开始在我朝推广思维导图,这就是一种思维可视化工具。自吹到此结束。看这个问题的流程图: 59 | 60 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/11101.png) 61 | 62 | 理解了流程图中的含义,就开始写代码,代码实例如下: 63 | 64 | #! /usr/bin/env python 65 | #coding:utf-8 66 | 67 | print "请输入任意一个整数数字:" 68 | 69 | number = int(raw_input()) #通过raw_input()输入的数字是字符串 70 | #用int()将该字符串转化为整数 71 | 72 | if number == 10: 73 | print "您输入的数字是:%d"%number 74 | print "You are SMART." 75 | elif number > 10: 76 | print "您输入的数字是:%d"%number 77 | print "This number is more than 10." 78 | elif number < 10: 79 | print "您输入的数字是:%d"%number 80 | print "This number is less than 10." 81 | else: 82 | print "Are you a human?" 83 | 84 | 特别提醒看官注意,前面我们已经用过raw_input()函数了,这个是获得用户在界面上输入的信息,而通过它得到的是字符串类型的数据。可以在IDLE中这样检验一下: 85 | 86 | >>> a=raw_input() 87 | 10 88 | >>> a 89 | '10' 90 | >>> type(a) 91 | 92 | >>> a=int(a) 93 | >>> a 94 | 10 95 | >>> type(a) 96 | 97 | 98 | 刚刚得到的那个a就是str类型,如果用int()转换一下,就变成int类型了。 99 | 100 | 看来**int()可以将字str类型的数字转换为int类型**,类似,是不是有这样的结论呢:**str()可以将int类型的数字转化为str类型**.建议看官实验一下。 101 | 102 | 上述程序的后面,就是依据条件进行判断,不同条件下做不同的事情了。需要提醒的是在条件中:number == 10,为了阅读方便,在number和==之间有一个空格最好了,同理,后面也有一个。这里的10,是int类型,number也是int类型. 103 | 104 | 上面的程序不知道是不是搞懂了?如果没有,可以通过QQ跟我联系,我的QQ公布一下:26066913,或者登录我的微博,通过微博跟我联系,当然还可以发邮件啦。我看到您的问题,会答复的。在github上跟我互动,是我最欢迎的。 105 | 106 | 最后,给看官留一个练习题目: 107 | 108 | 课后练习:开发一个猜数字游戏的程序。即程序在某个范围内指定一个数字,比如在0到9范围内指定一个数字,用户猜测程序所指定的数字大小。 109 | 110 | 请看官自己编写。我们会在后面讨论这个问题。 111 | 112 | ##小知识 113 | 114 | 不知道各位是否注意到,上面的那段代码,开始有一行: 115 | 116 | #! /usr/bin/env python 117 | 118 | 这是什么意思呢? 119 | 120 | 这句话以#开头,表示本来不在程序中运行。这句话的用途是告诉机器寻找到该设备上的python解释器,操作系统使用它找到的解释器来运行文件中的程序代码。有的程序里写的是/usr/bin python,表示python解释器在/usr/bin里面。但是,如果写成/usr/bin/env,则表示要通过系统搜索路径寻找python解释器。不同系统,可能解释器的位置不同,所以这种方式能够让代码更将拥有可移植性。对了,以上是对Unix系列操作系统而言。对与windows系统,这句话就当不存在。 121 | -------------------------------------------------------------------------------- /100/112.md: -------------------------------------------------------------------------------- 1 | ## 一个免费的实验室 2 | 3 | 在学生时代,就羡慕实验室,老师在里面可以鼓捣各种有意思的东西。上大学的时候,终于有机会在实验室做大量实验了,因为我是物理系,并且,遇到了一位非常令我尊敬的老师——高老师,让我在他的实验室里面,把所有已经破旧损坏的实验仪器修理装配好,并且按照要求做好实验样例。经过一番折腾,才明白,要做好实验,不仅仅花费精力,还有不菲的设备成本呢。后来工作的时候,更感觉到实验设备费用之高昂,因此做实验的时候总要小心翼翼。 4 | 5 | 再后来,终于发现原来计算机是一个最好的实验室。在这里做实验成本真的很低呀。 6 | 7 | 扯的远了吧。不远,现在就扯回来。学习Python,也要做实验,也就是尝试性地看看某个命令到底什么含义。通过实验,研究清楚了,才能在编程实践中使用。 8 | 9 | 怎么做Python实验呢? 10 | 11 | ## 走进Python实验室 12 | 13 | 在[《集成开发环境(IDE)》](./102.md)一章中,我们介绍了Python的IDE时,给大家推荐了IDLE,进入到IDLE中,看到>>>符号,可以在后面输入一行指令。其实,这就是一个非常好的实验室。 14 | 15 | 另外一个实验室就是UNIX操作系统(包含各种Linux和Mac OSx)的shell,在打开shell之后,输入python,出现如下图所示: 16 | 17 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/11201.png) 18 | 19 | 如果看官是用windows的,也能够通过cmd来获得上图类似的界面,依然是输入python,之后得到界面。 20 | 21 | 在上述任何一个环境中,都可以输入指令,敲回车键运行并输出结果。 22 | 23 | 在这里你可以随心所欲实验。 24 | 25 | ## 交互模式下进行实验 26 | 27 | 前面的各讲中,其实都使用了交互模式。本着循序渐进、循环上升的原则,本讲应该对交互模式进行一番深入和系统化了。 28 | 29 | ### 通过变量直接显示其内容 30 | 31 | 从例子开始: 32 | 33 | >>> a="http://qiwsir.github.io" 34 | >>> a 35 | 'http://qiwsir.github.io' 36 | >>> print a 37 | http://qiwsir.github.io 38 | 39 | 当给一个变量a赋值于一个字符串之后,输入变量名称,就能够打印出字符串,和print a具有同样的效果。这是交互模式下的一个特点,如果在文件模式中,则不能,只有通过print才能打印变量内容。 40 | 41 | ###缩进 42 | 43 | >>> if bool(a): 44 | ... print "I like python" 45 | ... 46 | I like python 47 | 48 | 对于if语句,在上一讲[《从if开始语句的征程》](./111.md)中,已经注意到,if下面的执行语句要缩进四个空格。在有的python教材中,说在交互模式下不需要缩进,可能是针对python3或者其它版本,我使用的是python2.7,的确需要缩进。上面的例子就看出来了。 49 | 50 | 看官在自己的机器上测试一下,是不是需要缩进? 51 | 52 | ###报错 53 | 54 | 在一个广告中看到过这样一句话:程序员的格言,“不求最好,只求报错”。报错,对编程不是坏事。如何对待报错呢? 55 | 56 | **一定要认真阅读所提示的错误信息。** 57 | 58 | 还是上面那个例子,我如果这样写: 59 | 60 | >>> if bool(a): 61 | ... print "I like python" 62 | File "", line 2 63 | print "I like python" 64 | ^ 65 | IndentationError: expected an indented block 66 | 67 | 从错误信息中,我们可以知道,第二行错了。错在什么地方呢?python非常人性化就在这里,告诉你错误在什么地方: 68 | 69 | IndentationError: expected an indented block 70 | 71 | 意思就是说需要一个缩进块。也就是我没有对第二行进行缩进,需要缩进。 72 | 73 | 另外,顺便还要提醒,>>>表示后面可以输入指令,...表示当前指令没有结束。要结束并执行,需要敲击两次回车键。 74 | 75 | ###探索 76 | 77 | 如果看官对某个指令不了解,或者想试试某种操作是否可行,可以在交互模式下进行探索,这种探索的损失成本非常小,充其量就是报错。而且从报错信息中,我们还能得到更多有价值的内容。 78 | 79 | 例如,在[《眼花缭乱的运算符》](./110.md)中,提到了布尔运算,其实,在变量的类型中,除了前面提到的整数型、字符串型,布尔型也是一种,那么布尔型的变量有什么特点呢?下面就探索一下: 80 | ```python 81 | >>> a 82 | 'http://qiwsir.github.io' 83 | >>> bool(a) #布尔型,用bool()表示,就类似int(),str(),是一个内置函数 84 | True 85 | >>> b="" 86 | >>> bool(b) 87 | False 88 | >>> bool(4>3) 89 | True 90 | >>> bool(4<3) 91 | False 92 | >>> m=bool(b) 93 | >>> m 94 | False 95 | >>> type(m) 96 | 97 | >>> 98 | ``` 99 | 从上面的实验可以看出,如果对象是空,返回False,如果不是,则返回True;如果对象是False,返回False。上面探索,还可以扩展到其它情况。看官能不能通过探索,总结出bool()的特点呢? 100 | -------------------------------------------------------------------------------- /100/113.md: -------------------------------------------------------------------------------- 1 | ## 有容乃大的list(1) 2 | 3 | 前面的学习中,我们已经知道了两种python的数据类型:int和str。再强调一下对数据类型的理解,这个世界是由数据组成的,数据可能是数字(注意,别搞混了,数字和数据是有区别的),也可能是文字、或者是声音、视频等。在python中(其它高级语言也类似)把状如2,3这样的数字划分为一个类型,把状如“你好”这样的文字划分一个类型,前者是int类型,后者是str类型(这里就不说翻译的名字了,请看官熟悉用英文的名称,对日后编程大有好处,什么好处呢?谁用谁知道!)。 4 | 5 | 前面还学习了变量,如果某个变量跟一个int类型的数据用线连着(行话是:赋值),那么这个变量我们就把它叫做int类型的变量;有时候还没赋值呢,是准备让这个变量接收int类型的数据,我们也需要将它声明为int类型的变量。不过,在python里面有一样好处,变量不用提前声明,随用随命名。 6 | 7 | 这一讲中的list类型,也是python的一种数据类型。翻译为:列表。下面的黑字,请看官注意了: 8 | 9 | **LIST在python中具有非常强大的功能。** 10 | 11 | ## 定义 12 | 13 | 在python中,用方括号表示一个list,[ ] 14 | 15 | 在方括号里面,可以是int,也可以是str类型的数据,甚至也能够是True/False这种布尔值。看下面的例子,特别注意阅读注释。 16 | ```python 17 | >>> a=[] #定义了一个变量a,它是list类型,并且是空的。 18 | >>> type(a) 19 | #用内置函数type()查看变量a的类型,为list 20 | >>> bool(a) #用内置函数bool()看看list类型的变量a的布尔值,因为是空的,所以为False 21 | False 22 | >>> print a #打印list类型的变量a 23 | [] 24 | ``` 25 | 不能总玩空的,来点实的吧。 26 | ```python 27 | >>> a=['2',3,'qiwsir.github.io'] 28 | >>> a 29 | ['2', 3, 'qiwsir.github.io'] 30 | >>> type(a) 31 | 32 | >>> bool(a) 33 | True 34 | >>> print a 35 | ['2', 3, 'qiwsir.github.io'] 36 | ``` 37 | 用上述方法,定义一个list类型的变量和数据。 38 | 39 | 本讲的标题是“有容乃大的list”,就指明了list的一大特点:可以无限大,就是说list里面所能容纳的元素数量无限,当然这是在硬件设备理想的情况下。 40 | 41 | ## list索引 42 | 43 | 尚记得在[《玩转字符串(3)》](./109.md)中,曾经给字符串进行编号,然后根据编号来获取某个或者某部分字符,这样的过程,就是“索引”(index)。 44 | 45 | >>> url = "qiwsir.github.io" 46 | >>> url[2] 47 | 'w' 48 | >>> url[:4] 49 | 'qiws' 50 | >>> url[3:9] 51 | 'sir.gi' 52 | 53 | 在list中,也有类似的操作。只不过是以元素为单位,不是以字符为单位进行索引了。看例子就明白了。 54 | ```python 55 | >>> a 56 | ['2', 3, 'qiwsir.github.io'] 57 | >>> a[0] #索引序号也是从0开始 58 | '2' 59 | >>> a[1] 60 | 3 61 | >>> [2] 62 | [2] 63 | >>> a[:2] #跟str中的类似,切片的范围是:包含开始位置,到结束位置之前 64 | ['2', 3] #不包含结束位置 65 | >>> a[1:] 66 | [3, 'qiwsir.github.io'] 67 | >>> a[-1] #负数编号从右边开始 68 | 'qiwsir.github.io' 69 | >>> a[-2] 70 | 3 71 | >>> a[:] 72 | ['2', 3, 'qiwsir.github.io'] 73 | ``` 74 | ## 对list的操作 75 | 76 | 任何一个行业都有自己的行话,如同古代的强盗,把撤退称之为“扯乎”一样,纵然是一个含义,但是强盗们愿意用他们自己的行业用语,俗称“黑话”。各行各业都如此。这样做的目的我理解有两个,一个是某种保密;另外一个是行外人士显示本行业的门槛,让别人感觉这个行业很高深,从业者有一定水平。 77 | 78 | 不管怎么,在python和很多高级语言中,都给本来数学角度就是函数的东西,又在不同情况下有不同的称呼,如方法、类等。当然,这种称呼,其实也是为了区分函数的不同功能。 79 | 80 | 前面在对str进行操作的时候,有一些内置函数,比如s.strip(),这是去掉左右空格的内置函数,也是str的方法。按照一贯制的对称法则,对list也会有一些操作方法。 81 | 82 | ### 追加元素 83 | ```python 84 | >>> a = ["good","python","I"] 85 | >>> a 86 | ['good', 'python', 'I'] 87 | >>> a.append("like") #向list中添加str类型"like" 88 | >>> a 89 | ['good', 'python', 'I', 'like'] 90 | >>> a.append(100) #向list中添加int类型100 91 | >>> a 92 | ['good', 'python', 'I', 'like', 100] 93 | ``` 94 | [官方文档](https://docs.python.org/2/tutorial/datastructures.html)这样描述list.append()方法 95 | 96 | > list.append(x) 97 | 98 | > Add an item to the end of the list; equivalent to a[len(a):] = [x]. 99 | 100 | 从以上描述中,以及本部分的标题“追加元素”,是不是能够理解list.append(x)的含义呢?即将新的元素x追加到list的尾部。 101 | 102 | 列位看官,如果您注意看上面官方文档中的那句话,应该注意到,还有后面半句: equivalent to a[len(a):] = [x],意思是说list.append(x)等效于:a[len(a):]=[x]。这也相当于告诉我们了另外一种追加元素的方法,并且两种方法等效。 103 | ```python 104 | >>> a 105 | ['good', 'python', 'I', 'like', 100] 106 | >>> a[len(a):]=[3] #len(a),即得到list的长度,这个长度是指list中的元素个数。 107 | >>> a 108 | ['good', 'python', 'I', 'like', 100, 3] 109 | >>> len(a) 110 | 6 111 | >>> a[6:]=['xxoo'] 112 | >>> a 113 | ['good', 'python', 'I', 'like', 100, 3, 'xxoo'] 114 | ``` 115 | 顺便说一下len(),这个是用来获取list,str等类型的数据长度的。在字符串讲解的时候也提到了。 116 | ```python 117 | >>> name = 'yeashape' 118 | >>> len(name) #str的长度,是字符的个数 119 | 8 120 | >>> a=[1,2,'a','b'] #list的长度,是元素的个数 121 | >>> len(a) 122 | 4 123 | >>> b=['yeashape'] 124 | >>> len(b) 125 | 1 126 | ``` 127 | 下一讲继续list,有容乃大。 128 | -------------------------------------------------------------------------------- /100/114.md: -------------------------------------------------------------------------------- 1 | ## 有容乃大的list(2) 2 | 3 | ## 对list的操作 4 | 5 | ### list的长度 6 | 7 | 还记得str的长度怎么获得吗?其长度是什么含呢?那种方法能不能用在list上面呢?效果如何? 8 | 9 | 做实验: 10 | ```python 11 | >>> name = 'qiwsir' 12 | >>> type(name) 13 | 14 | >>> len(name) 15 | 6 16 | >>> lname = ['sir','qi'] 17 | >>> type(lname) 18 | 19 | >>> len(lname) 20 | 2 21 | >>> length = len(lname) 22 | >>> length 23 | 2 24 | >>> type(length) 25 | 26 | ``` 27 | 实验结论: 28 | 29 | - len(x),对于list一样适用 30 | - 得到的是list中元素个数 31 | - 返回值是int类型 32 | 33 | ###合并list 34 | 35 | [《有容乃大的list(1)》](./113.md)中,对list的操作提到了list.append(x),也就是将某个元素x 追加到已知的一个list后边。 36 | 37 | 除了将元素追加到list中,还能够将两个list合并,或者说将一个list追加到另外一个list中。按照前文的惯例,还是首先看[官方文档](https://docs.python.org/2/tutorial/datastructures.html)中的描述: 38 | 39 | > list.extend(L) 40 | 41 | > Extend the list by appending all the items in the given list; equivalent to a[len(a):] = L. 42 | 43 | **向所有正在学习本内容的朋友提供一个成为优秀程序员的必备:看官方文档,是必须的。** 44 | 45 | 官方文档的这句话翻译过来: 46 | 47 | > 通过将所有元素追加到已知list来扩充它,相当于a[len(a)]= L 48 | 49 | 英语太烂,翻译太差。直接看例子,更明白 50 | ```python 51 | >>> la 52 | [1, 2, 3] 53 | >>> lb 54 | ['qiwsir', 'python'] 55 | >>> la.extend(lb) 56 | >>> la 57 | [1, 2, 3, 'qiwsir', 'python'] 58 | >>> lb 59 | ['qiwsir', 'python'] 60 | ``` 61 | 上面的例子,显示了如何将两个list,一个是la,另外一个lb,将lb追加到la的后面,也就是把lb中的所有元素加入到la中,即让la扩容。 62 | 63 | 学程序一定要有好奇心,我在交互环境中,经常实验一下自己的想法,有时候是比较愚蠢的想法。 64 | ```python 65 | >>> la = [1,2,3] 66 | >>> b = "abc" 67 | >>> la.extend(b) 68 | >>> la 69 | [1, 2, 3, 'a', 'b', 'c'] 70 | >>> c = 5 71 | >>> la.extend(c) 72 | Traceback (most recent call last): 73 | File "", line 1, in 74 | TypeError: 'int' object is not iterable 75 | ``` 76 | 从上面的实验中,看官能够有什么心得?原来,如果extend(str)的时候,str被以字符为单位拆开,然后追加到la里面。 77 | 78 | 如果extend的对象是数值型,则报错。 79 | 80 | 所以,extend的对象是一个list,如果是str,则python会先把它按照字符为单位转化为list再追加到已知list。 81 | 82 | 不过,别忘记了前面官方文档的后半句话,它的意思是: 83 | ```python 84 | >>> la 85 | [1, 2, 3, 'a', 'b', 'c'] 86 | >>> lb 87 | ['qiwsir', 'python'] 88 | >>> la[len(la):]=lb 89 | >>> la 90 | [1, 2, 3, 'a', 'b', 'c', 'qiwsir', 'python'] 91 | ``` 92 | list.extend(L) 等效于 list[len(list):] = L,L是待并入的list 93 | 94 | 联想到到[上一讲](./113.md)中的一个list函数list.append(),这里的extend函数也是将另外的元素(只不过这个元素是列表)增加到一个已知列表中,那么两者有什么不一样呢?看下面例子: 95 | ```python 96 | >>> lst = [1,2,3] 97 | >>> lst.append(["qiwsir","github"]) 98 | >>> lst 99 | [1, 2, 3, ['qiwsir', 'github']] #append的结果 100 | >>> len(lst) 101 | 4 102 | 103 | >>> lst2 = [1,2,3] 104 | >>> lst2.extend(["qiwsir","github"]) 105 | >>> lst2 106 | [1, 2, 3, 'qiwsir', 'github'] #extend的结果 107 | >>> len(lst2) 108 | 5 109 | ``` 110 | append是整建制地追加,extend是个体化扩编。 111 | 112 | ### list中某元素的个数 113 | 114 | 上面的len(L),可得到list的长度,也就是list中有多少个元素。python的list还有一个操作,就是数一数某个元素在该list中出现多少次,也就是某个元素有多少个。官方文档是这么说的: 115 | 116 | > list.count(x) 117 | 118 | > Return the number of times x appears in the list. 119 | 120 | 一定要不断实验,才能理解文档中精炼的表达。 121 | ```python 122 | >>> la = [1,2,1,1,3] 123 | >>> la.count(1) 124 | 3 125 | >>> la.append('a') 126 | >>> la.append('a') 127 | >>> la 128 | [1, 2, 1, 1, 3, 'a', 'a'] 129 | >>> la.count('a') 130 | 2 131 | >>> la.count(2) 132 | 1 133 | >>> la.count(5) #NOTE:la中没有5,但是如果用这种方法找,不报错,返回的是数字0 134 | 0 135 | ``` 136 | ###元素在list中的位置 137 | 138 | [《有容乃大的list(1)》](./113.md)中已经提到,可以将list中的元素,从左向右依次从0开始编号,建立索引(如果从右向左,就从-1开始依次编号),通过索引能够提取出某个元素,或者某几个元素。就是如这样做: 139 | ```python 140 | >>> la 141 | [1, 2, 3, 'a', 'b', 'c', 'qiwsir', 'python'] 142 | >>> la[2] 143 | 3 144 | >>> la[2:5] 145 | [3, 'a', 'b'] 146 | >>> la[:7] 147 | [1, 2, 3, 'a', 'b', 'c', 'qiwsir'] 148 | ``` 149 | 如果考虑反过来的情况,能不能通过某个元素,找到它在list中的编号呢? 150 | 151 | 看官的需要就是python的方向,你想到,python就做到。 152 | ```python 153 | >>> la 154 | [1, 2, 3, 'a', 'b', 'c', 'qiwsir', 'python'] 155 | >>> la.index(3) 156 | 2 157 | >>> la.index('a') 158 | 3 159 | >>> la.index(1) 160 | 0 161 | >>> la.index('qi') #如果不存在,就报错 162 | Traceback (most recent call last): 163 | File "", line 1, in 164 | ValueError: 'qi' is not in list 165 | >>> la.index('qiwsir') 166 | 6 167 | ``` 168 | list.index(x),x是list中的一个元素,这样就能够检索到该元素在list中的位置了。这才是真正的索引,注意那个英文单词index。 169 | 170 | 依然是上一条官方解释: 171 | 172 | > list.index(x) 173 | 174 | > Return the index in the list of the first item whose value is x. It is an error if there is no such item. 175 | 176 | 是不是说的非常清楚明白了? 177 | 178 | 先到这里,下讲还继续有容乃大的list. 179 | -------------------------------------------------------------------------------- /100/115.md: -------------------------------------------------------------------------------- 1 | ## 有容乃大的list(3) 2 | 3 | 现在是讲lis的第三章了。俗话说,事不过三,不知道在开头,我也不知道这一讲是不是能够把基础的list知识讲完呢。哈哈。其实如果真正写文章,会在写完之后把这句话删掉的。而我则是完全像跟看官聊天一样,就不删除了。 4 | 5 | 继续。 6 | 7 | ##对list的操作 8 | 9 | ###向list中插入一个元素 10 | 11 | 前面有一个向list中追加元素的方法,那个追加是且只能是将新元素添加在list的最后一个。如: 12 | ```python 13 | >>> all_users = ["qiwsir","github"] 14 | >>> all_users.append("io") 15 | >>> all_users 16 | ['qiwsir', 'github', 'io'] 17 | ``` 18 | 从这个操作,就可以说明list是可以随时改变的。这种改变的含义只它的大小即所容纳元素的个数以及元素内容,可以随时直接修改,而不用进行转换。这和str有着很大的不同。对于str,就不能进行字符的追加。请看官要注意比较,这也是str和list的重要区别。 19 | 20 | 与list.append(x)类似,list.insert(i,x)也是对list元素的增加。只不过是可以在任何位置增加一个元素。 21 | 22 | 我特别引导列为看官要通过[官方文档来理解](https://docs.python.org/2/tutorial/datastructures.html): 23 | 24 | > list.insert(i, x) 25 | 26 | > Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x). 27 | 28 | 这次就不翻译了。如果看不懂英语,怎么了解贵国呢?一定要硬着头皮看英语,不仅能够学好程序,更能...(此处省略两千字) 29 | 30 | 根据官方文档的说明,我们做下面的实验,请看官从实验中理解: 31 | ```python 32 | >>> all_users 33 | ['qiwsir', 'github', 'io'] 34 | >>> all_users.insert("python") #list.insert(i,x),要求有两个参数,少了就报错 35 | Traceback (most recent call last): 36 | File "", line 1, in 37 | TypeError: insert() takes exactly 2 arguments (1 given) 38 | 39 | >>> all_users.insert(0,"python") 40 | >>> all_users 41 | ['python', 'qiwsir', 'github', 'io'] 42 | 43 | >>> all_users.insert(1,"http://") 44 | >>> all_users 45 | ['python', 'http://', 'qiwsir', 'github', 'io'] 46 | 47 | >>> length = len(all_users) 48 | >>> length 49 | 5 50 | 51 | >>> all_users.insert(length,"algorithm") 52 | >>> all_users 53 | ['python', 'http://', 'qiwsir', 'github', 'io', 'algorithm'] 54 | ``` 55 | 小结: 56 | 57 | - list.insert(i,x),将新的元素x 插入到原list中的list[i]前面 58 | - 如果i==len(list),意思是在后面追加,就等同于list.append(x) 59 | 60 | ###删除list中的元素 61 | 62 | list中的元素,不仅能增加,还能被删除。删除list元素的方法有两个,它们分别是: 63 | 64 | list.remove(x) 65 | 66 | >Remove the first item from the list whose value is x. It is an error if there is no such item. 67 | 68 | list.pop([i]) 69 | 70 | > Remove the item at the given position in the list, and return it. If no index is specified, a.pop() removes and returns the last item in the list. (The square brackets around the i in the method signature denote that the parameter is optional, not that you should type square brackets at that position. You will see this notation frequently in the Python Library Reference.) 71 | 72 | 我这里讲授python,有一个习惯,就是用学习物理的方法。如果看官当初物理没有学好,那么一定是没有用这种方法,或者你的老师没有用这种教学法。这种方法就是:自己先实验,然后总结规律。 73 | 74 | 先实验list.remove(x),注意看上面的描述。这是一个能够删除list元素的方法,同时上面说明告诉我们,如果x没有在list中,会报错。 75 | ```python 76 | >>> all_users 77 | ['python', 'http://', 'qiwsir', 'github', 'io', 'algorithm'] 78 | >>> all_users.remove("http://") 79 | >>> all_users #的确是把"http://"删除了 80 | ['python', 'qiwsir', 'github', 'io', 'algorithm'] 81 | 82 | >>> all_users.remove("tianchao") #原list中没有“tianchao”,要删除,就报错。 83 | Traceback (most recent call last): 84 | File "", line 1, in 85 | ValueError: list.remove(x): x not in list 86 | ``` 87 | 注意两点: 88 | 89 | - 如果正确删除,不会有任何反馈。没有消息就是好消息。 90 | - 如果所删除的内容不在list中,就报错。注意阅读报错信息:x not in list 91 | 92 | 看官是不是想到一个问题?如果能够在删除之前,先判断一下这个元素是不是在list中,在就删,不在就不删,不是更智能吗? 93 | 94 | 如果看官想到这里,就是在编程的旅程上一进步。python的确让我们这么做。 95 | ```python 96 | >>> all_users 97 | ['python', 'qiwsir', 'github', 'io', 'algorithm'] 98 | >>> "python" in all_users #这里用in来判断一个元素是否在list中,在则返回True,否则返回False 99 | True 100 | 101 | >>> if "python" in all_users: 102 | ... all_users.remove("python") 103 | ... print all_users 104 | ... else: 105 | ... print "'python' is not in all_users" 106 | ... 107 | ['qiwsir', 'github', 'io', 'algorithm'] #删除了"python"元素 108 | 109 | >>> if "python" in all_users: 110 | ... all_users.remove("python") 111 | ... print all_users 112 | ... else: 113 | ... print "'python' is not in all_users" 114 | ... 115 | 'python' is not in all_users #因为已经删除了,所以就没有了。 116 | ``` 117 | 上述代码,就是两段小程序,我是在交互模式中运行的,相当于小实验。 118 | 119 | 另外一个删除list.pop([i])会怎么样呢?看看文档,做做实验。 120 | ```python 121 | >>> all_users 122 | ['qiwsir', 'github', 'io', 'algorithm'] 123 | >>> all_users.pop() #list.pop([i]),圆括号里面是[i],表示这个序号是可选的 124 | 'algorithm' #如果不写,就如同这个操作,默认删除最后一个,并且将该结果返回 125 | 126 | >>> all_users 127 | ['qiwsir', 'github', 'io'] 128 | 129 | >>> all_users.pop(1) #指定删除编号为1的元素"github" 130 | 'github' 131 | 132 | >>> all_users 133 | ['qiwsir', 'io'] 134 | >>> all_users.pop() 135 | 'io' 136 | 137 | >>> all_users #只有一个元素了,该元素编号是0 138 | ['qiwsir'] 139 | >>> all_users.pop(1) #但是非要删除编号为1的元素,结果报错。注意看报错信息 140 | Traceback (most recent call last): 141 | File "", line 1, in 142 | IndexError: pop index out of range #删除索引超出范围,就是1不在list的编号范围之内 143 | ``` 144 | 给看官留下一个思考题,如果要向前面那样,能不能事先判断一下要删除的编号是不是在list的长度范围(用len(list)获取长度)以内?然后进行删除或者不删除操作。 145 | 146 | list是一个有意思的东西,内涵丰富。看来下一讲还要继续讲list。并且可能会做一个有意思的游戏。请期待。 147 | -------------------------------------------------------------------------------- /100/116.md: -------------------------------------------------------------------------------- 1 | ## 有容乃大的list(4) 2 | 3 | list的话题的确不少,而且,在编程中,用途也非常多。 4 | 5 | 有看官可能要问了,如果要生成一个list,除了要把元素一个一个写上之外,有没有能够让计算机自己按照某个规律生成list的方法呢? 6 | 7 | 如果你提出了这个问题,充分说明你是一个“懒人”,不过这不是什么坏事情,这个世界就是因为“懒人”的存在而进步。“懒人”其实不懒。 8 | 9 | ## 对list的操作 10 | 11 | ###range(start,stop)生成数字list 12 | 13 | range(start, stop[, step])是一个内置函数。 14 | 15 | 要研究清楚一些函数特别是内置函数的功能,建议看官首先要明白内置函数名称的含义。因为在python中,名称不是随便取的,是代表一定意义的。关于取名字问题,可以看参考本系列的:[永远强大的函数](./106.md)中的《取名字的学问》部分内容。 16 | 17 | >range 18 | 19 | >n. 范围;幅度;排;山脉 20 | >vi. (在...内)变动;平行,列为一行;延伸;漫游;射程达到 21 | >vt. 漫游;放牧;使并列;归类于;来回走动 22 | 23 | 在具体实验之前,还是按照管理,摘抄一段[官方文档的原话](https://docs.python.org/2/library/functions.html#range),让我们能够深刻理解之: 24 | 25 | >This is a versatile function to create lists containing arithmetic progressions. It is most often used in for loops. The arguments must be plain integers. If the step argument is omitted, it defaults to 1. If the start argument is omitted, it defaults to 0. The full form returns a list of plain integers [start, start + step, start + 2 * step, ...]. If step is positive, the last element is the largest start + i * step less than stop; if step is negative, the last element is the smallest start + i * step greater than stop. step must not be zero (or else ValueError is raised). 26 | 27 | 从这段话,我们可以得出关于range()函数的以下几点: 28 | 29 | - 这个函数可以创建一个数字元素组成的列表。 30 | - 这个函数最常用于for循环(关于for循环,马上就要涉及到了) 31 | - 函数的参数必须是整数,默认从0开始。返回值是类似[start, start + step, start + 2*step, ...]的列表。 32 | - step默认值是1。如果不写,就是按照此值。 33 | - 如果step是正数,返回list的最最后的值不包含stop值,即start+i*step这个值小于stop;如果step是负数,start+i*step的值大于stop。 34 | - step不能等于零,如果等于零,就报错。 35 | 36 | 在实验开始之前,再解释range(start,stop[,step])的含义: 37 | 38 | - start:开始数值,默认为0,也就是如果不写这项,就是认为start=0 39 | - stop:结束的数值,必须要写的。 40 | - step:变化的步长,默认是1,也就是不写,就是认为步长为1。坚决不能为0 41 | 42 | 实验开始,请以各项对照前面的讲述: 43 | ```python 44 | >>> range(9) #stop=9,别的都没有写,含义就是range(0,9,1) 45 | [0, 1, 2, 3, 4, 5, 6, 7, 8] #从0开始,步长为1,增加,直到小于9的那个数 46 | >>> range(0,9) 47 | [0, 1, 2, 3, 4, 5, 6, 7, 8] 48 | >>> range(0,9,1) 49 | [0, 1, 2, 3, 4, 5, 6, 7, 8] 50 | 51 | >>> range(1,9) #start=1 52 | [1, 2, 3, 4, 5, 6, 7, 8] 53 | 54 | >>> range(0,9,2) #step=2,每个元素等于start+i*step, 55 | [0, 2, 4, 6, 8] 56 | ``` 57 | 仅仅解释一下range(0,9,2) 58 | 59 | - 如果是从0开始,步长为1,可以写成range(9)的样子,但是,如果步长为2,写成range(9,2)的样子,计算机就有点糊涂了,它会认为start=9,stop=2。所以,在步长不为1的时候,切忌,要把start的值也写上。 60 | - start=0,step=2,stop=9.list中的第一个值是start=0,第二个值是start+1*step=2(注意,这里是1,不是2,不要忘记,前面已经讲过,不论是list还是str,对元素进行编号的时候,都是从0开始的),第n个值就是start+(n-1)*step。直到小于stop前的那个值。 61 | 62 | 熟悉了上面的计算过程,看看下面的输入谁是什么结果? 63 | 64 | >>> range(-9) 65 | 66 | 我本来期望给我返回[0,-1,-2,-3,-4,-5,-6,-7,-8],我的期望能实现吗? 67 | 68 | 分析一下,这里start=0,step=1,stop=-9. 69 | 70 | 第一个值是0;第二个是start+1*step,将上面的数代入,应该是1,但是最后一个还是-9,显然出现问题了。但是,python在这里不报错,它返回的结果是: 71 | ```python 72 | >>> range(-9) 73 | [] 74 | >>> range(0,-9) 75 | [] 76 | >>> range(0) 77 | [] 78 | ``` 79 | 报错和返回结果,是两个含义,虽然返回的不是我们要的。应该如何修改呢? 80 | ```python 81 | >>> range(0,-9,-1) 82 | [0, -1, -2, -3, -4, -5, -6, -7, -8] 83 | >>> range(0,-9,-2) 84 | [0, -2, -4, -6, -8] 85 | ``` 86 | 有了这个内置函数,很多事情就简单了。比如: 87 | ```python 88 | >>> range(0,100,2) 89 | [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98] 90 | ``` 91 | 100以内的自然数中的偶数组成的list,就非常简单地搞定了。 92 | 93 | 思考一个问题,现在有一个列表,比如是["I","am","a","pythoner","I","am","learning","it","with","qiwsir"],要得到这个list的所有序号组成的list,但是不能一个一个用手指头来数。怎么办? 94 | 95 | 请沉思两分钟之后,自己实验一下,然后看下面。 96 | ```python 97 | >>> pythoner 98 | ['I', 'am', 'a', 'pythoner', 'I', 'am', 'learning', 'it', 'with', 'qiwsir'] 99 | >>> py_index = range(len(pythoner)) #以len(pythoner)为stop的值 100 | >>> py_index 101 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 102 | ``` 103 | 再用手指头指着pythoner里面的元素,数一数,是不是跟结果一样。 104 | 105 | ###排排坐,分果果 106 | 107 | 排序,不管在现实还是在网络上都是随处可见的。梁山好汉要从第一个排序到第108个,这是一个不很容易搞定的活。 108 | 109 | 前面提到的内置函数range()得到的结果,就是一个排好序的。对于一个没有排好序的list,怎么排序呢? 110 | 111 | 有两个方法可以实现对list的排序: 112 | 113 | - list.sort(cmp=None, key=None, reverse=False) 114 | - sorted(iterable[, cmp[, key[, reverse]]]) 115 | 116 | 通过下面的实验,可以理解如何排序的方法 117 | ```python 118 | >>> number = [1,4,6,2,9,7,3] 119 | >>> number.sort() 120 | >>> number 121 | [1, 2, 3, 4, 6, 7, 9] 122 | 123 | >>> number = [1,4,6,2,9,7,3] 124 | >>> number 125 | [1, 4, 6, 2, 9, 7, 3] 126 | >>> sorted(number) 127 | [1, 2, 3, 4, 6, 7, 9] 128 | 129 | >>> number = [1,4,6,2,9,7,3] 130 | >>> number 131 | [1, 4, 6, 2, 9, 7, 3] 132 | >>> number.sort(reverse=True) #开始实现倒序 133 | >>> number 134 | [9, 7, 6, 4, 3, 2, 1] 135 | 136 | >>> number = [1,4,6,2,9,7,3] 137 | >>> number 138 | [1, 4, 6, 2, 9, 7, 3] 139 | >>> sorted(number,reverse=True) 140 | [9, 7, 6, 4, 3, 2, 1] 141 | ``` 142 | 其实,在高级语言中,排序是一个比较热门对的话题,如果有兴趣的读者,可以到我写的[有关算法](https://github.com/qiwsir/algorithm/blob/master/README.md)中查看有关排序的话题。 143 | 144 | 至此,有关list的基本操作的内置函数,就差不多了。不过最后,还要告诉看官们一个学习方法。因为python的内置函数往往不少,有时候光凭教程,很难学到全部,那么,最关键地是要自己会查找都有哪些函数可以用。怎么查找呢? 145 | 146 | ##一个非常重要的方法 147 | 148 | 假设有一个list,如何知道它所拥有的内置函数呢?请用help(),帮助我吧。 149 | 150 | >>> help(list) 151 | 152 | 就能够看到所有的关于list的函数,以及该函数的使用方法。 153 | -------------------------------------------------------------------------------- /100/118.md: -------------------------------------------------------------------------------- 1 | ## 画圈还不简单吗? 2 | 3 | 画圈?换一个说法就是循环。循环,是高级语言编程中重要的工作。现实生活中,很多事情都是在循环,日月更迭,斗转星移,无不是循环;王朝更迭,寻常百姓,也都是循环。 4 | 5 | 在python中,循环有一个语句:for语句。 6 | 7 | ## 简单的for循环例子 8 | ```python 9 | >>> hello = "world" 10 | >>> for i in hello: 11 | ... print i 12 | ... 13 | w 14 | o 15 | r 16 | l 17 | d 18 | ``` 19 | 上面这个for循环是怎么工作的呢? 20 | 21 | 1. hello这个变量引用的是"world"这个str类型的数据 22 | 2. 变量 i 通过hello找到它所引用的"world",然后从第一字符开始,依次获得该字符的引用。 23 | 3. 当 i="w"的时候,执行print i,打印出了字母w,结束之后循环第二次,让 i="e",然后执行print i,打印出字母e,如此循环下去,一直到最后一个字符被打印出来,循环自动结束 24 | 25 | 顺便补充一个print的技巧,上面的打印结果是竖着排列,也就是每打印一个之后,就自动换行。如果要让打印的在一行,可以用下面的方法,在打印的后面加一个逗号(英文) 26 | 27 | >>> for i in hello: 28 | ... print i, 29 | ... 30 | w o r l d 31 | 32 | >>> for i in hello: 33 | ... print i+",", #为了美观,可以在每个字符后面加一个逗号分割 34 | ... 35 | w, o, r, l, d, 36 | >>> 37 | 38 | 因为可以通过使用索引编号(偏移量)做为下表,得到某个字符。所以,还可以通过下面的循环方式实现上面代码中同样功能: 39 | 40 | >>> for i in range(len(hello)): 41 | ... print hello[i] 42 | ... 43 | w 44 | o 45 | r 46 | l 47 | d 48 | 49 | 其工作方式是: 50 | 51 | 1. len(hello)得到hello引用的字符串的长度,为5 52 | 2. range(len(hello),就是range(5),也就是[0, 1, 2, 3, 4],对应这"world"每个字母的编号,即偏移量。 53 | 3. for i in range(len(hello)),就相当于for i in [0,1,2,3,4],让i依次等于list中的各个值。当i=0时,打印hello[0],也就是第一个字符。然后顺序循环下去,直到最后一个i=4为止。 54 | 55 | 以上的循环举例中,显示了对字str的字符依次获取,也涉及了list,感觉不过瘾呀。那好,看下面对list的循环: 56 | 57 | >>> ls_line 58 | ['Hello', 'I am qiwsir', 'Welcome you', ''] 59 | >>> for word in ls_line: 60 | ... print word 61 | ... 62 | Hello 63 | I am qiwsir 64 | Welcome you 65 | 66 | >>> for i in range(len(ls_line)): 67 | ... print ls_line[i] 68 | ... 69 | Hello 70 | I am qiwsir 71 | Welcome you 72 | 73 | ##上一个台阶 74 | 75 | 我们已经理解了for语句的基本工作流程,如果写一个一般化的公式,可以这么表示: 76 | 77 | for 循环规则: 78 | 操作语句 79 | 80 | 用for语句来解决一个实际问题。 81 | 82 | **例:**找出100以内的能够被3整除的正整数。 83 | 84 | **分析:**这个问题有两个限制条件,第一是100以内的正整数,根据前面所学,可以用range(1,100)来实现;第二个是要解决被3整除的问题,假设某个正整数n,这个数如果能够被3整除,也就是n%3(%是取余数)为0.那么如何得到n呢,就是要用for循环。 85 | 86 | 以上做了简单分析,要实现流程,还需要细化一下。按照前面曾经讲授过的一种方法,要画出问题解决的流程图。 87 | 88 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/11801.png) 89 | 90 | 下面写代码就是按图索骥了。 91 | 92 | 代码: 93 | 94 | 95 | #! /usr/bin/env python 96 | #coding:utf-8 97 | 98 | aliquot = [] 99 | 100 | for n in range(1,100): 101 | if n%3 == 0: 102 | aliquot.append(n) 103 | 104 | print aliquot 105 | 106 | 代码运行结果: 107 | 108 | [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99] 109 | 110 | 这里仅仅列举一个简单的例子,看官可以在这个例子基础上深入:打印某范围内的偶数/奇数等。 111 | 112 | 如果要对list的循环进行深入了解的,可以到我专门撰写的[python and algorithm](https://github.com/qiwsir/algorithm/blob/master/README.md)里面阅读有关文章 113 | -------------------------------------------------------------------------------- /100/119.md: -------------------------------------------------------------------------------- 1 | ## 再深点,更懂list 2 | 3 | 对于list,由于她的确非常非常庞杂,在python中应用非常广泛,所以,虽然已经介绍完毕了基础内容,这里还要用一讲深入一点点,往往越深入越... 4 | 5 | ## list解析 6 | 7 | 先看下面的例子,这个例子是想得到1到9的每个整数的平方,并且将结果放在list中打印出来 8 | ```python 9 | >>> power2 = [] 10 | >>> for i in range(1,10): 11 | ... power2.append(i*i) 12 | ... 13 | >>> power2 14 | [1, 4, 9, 16, 25, 36, 49, 64, 81] 15 | ``` 16 | python有一个非常有意思的功能,就是list解析,就是这样的: 17 | ```python 18 | >>> squares = [x**2 for x in range(1,10)] 19 | >>> squares 20 | [1, 4, 9, 16, 25, 36, 49, 64, 81] 21 | ``` 22 | 看到这个结果,看官还不惊叹吗?这就是python,追求简洁优雅的python! 23 | 24 | 其官方文档中有这样一段描述,道出了list解析的真谛: 25 | 26 | >List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition. 27 | 28 | 还记得[前面一讲](./118.md)中的那个问题吗? 29 | 30 | >找出100以内的能够被3整除的正整数。 31 | 32 | 我们用的方法是: 33 | 34 | aliquot = [] 35 | 36 | for n in range(1,100): 37 | if n%3 == 0: 38 | aliquot.append(n) 39 | 40 | print aliquot 41 | 42 | 好了。现在用list解析重写,会是这样的: 43 | 44 | >>> aliquot = [n for n in range(1,100) if n%3==0] 45 | >>> aliquot 46 | [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99] 47 | 48 | 震撼了。绝对牛X! 49 | 50 | 再来一个,是网友[ccbikai](https://github.com/ccbikai)提供的,比牛X还牛X。 51 | 52 | >>> print range(3,100,3) 53 | [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99] 54 | 55 | 这就是python有意思的地方,也是计算机高级语言编程有意思的地方,你只要动脑筋,总能找到惊喜的东西。 56 | 57 | 其实,不仅仅对数字组成的list,所有的都可以如此操作。请在平复了激动的心之后,默默地看下面的代码,感悟一下list解析的魅力。 58 | 59 | >>> mybag = [' glass',' apple','green leaf '] #有的前面有空格,有的后面有空格 60 | >>> [one.strip() for one in mybag] #去掉元素前后的空格 61 | ['glass', 'apple', 'green leaf'] 62 | 63 | ##enumerate 64 | 65 | 这是一个有意思的内置函数,本来我们可以通过for i in range(len(list))的方式得到一个list的每个元素编号,然后在用list[i]的方式得到该元素。如果要同时得到元素编号和元素怎么办?就是这样了: 66 | 67 | >>> for i in range(len(week)): 68 | ... print week[i]+' is '+str(i) #注意,i是int类型,如果和前面的用+连接,必须是str类型 69 | ... 70 | monday is 0 71 | sunday is 1 72 | friday is 2 73 | 74 | python中提供了一个内置函数enumerate,能够实现类似的功能 75 | 76 | >>> for (i,day) in enumerate(week): 77 | ... print day+' is '+str(i) 78 | ... 79 | monday is 0 80 | sunday is 1 81 | friday is 2 82 | 83 | 算是一个有意思的内置函数了,主要是提供一个简单快捷的方法。 84 | 85 | 官方文档是这么说的: 86 | 87 | >Return an enumerate object. sequence must be a sequence, an iterator, or some other object which supports iteration. The next() method of the iterator returned by enumerate() returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over sequence: 88 | 89 | 顺便抄录几个例子,供看官欣赏,最好实验一下。 90 | 91 | >>> seasons = ['Spring', 'Summer', 'Fall', 'Winter'] 92 | >>> list(enumerate(seasons)) 93 | [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')] 94 | >>> list(enumerate(seasons, start=1)) 95 | [(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')] 96 | 97 | 在这里有类似(0,'Spring')这样的东西,这是另外一种数据类型,待后面详解。 98 | 99 | 下面将enumerate函数和list解析联合起来,同时显示,在进行list解析的时候,也可以包含进函数(关于函数,可以参考的章节有:[初始强大的函数](./106.md),[重回函数](./212.md))。 100 | 101 | >>> def treatment(pos, element): 102 | ... return "%d: %s"%(pos,element) 103 | ... 104 | >>> seq = ["qiwsir","qiwsir.github.io","python"] 105 | >>> [ treatment(i, ele) for i,ele in enumerate(seq) ] 106 | ['0: qiwsir', '1: qiwsir.github.io', '2: python'] 107 | 108 | 看官也可以用[小话题大函数](./209.md)中的lambda函数来写上面的代码: 109 | 110 | >>> seq = ["qiwsir","qiwsir.github.io","python"] 111 | >>> foo = lambda i,ele:"%d:%s"%(i,ele) #lambda函数,给代码带来了简介 112 | >>> [foo(i,ele) for i,ele in enumerate(seq)] 113 | ['0:qiwsir', '1:qiwsir.github.io', '2:python'] 114 | -------------------------------------------------------------------------------- /100/121.md: -------------------------------------------------------------------------------- 1 | ## dict()的操作方法 2 | 3 | dict的很多方法跟list有类似的地方,下面一一道来,并且会跟list做一个对比 4 | 5 | ## 嵌套 6 | 7 | 嵌套在list中也存在,就是元素是list,在dict中,也有类似的样式: 8 | ```python 9 | >>> a_list = [[1,2,3],[4,5],[6,7]] 10 | >>> a_list[1][1] 11 | 5 12 | >>> a_dict = {1:{"name":"qiwsir"},2:"python","email":"qiwsir@gmail.com"} 13 | >>> a_dict 14 | {1: {'name': 'qiwsir'}, 2: 'python', 'email': 'qiwsir@gmail.com'} 15 | >>> a_dict[1]['name'] #一个嵌套的dict访问其值的方法:一层一层地写出键 16 | 'qiwsir' 17 | ``` 18 | ## 获取键、值 19 | 20 | 在[上一讲](./120.md)中,已经知道可以通过dict的键得到其值。例上面的例子。 21 | 22 | 还有别的方法得到键值吗?有!python一般不是只有一个方法实现某个操作的。 23 | 24 | >>> website = {1:"google","second":"baidu",3:"facebook","twitter":4} 25 | 26 | >>>#用d.keys()的方法得到dict的所有键,结果是list 27 | >>> website.keys() 28 | [1, 'second', 3, 'twitter'] 29 | 30 | >>>#用d.values()的方法得到dict的所有值,如果里面没有嵌套别的dict,结果是list 31 | >>> website.values() 32 | ['google', 'baidu', 'facebook', 4] 33 | 34 | >>>#用items()的方法得到了一组一组的键值对, 35 | >>>#结果是list,只不过list里面的元素是元组 36 | >>> website.items() 37 | [(1, 'google'), ('second', 'baidu'), (3, 'facebook'), ('twitter', 4)] 38 | 39 | 从上面的结果中,我们就可以看出,还可以用for语句循环得到相应内容。例如: 40 | 41 | >>> for key in website.keys(): 42 | ... print key,type(key) 43 | ... 44 | 1 45 | second 46 | 3 47 | twitter 48 | 49 | >>>#下面的方法和上面的方法是一样的 50 | >>> for key in website: 51 | ... print key,type(key) 52 | ... 53 | 1 54 | second 55 | 3 56 | twitter 57 | 58 | 以下两种方法等效: 59 | 60 | >>> for value in website.values(): 61 | ... print value 62 | ... 63 | google 64 | baidu 65 | facebook 66 | 4 67 | 68 | >>> for key in website: 69 | ... print website[key] 70 | ... 71 | google 72 | baidu 73 | facebook 74 | 4 75 | 76 | 下面的方法又是等效的: 77 | 78 | >>> for k,v in website.items(): 79 | ... print str(k)+":"+str(v) 80 | ... 81 | 1:google 82 | second:baidu 83 | 3:facebook 84 | twitter:4 85 | 86 | >>> for k in website: 87 | ... print str(k)+":"+str(website[k]) 88 | ... 89 | 1:google 90 | second:baidu 91 | 3:facebook 92 | twitter:4 93 | 94 | 下面的方法也能得到键值,不过似乎要多敲键盘 95 | 96 | >>> website 97 | {1: 'google', 'second': 'baidu', 3: 'facebook', 'twitter': 4} 98 | >>> website.get(1) 99 | 'google' 100 | >>> website.get("second") 101 | 'baidu' 102 | 103 | ##其它几种常用方法 104 | 105 | dict中的方法在这里不做过多的介绍,因为前面一节中已经列出来类,看官如果有兴趣可以一一尝试。下面列出几种常用的 106 | 107 | >>> len(website) 108 | 4 109 | >>> website 110 | {1: 'google', 'second': 'baidu', 3: 'facebook', 'twitter': 4} 111 | 112 | >>> new_web = website.copy() #拷贝一份,这个拷贝也叫做浅拷贝,对应着还有深拷贝。 113 | >>> new_web  #两者区别,可以google一下。 114 | {1: 'google', 'second': 'baidu', 3: 'facebook', 'twitter': 4} 115 | 116 | 删除键值对的方法有两个,但是两者有一点区别 117 | 118 | >>>#d.pop(key),根据key删除相应的键值对,并返回该值 119 | >>> new_web.pop('second') 120 | 'baidu' 121 | 122 | >>> del new_web[3]  #没有返回值,如果删除键不存在,返回错误 123 | >>> new_web 124 | {1: 'google', 'twitter': 4} 125 | >>> del new_web[9] 126 | Traceback (most recent call last): 127 | File "", line 1, in 128 | KeyError: 9 129 | 130 | 用d.update(d2)可以把d2合并到d中。 131 | 132 | >>> cnweb 133 | {'qq': 'first in cn', 'python': 'qiwsir.github.io', 'alibaba': 'Business'} 134 | >>> website 135 | {1: 'google', 'second': 'baidu', 3: 'facebook', 'twitter': 4} 136 | 137 | >>> website.update(cnweb) #把cnweb合并到website内 138 | >>> website  #变化了 139 | {'qq': 'first in cn', 1: 'google', 'second': 'baidu', 3: 'facebook', 'python': 'qiwsir.github.io', 'twitter': 4, 'alibaba': 'Business'} 140 | >>> cnweb  #not changed 141 | {'qq': 'first in cn', 'python': 'qiwsir.github.io', 'alibaba': 'Business'} 142 | 143 | 在本讲最后,要提醒看官,在python3中,dict有不少变化,比如能够进行字典解析,就类似列表解析那样,这可是非常有意思的东西哦。 144 | -------------------------------------------------------------------------------- /100/122.md: -------------------------------------------------------------------------------- 1 | ## 有点简约的元组 2 | 3 | 关于元组,上一讲中涉及到了这个名词。本讲完整地讲述它。 4 | 5 | 先看一个例子: 6 | ```python 7 | >>>#变量引用str 8 | >>> s = "abc" 9 | >>> s 10 | 'abc' 11 | 12 | >>>#如果这样写,就会是... 13 | >>> t = 123,'abc',["come","here"] 14 | >>> t 15 | (123, 'abc', ['come', 'here']) 16 | ``` 17 | 上面例子中看到的变量t,并没有报错,也没有“最后一个有效”,而是将对象做为一个新的数据类型:tuple(元组),赋值给了变量t。 18 | 19 | **元组是用圆括号括起来的,其中的元素之间用逗号隔开。(都是英文半角)** 20 | 21 | tuple是一种序列类型的数据,这点上跟list/str类似。它的特点就是其中的元素不能更改,这点上跟list不同,倒是跟str类似;它的元素又可以是任何类型的数据,这点上跟list相同,但不同于str。 22 | 23 | >>> t = 1,"23",[123,"abc"],("python","learn") #元素多样性,近list 24 | >>> t 25 | (1, '23', [123, 'abc'], ('python', 'learn')) 26 | 27 | >>> t[0] = 8  #不能原地修改,近str 28 | Traceback (most recent call last): 29 | File "", line 1, in 30 | TypeError: 'tuple' object does not support item assignment 31 | 32 | >>> t.append("no") 33 | Traceback (most recent call last): 34 | File "", line 1, in 35 | AttributeError: 'tuple' object has no attribute 'append' 36 | >>> 37 | 38 | 从上面的简单比较似乎可以认为,tuple就是一个融合了部分list和部分str属性的杂交产物。此言有理。 39 | 40 | ##像list那样访问元素和切片 41 | 42 | 先复习list中的一点知识: 43 | 44 | >>> one_list = ["python","qiwsir","github","io"] 45 | >>> one_list[2] 46 | 'github' 47 | >>> one_list[1:] 48 | ['qiwsir', 'github', 'io'] 49 | >>> for word in one_list: 50 | ... print word 51 | ... 52 | python 53 | qiwsir 54 | github 55 | io 56 | >>> len(one_list) 57 | 4 58 | 59 | 下面再实验一下,上面的list如果换成tuple是否可行 60 | 61 | >>> t 62 | (1, '23', [123, 'abc'], ('python', 'learn')) 63 | >>> t[2] 64 | [123, 'abc'] 65 | >>> t[1:] 66 | ('23', [123, 'abc'], ('python', 'learn')) 67 | >>> for every in t: 68 | ... print every 69 | ... 70 | 1 71 | 23 72 | [123, 'abc'] 73 | ('python', 'learn') 74 | >>> len(t) 75 | 4 76 | 77 | >>> t[2][0] #还能这样呀,哦对了,list中也能这样 78 | 123 79 | >>> t[3][1] 80 | 'learn' 81 | 82 | **所有在list中可以修改list的方法,在tuple中,都失效。** 83 | 84 | 分别用list()和tuple()能够实现两者的转化: 85 | 86 | >>> t 87 | (1, '23', [123, 'abc'], ('python', 'learn')) 88 | >>> tls = list(t) #tuple-->list 89 | >>> tls 90 | [1, '23', [123, 'abc'], ('python', 'learn')] 91 | 92 | >>> t_tuple = tuple(tls) #list-->tuple 93 | >>> t_tuple 94 | (1, '23', [123, 'abc'], ('python', 'learn')) 95 | 96 | 97 | ##tuple用在哪里? 98 | 99 | 既然它是list和str的杂合,它有什么用途呢?不是用list和str都可以了吗? 100 | 101 | 在很多时候,的确是用list和str都可以了。但是,看官不要忘记,我们用计算机语言解决的问题不都是简单问题,就如同我们的自然语言一样,虽然有的词汇看似可有可无,用别的也能替换之,但是我们依然需要在某些情况下使用它们. 102 | 103 | 一般认为,tuple有这类特点,并且也是它使用的情景: 104 | 105 | - Tuple 比 list 操作速度快。如果您定义了一个值的常量集,并且唯一要用它做的是不断地遍历它,请使用 tuple 代替 list。 106 | - 如果对不需要修改的数据进行 “写保护”,可以使代码更安全。使用 tuple 而不是 list 如同拥有一个隐含的 assert 语句,说明这一数据是常量。如果必须要改变这些值,则需要执行 tuple 到 list 的转换 (需要使用一个特殊的函数)。 107 | - Tuples 可以在 dictionary 中被用做 key,但是 list 不行。实际上,事情要比这更复杂。Dictionary key 必须是不可变的。Tuple 本身是不可改变的,但是如果您有一个 list 的 tuple,那就认为是可变的了,用做 dictionary key 就是不安全的。只有字符串、整数或其它对 dictionary 安全的 tuple 才可以用作 dictionary key。 108 | - Tuples 可以用在字符串格式化中,后面会用到。 109 | -------------------------------------------------------------------------------- /100/124.md: -------------------------------------------------------------------------------- 1 | ## 集合的关系 2 | 3 | ## 冻结的集合 4 | 5 | 前面[一节讲述了集合的基本概念](./123.md),注意,那里所涉及到的集合都是可原处修改的集合。还有一种集合,不能在原处修改。这种集合的创建方法是: 6 | ```python 7 | >>> f_set = frozenset("qiwsir") #看这个名字就知道了frozen,冻结的set 8 | >>> f_set 9 | frozenset(['q', 'i', 's', 'r', 'w']) 10 | >>> f_set.add("python") #报错 11 | Traceback (most recent call last): 12 | File "", line 1, in 13 | AttributeError: 'frozenset' object has no attribute 'add' 14 | 15 | >>> a_set = set("github") #对比看一看,这是一个可以原处修改的set 16 | >>> a_set 17 | set(['b', 'g', 'i', 'h', 'u', 't']) 18 | >>> a_set.add("python") 19 | >>> a_set 20 | set(['b', 'g', 'i', 'h', 'python', 'u', 't']) 21 | ``` 22 | ## 集合运算 23 | 24 | 先复习一下中学数学(准确说是高中数学中的一点知识)中关于集合的一点知识,主要是唤起那痛苦而青涩美丽的回忆吧,至少对我是。 25 | 26 | ###元素与集合的关系 27 | 28 | 元素是否属于某个集合。 29 | 30 | >>> aset 31 | set(['h', 'o', 'n', 'p', 't', 'y']) 32 | >>> "a" in aset 33 | False 34 | >>> "h" in aset 35 | True 36 | 37 | ###集合与集合的纠结 38 | 39 | 假设两个集合A、B 40 | 41 | - A是否等于B,即两个集合的元素完全一样 42 | 43 | 在交互模式下实验 44 | 45 | >>> a 46 | set(['q', 'i', 's', 'r', 'w']) 47 | >>> b 48 | set(['a', 'q', 'i', 'l', 'o']) 49 | >>> a == b 50 | False 51 | >>> a != b 52 | True 53 | 54 | - A是否是B的子集,或者反过来,B是否是A的超集。即A的元素也都是B的元素,但是B的元素比A的元素数量多。 55 | 56 | 实验一下 57 | 58 | >>> a 59 | set(['q', 'i', 's', 'r', 'w']) 60 | >>> c 61 | set(['q', 'i']) 62 | >>> c>> c.issubset(a) #或者用这种方法,判断c是否是a的子集 65 | True 66 | >>> a.issuperset(c) #判断a是否是c的超集 67 | True 68 | 69 | >>> b 70 | set(['a', 'q', 'i', 'l', 'o']) 71 | >>> a>> a.issubset(b) #或者这样做 74 | False 75 | 76 | - A、B的并集,即A、B所有元素,如下图所示 77 | 78 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/12401.png) 79 | 80 | >>> a 81 | set(['q', 'i', 's', 'r', 'w']) 82 | >>> b 83 | set(['a', 'q', 'i', 'l', 'o']) 84 | >>> a | b #可以有两种方式,结果一样 85 | set(['a', 'i', 'l', 'o', 'q', 's', 'r', 'w']) 86 | >>> a.union(b) 87 | set(['a', 'i', 'l', 'o', 'q', 's', 'r', 'w']) 88 | 89 | - A、B的交集,即A、B所公有的元素,如下图所示 90 | 91 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/12402.png) 92 | 93 | >>> a 94 | set(['q', 'i', 's', 'r', 'w']) 95 | >>> b 96 | set(['a', 'q', 'i', 'l', 'o']) 97 | >>> a & b #两种方式,等价 98 | set(['q', 'i']) 99 | >>> a.intersection(b) 100 | set(['q', 'i']) 101 | 102 | 我在实验的时候,顺手敲了下面的代码,出现的结果如下,看官能解释一下吗?(思考题) 103 | 104 | >>> a and b 105 | set(['a', 'q', 'i', 'l', 'o']) 106 | 107 | - A相对B的差(补),即A相对B不同的部分元素,如下图所示 108 | 109 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/12403.png) 110 | 111 | >>> a 112 | set(['q', 'i', 's', 'r', 'w']) 113 | >>> b 114 | set(['a', 'q', 'i', 'l', 'o']) 115 | >>> a - b 116 | set(['s', 'r', 'w']) 117 | >>> a.difference(b) 118 | set(['s', 'r', 'w']) 119 | 120 | -A、B的对称差集,如下图所示 121 | 122 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/12404.png) 123 | 124 | >>> a 125 | set(['q', 'i', 's', 'r', 'w']) 126 | >>> b 127 | set(['a', 'q', 'i', 'l', 'o']) 128 | >>> a.symmetric_difference(b) 129 | set(['a', 'l', 'o', 's', 'r', 'w']) 130 | 131 | 以上是集合的基本运算。在编程中,如果用到,可以用前面说的方法查找。不用死记硬背。 132 | -------------------------------------------------------------------------------- /100/125.md: -------------------------------------------------------------------------------- 1 | ## Python的数据类型总结 2 | 3 | 前面已经洋洋洒洒地介绍了不少数据类型。不能再不顾一切地向前冲了,应当总结一下。这样让看官能够从总体上对这些数据类型有所了解,如果能够有一览众山小的感觉,就太好了。 4 | 5 | 下面的表格中列出了已经学习过的数据类型,也是python的核心数据类型之一部分,这些都被称之为内置对象。 6 | 7 | >对象,就是你面对的所有东西都是对象,看官要逐渐熟悉这个称呼。所有的数据类型,就是一种对象。英文单词是object,直接的汉语意思是物体,这就好像我们在现实中一样,把很多我们看到和用到的都可以统称为“东西”一样。“东西”就是“对象”,就是object。在编程中,那个所谓面向对象,也可以说成“面向东西”,是吗?容易有歧义吧。 8 | 9 | | 对象类型 | 举例 | 10 | |----------|------| 11 | | int/float | 123, 3.14 | 12 | | str | 'qiwsir.github.io'| 13 | | list | [1, [2, 'three'], 4] | 14 | | dict | {'name':"qiwsir","lang":"python"} | 15 | | tuple | (1, 2, "three") | 16 | | set | set("qi"), {"q", "i"}| 17 | 18 | 不论任何类型的数据,只要动用dir(object)或者help(obj)就能够在交互模式下查看到有关的函数,也就是这样能够查看相关帮助文档了。举例: 19 | 20 | >>> dir(dict) 21 | 22 | 看官需要移动鼠标,就能够看全(下面的本质上就是一个list): 23 | 24 | ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues'] 25 | 26 | 先略过__双下划线开头的哪些,看后面的,就是dict的内置函数。至于详细的操作方法,通过类似help(dict.pop)的方式获得。这是前面说过的,再说一遍,加深印象。 27 | 28 | **我的观点:学习,重要的是学习方法,不是按部就班的敲代码。** 29 | 30 | 今天既然是复习,就要在原来基础上提高一点。所以,也要看看上面那些以双下划线__开头的东西,请看官找一下,有没有发现这个:"\_\_doc\_\_"。这是什么,它是一个文件,里面记录了对当前所查看的对象的详细解释。可以在交互模式下这样查看: 31 | 32 | >>> dict.__doc__ 33 | 34 | 显示应该是这样的: 35 | 36 | >"dict() -> new empty dictionary\ndict(mapping) -> new dictionary initialized from a mapping object's\n (key, value) pairs\ndict(iterable) -> new dictionary initialized as if via:\n d = {}\n for k, v in iterable:\n d[k] = v\ndict(**kwargs) -> new dictionary initialized with the name=value pairs\n in the keyword argument list. For example: dict(one=1, two=2)" 37 | 38 | 注意看上面乱七八糟的英文中,是不是有\n符号,这是什么?前面在讲述字符串的时候提到了转义符号\,这是换一行。也就是说,如果上面的文字,按照排版要求,应该是这样的(当然,在文本中,如果打开,其实就是排好版的样子)。 39 | 40 | >"dict() -> new empty dictionary 41 | >dict(mapping) -> new dictionary initialized from a mapping object's 42 | > (key, value) pairs 43 | >dict(iterable) -> new dictionary initialized as if via: 44 | > d = {} 45 | > for k, v in iterable: 46 | > d[k] = v 47 | > dict(**kwargs) -> new dictionary initialized with the name=value pairs 48 | > in the keyword argument list. For example: dict(one=1, two=2)" 49 | 50 | 可能排版还是不符合愿意。不过,看官也大概能看明白了。我要说的不是排版,要说的是告诉看官一种查看某个数据类型含义的方法,就是通过obj.\_\_doc\_\_文件来看。 51 | 52 | 嘿嘿,其实有一种方法,可以看到排版的结果的: 53 | 54 | >>> print dict.__doc__ 55 | dict() -> new empty dictionary 56 | dict(mapping) -> new dictionary initialized from a mapping object's 57 | (key, value) pairs 58 | dict(iterable) -> new dictionary initialized as if via: 59 | d = {} 60 | for k, v in iterable: 61 | d[k] = v 62 | dict(**kwargs) -> new dictionary initialized with the name=value pairs 63 | in the keyword argument list. For example: dict(one=1, two=2) 64 | 65 | 上面那么折腾一下,就是为了凑篇幅,不然这个总结的东西太少了。 66 | 67 | 总之,只要用这种方法,你就能得到所有帮助文档,随时随地。如果可以上网,到官方网站,是另外一种方法。 68 | 69 | 还需要再解释别的吗?都多余了。唯一需要的是看官要能会点英语。不过我相信看官能够读懂,我这个二把刀都不如的英语水平,还能凑合看呢,何况看官呢? 70 | 71 | 总结不是意味着结束,是意味着继往开来。精彩还在后面,这里只是休息。今天还是周日。 72 | 73 | ##主日崇拜 74 | 75 | 腓立比書 Philippians(3:13-14) 76 | 77 | >Brethren, I count not myself to have apprehended: but this one thing I do, forgetting those things which are behind, and reaching forth unto those things which are before, 78 | >I press toward the mark for the prize of the high calling of God in Christ Jesus. 79 | 80 | >弟兄們、我不是以為自己已經得著了.我只有一件事、就是忘記背後努力面前的, 81 | >向著標竿直跑、要得神在基督耶穌裡從上面召我來得的獎賞 。 82 | 83 | ###忘记背后,努力面前,向着标杆直跑## 84 | -------------------------------------------------------------------------------- /100/126.md: -------------------------------------------------------------------------------- 1 | ## 深入变量和引用对象 2 | 3 | 今天是2014年8月4日,这段时间灾祸接连发生,显示不久前昆山的工厂爆炸,死伤不少,然后是云南地震,也有死伤。为所有在灾难中受伤害的人们献上祷告。 4 | 5 | 在[《永远强大的函数》](./106.md)那一讲中,老齐我(http://qiwsir.github.io)已经向看官们简述了一下变量,之后我们就一直在使用变量,每次使用变量,都要有一个操作,就是赋值。本讲再次提及这个两个事情,就是要让看官对变量和赋值有一个知其然和知其所以然的认识。当然,最后能不能达到此目的,主要看我是不是说的通俗易懂了。如果您没有明白,就说明我说的还不够好,可以联系我,我再为您效劳。 6 | 7 | ## 变量和对象 8 | 9 | 在[《learning python》](http://shop.oreilly.com/product/0636920028154.do)那本书里面,作者对变量、对象和引用的关系阐述的非常明了。我这里在很大程度上是受他的启发。感谢作者Mark Lutz先生的巨著。 10 | 11 | 应用《learning python》中的一个观点:**变量无类型,对象有类型** 12 | 13 | 在python中,如果要使用一个变量,不需要提前声明,只需要在用的时候,给这个变量赋值即可。这里特别强调,只要用一个变量,就要给这个变量赋值。 14 | 15 | 所以,像这样是不行的。 16 | 17 | >>> x 18 | Traceback (most recent call last): 19 | File "", line 1, in 20 | NameError: name 'x' is not defined 21 | 22 | 反复提醒:一定要注意看报错信息。如果光光地写一个变量,而没有赋值,那么python认为这个变量没有定义。赋值,不仅仅是给一个非空的值,也可以给一个空值,如下,都是允许的 23 | 24 | >>> x = 3 25 | >>> lst = [] 26 | >>> word = "" 27 | >>> my_dict = {} 28 | 29 | 在前面讲述中,我提出了一个类比,就是变量通过一根线,连着对象(具体就可能是一个int/list等),这个类比被很多人接受了,算是我老齐的首创呀。那么,如果要用一种严格的语言来描述,变量可以理解为一个系统表的元素,它拥有过指向对象的命名空间。太严肃了,不好理解,就理解我那个类比吧。变量就是存在系统中的一个东西,这个东西有一种能力,能够用一根线与某对象连接,它能够钓鱼。 30 | 31 | 对象呢?展开想象。在机器的内存中,系统分配一个空间,这里面就放着所谓的对象,有时候放数字,有时候放字符串。如果放数字,就是int类型,如果放字符串,就是str类型。 32 | 33 | 接下来的事情,就是前面说的变量用自己所拥有的能力,把对象和自己连接起来(指针连接对象空间),这就是引用。引用完成,就实现了赋值。 34 | 35 | ![](../Pictures/12601.png) 36 | 37 | 看到上面的图了吧,从图中就比较鲜明的表示了变量和对象的关系。所以,严格地将,只有放在内存空间中的对象(也就是数据)才有类型,而变量是没有类型的。这么说如果还没有彻底明白,就再打一个比喻:变量就好比钓鱼的人,湖水里就好像内存,里面有好多鱼,有各种各样的鱼,它们就是对象。钓鱼的人(变量)的任务就是用某种方式(鱼儿引诱)把自己和鱼通过鱼线连接起来。那么,鱼是有类型的,有鲢鱼、鲫鱼、带鱼(带鱼也跑到湖水了了,难道是淡水带鱼?呵呵,就这么扯淡吧,别较真),钓鱼的人(变量)没有这种类型,他钓到不同类型的鱼。 38 | 39 | 这个比喻太烂了。凑合着理解吧。看官有好的比喻,别忘记分享。 40 | 41 | 同一个变量可以同时指向两个对象吗?绝对不能脚踩两只船。如果这样呢? 42 | 43 | >>> x = 4 44 | >>> x = 5 45 | >>> x 46 | 5 47 | 48 | 变量x先指向了对象4,然后指向对象5,当后者放生的时候,自动跟第一个对象4解除关系。再看x,引用的对象就是5了。那么4呢?一旦没有变量引用它了,它就变成了孤魂野鬼。python是很吝啬的,它绝对不允许在内存中存在孤魂野鬼。凡是这些东西都被看做垃圾,而对垃圾,python有一个自动的收回机制。 49 | 50 | 在网上找了一个图示说明,很好,引用过来(来源:http://www.linuxidc.com/Linux/2012-09/69523.htm) 51 | 52 | >>> a = 100 #完成了变量a对内存空间中的对象100的引用 53 | 54 | 如下图所示: 55 | 56 | ![](../Pictures/12602.png) 57 | 58 | 然后,又操作了: 59 | 60 | >>> a = "hello" 61 | 62 | 如下图所示: 63 | 64 | ![](../Pictures/12603.png) 65 | 66 | 原来内存中的那个100就做为垃圾被收集了。而且,这个收集过程是python自动完成的,不用我们操心。 67 | 68 | 那么,python是怎么进行垃圾收集的呢?在[Quora](http://www.quora.com)上也有人问这个问题,我看那个回答很精彩,做个链接,有性趣的读一读吧。[Python (programming language): How does garbage collection in Python work?](http://www.quora.com/Python-programming-language-1/How-does-garbage-collection-in-Python-work) 69 | 70 | ##is和==的效果 71 | 72 | 以上过程的原理搞清楚了,下面就可以深入一步了。 73 | 74 | >>> l1 = [1,2,3] 75 | >>> l2 = l1 76 | 77 | 这个操作中,l1和l2两个变量,引用的是一个对象,都是[1,2,3]。何以见得?如果通过l1来修改[1,2,3],l2引用对象也修改了,那么就证实这个观点了。 78 | 79 | >>> l1[0] = 99 #把对象变为[99,2,3] 80 | >>> l1 #变了 81 | [99, 2, 3] 82 | >>> l2  #真的变了吔 83 | [99, 2, 3] 84 | 85 | 再换一个方式: 86 | 87 | >>> l1 = [1,2,3] 88 | >>> l2 = [1,2,3] 89 | >>> l1[0] = 99 90 | >>> l1 91 | [99, 2, 3] 92 | >>> l2 93 | [1, 2, 3] 94 | 95 | l1和l2貌似指向了同样的一个对象[1,2,3],其实,在内存中,这是两块东西,互不相关。只是在内容上一样。就好像是水里长的一样的两条鱼,两个人都钓到了,但不是同一条。所以,当通过l1修改引用对象的后,l2没有变化。 96 | 97 | 进一步还能这么检验: 98 | 99 | >>> l1 100 | [1, 2, 3] 101 | >>> l2 102 | [1, 2, 3] 103 | >>> l1 == l2 #两个相等,是指内容一样 104 | True 105 | >>> l1 is l2 #is 是比较两个引用对象在内存中的地址是不是一样 106 | False  #前面的检验已经说明,这是两个东东 107 | 108 | >>> l3 = l1   #顺便看看如果这样,l3和l1应用同一个对象 109 | >>> l3 110 | [1, 2, 3] 111 | >>> l3 == l1 112 | True 113 | >>> l3 is l1 #is的结果是True 114 | True 115 | 116 | 某些对象,有copy函数,通过这个函数得到的对象,是一个新的还是引用到同一个对象呢?看官也可以做一下类似上面的实验,就晓得了。比如: 117 | 118 | >>> l1 119 | [1, 2, 3] 120 | >>> l2 = l1[:] 121 | >>> l2 122 | [1, 2, 3] 123 | >>> l1[0] = 22 124 | >>> l1 125 | [22, 2, 3] 126 | >>> l2 127 | [1, 2, 3] 128 | 129 | >>> adict = {"name":"qiwsir","web":"qiwsir.github.io"} 130 | >>> bdict = adict.copy() 131 | >>> bdict 132 | {'web': 'qiwsir.github.io', 'name': 'qiwsir'} 133 | >>> adict["email"] = "qiwsir@gmail.com" 134 | >>> adict 135 | {'web': 'qiwsir.github.io', 'name': 'qiwsir', 'email': 'qiwsir@gmail.com'} 136 | >>> bdict 137 | {'web': 'qiwsir.github.io', 'name': 'qiwsir'} 138 | 139 | 不过,看官还有小心有点,python不总按照前面说的方式出牌,比如小数字的时候 140 | 141 | >>> x = 2 142 | >>> y = 2 143 | >>> x is y 144 | True 145 | >>> x = 200000 146 | >>> y = 200000 147 | >>> x is y #什么道理呀,小数字的时候,就用缓存中的. 148 | False 149 | 150 | >>> x = 'hello' 151 | >>> y = 'hello' 152 | >>> x is y 153 | True 154 | >>> x = "what is you name?" 155 | >>> y = "what is you name?" 156 | >>> x is y #不光小的数字,短的字符串也是 157 | False 158 | 159 | 赋值是不是简单地就是等号呢?从上面得出来,=的作用就是让变量指针指向某个对象。不过,还可以再深入一些。走着瞧吧。 160 | -------------------------------------------------------------------------------- /100/127.md: -------------------------------------------------------------------------------- 1 | ## 赋值,简单也不简单 2 | 3 | ## 变量命名 4 | 5 | 在[《初识永远强大的函数》](./106.md)一文中,有一节专门讨论“取名字的学问”,就是有关变量名称的问题,本温故而知新的原则,这里要复习: 6 | 7 | 名称格式:(下划线或者字母)+(任意数目的字母,数字或下划线) 8 | 9 | **注意:** 10 | 11 | 1. 区分大小写 12 | 2. 禁止使用保留字 13 | 3. 遵守通常习惯 14 | 15 | - 以单一下划线开头的变量名(_X)不会被from module import *语句导入的。 16 | - 前后有下划线的变量名(__X__)是系统定义的变量名,对解释器有特殊意义。 17 | - 以两个下划线开头,但结尾没有两个下划线的变量名(__X)是类本地(压缩)变量。 18 | - 通过交互模式运行时,只有单个下划线变量(_)会保存最后的表达式结果。 19 | 20 | 需要解释一下保留字,就是python里面保留了一些单词,这些单词不能让用户来用作变量名称。都有哪些呢?(python2和python3少有差别,但是总体差不多) 21 | 22 | >and assert break class continue def del elif else except exec finally for from global if import in is lambda not or pass print raise return try while yield 23 | 24 | 需要都记住吗?当然不需要了。一方面,可以在网上随手查到,另外,还能这样: 25 | 26 | >>> not = 3 27 | File "", line 1 28 | not = 3 29 | ^ 30 | SyntaxError: invalid syntax 31 | 32 | >>> pass = "hello,world" 33 | File "", line 1 34 | pass = "hello,world" 35 | ^ 36 | SyntaxError: invalid syntax 37 | 38 | 在交互模式的实验室中,用保留字做变量,就报错了。当然,这时候就要换名字了。 39 | 40 | 以上原则,是基本原则。在实际编程中,大家通常还这样做,以便让程序更具有可读性: 41 | 42 | - 名字具有一定的含义。比如写:n = "qiwsir",就不如写:name = "qiwsir"更好。 43 | - 名字不要误导别人。比如用account_list指一组账号,就会被人误解为是list类型的数据,事实上可能是也可能不是。所以这时候最好换个名称,比如直接用accounts。 44 | - 名字要有意义的区分,有时候你可能会用到a1,a2之类的名字,最好不要这么做,换个别的方式,通过字面能够看出一定的区分来更好。 45 | - 最好是名称能够读出来,千万别自己造英文单词,也别乱用所写什么的,特别是贵国的,还喜欢用汉语拼音缩写来做为名字,更麻烦了,还不如全拼呢。最好是用完整的单词或者公认的不会引起歧义的缩写。 46 | - 单个字母和数字就少用了,不仅是显得你太懒惰,还会因为在一段代码中可能有很多个单个的字母和数字,为搜索带来麻烦,别人也更不知道你的i和他理解的i是不是一个含义。 47 | 48 | 总之,取名字,讲究不少。不论如何,要记住一个标准:**明确** 49 | 50 | ##赋值语句 51 | 52 | 对于赋值语句,看官已经不陌生了。任何一个变量,在python中,只要想用它,就要首先赋值。 53 | 54 | **语句格式:**变量名称 = 对象 55 | 56 | [上一节](./126.md)中也分析了赋值的本质。 57 | 58 | 还有一种赋值方式,叫做隐式赋值,通过import、from、del、class、for、函数参数。等模块导入,函数和类的定义,for循环变量以及函数参数都是隐式赋值运算。这方面的东西后面会徐徐道来。 59 | 60 | >>> name = "qiwsir" 61 | 62 | >>> name, website = "qiwsir","qiwsir.github.io" #多个变量,按照顺序依次赋值 63 | >>> name 64 | 'qiwsir' 65 | >>> website 66 | 'qiwsir.github.io' 67 | 68 | >>> name, website = "qiwsir" #有几个变量,就对应几个对象,不能少,也不能多 69 | Traceback (most recent call last): 70 | File "", line 1, in 71 | ValueError: too many values to unpack 72 | 73 | 如果这样赋值,也得两边数目一致: 74 | 75 | >>> one,two,three,four = "good" 76 | >>> one 77 | 'g' 78 | >>> two 79 | 'o' 80 | >>> three 81 | 'o' 82 | >>> four 83 | 'd' 84 | 85 | 这就相当于把good分拆为一个一个的字母,然后对应着赋值给左边的变量。 86 | 87 | >>> [name,site] = ["qiwsir","qiwsir.github.io"] 88 | >>> name 89 | 'qiwsir' 90 | >>> site 91 | 'qiwsir.github.io' 92 | >>> name,site = ("qiwsir","qiwsir.github.io") 93 | >>> name 94 | 'qiwsir' 95 | >>> site 96 | 'qiwsir.github.io' 97 | 98 | 这样也行呀。 99 | 100 | 其实,赋值的样式不少,核心就是将变量和某对象对应起来。对象,可以用上面的方式,也许是这样的 101 | 102 | >>> site = "qiwsir.github.io" 103 | >>> name, main = site.split(".")[0], site.split(".")[1] #还记得str.split()这个东东吗?忘记了,google一下吧。 104 | >>> name 105 | 'qiwsir' 106 | >>> main 107 | 'github' 108 | 109 | ##增强赋值 110 | 111 | 这个东西听名字就是比赋值强的。 112 | 113 | 在python中,将下列的方式称为增强赋值: 114 | 115 | |增强赋值语句|等价于语句| 116 | |------------|----------| 117 | | x+=y | x = x+y | 118 | | x-=y | x = x-y | 119 | | x*=y | x = x*y | 120 | | x/=y | x = x/y | 121 | 122 | 其它类似结构:x&=y  x|=y  x^=y  x%=y  x>>=y x<<=y  x**=y  x//=y 123 | 124 | 看下面的例子,有一个list,想得到另外一个列表,其中每个数比原来list中的大2。可以用下面方式实现: 125 | 126 | >>> number 127 | [1, 2, 3, 4, 5] 128 | >>> number2 = [] 129 | >>> for i in number: 130 | ... i = i+2 131 | ... number2.append(i) 132 | ... 133 | >>> number2 134 | [3, 4, 5, 6, 7] 135 | 136 | 如果用上面的增强赋值,i = i+2可以写成 i +=2,试一试吧: 137 | 138 | >>> number 139 | [1, 2, 3, 4, 5] 140 | >>> number2 = [] 141 | >>> for i in number: 142 | ... i +=2 143 | ... number2.append(i) 144 | ... 145 | >>> number2 146 | [3, 4, 5, 6, 7] 147 | 148 | 这就是增强赋值。为什么用增强赋值?因为i +=2,比i = i+2计算更快,后者右边还要拷贝一个i。 149 | 150 | 上面的例子还能修改,别忘记了list解析的强大功能呀。 151 | 152 | >>> [i+2 for i in number] 153 | [3, 4, 5, 6, 7] 154 | -------------------------------------------------------------------------------- /100/129.md: -------------------------------------------------------------------------------- 1 | ## 做一个小游戏 2 | 3 | 在讲述[有关list的时候,提到做游戏的事情](./115.md),后来这个事情一直没有接续。不是忘记了,是在想在哪个阶段做最合适。经过一段时间学习,看官已经不是纯粹小白了,已经属于python初级者了。现在就是开始做那个游戏的时候了。 4 | 5 | ##游戏内容:猜数字游戏 6 | 7 | 太简单了吧。是的,游戏难度不大,不过这个游戏中蕴含的东西可是值得玩味的。 8 | 9 | ###游戏过程描述 10 | 11 | 1. 程序运行起来,随机在某个范围内选择一个整数。 12 | 2. 提示用户输入数字,也就是猜程序随即选的那个数字。 13 | 3. 程序将用户输入的数字与自己选定的对比,一样则用户完成游戏,否则继续猜。 14 | 4. 使用次数少的用户得胜. 15 | 16 | ##分析 17 | 18 | 在任何形式的程序开发之前,不管是大还是小,都要进行分析。即根据功能需求,将不同功能点进行分解。从而确定开发过程。我们现在做一个很小的程序,也是这样来做。 19 | 20 | ###随机选择一个数 21 | 22 | 要实现随机选择一个数字,可以使用python中的一个随机函数:random。下面对这个函数做简要介绍,除了针对本次应用之外,还扩展点,也许别处看官能用上。 23 | 24 | 还是要首先强化一种学习方法,就是要学会查看帮助文档。 25 | 26 | >>> import random #这个是必须的,因为不是内置函数 27 | >>> dir(random) 28 | ['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', 'WichmannHill', '_BuiltinMethodType', '_MethodType', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_acos', '_ceil', '_cos', '_e', '_exp', '_hashlib', '_hexlify', '_inst', '_log', '_pi', '_random', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', 'choice', 'division', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'jumpahead', 'lognormvariate', 'normalvariate', 'paretovariate', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', 'weibullvariate'] 29 | >>> help(random.randint) 30 | 31 | Help on method randint in module random: 32 | 33 | randint(self, a, b) method of random.Random instance 34 | Return random integer in range [a, b], including both end points. 35 | 36 | 耐心地看文档,就明白怎么用了。不过,还是把主要的东西列出来,但仍然建议看官在看每个函数的使用之前,在交互模式下通过help来查看文档。 37 | 38 | **随机整数:** 39 | 40 | >>> import random 41 | >>> random.randint(0,99) 42 | 21 43 | 44 | **随机选取0到100间的偶数:** 45 | 46 | >>> import random 47 | >>> random.randrange(0, 101, 2) 48 | 42 49 | 50 | **随机浮点数:** 51 | 52 | >>> import random 53 | >>> random.random() 54 | 0.85415370477785668 55 | >>> random.uniform(1, 10) 56 | 5.4221167969800881 57 | 58 | **随机字符:** 59 | 60 | >>> import random 61 | >>> random.choice('qiwsir.github.io') 62 | 'g' 63 | 64 | **多个字符中选取特定数量的字符:** 65 | 66 | >>> import random 67 | random.sample('qiwsir.github.io',3) 68 | ['w', 's', 'b'] 69 | 70 | **随机选取字符串:** 71 | 72 | >>> import random 73 | >>> random.choice ( ['apple', 'pear', 'peach', 'orange', 'lemon'] ) 74 | 'lemon' 75 | 76 | **洗牌:**把原有的顺序打乱,按照随机顺序排列 77 | 78 | >>> import random 79 | >>> items = [1, 2, 3, 4, 5, 6] 80 | >>> random.shuffle(items) 81 | >>> items 82 | [3, 2, 5, 6, 4, 1] 83 | 84 | 有点多了。不过,本次实验中,值用到了random.randint()即可。多出来是买一送一的(哦。忘记了,没有人买呢,本课程全是白送的)。 85 | 86 | 关键技术点之一已经突破。可以编程了。再梳理一下流程。画个图展示: 87 | 88 | (备注:这里我先懒惰一下吧,看官能不能画出这个程序的流程图呢?特别是如果是一个初学者,流程图一定要自己画哦。刚才看到网上一个朋友说自己学编程,但是逻辑思维差,所以没有学好。其实,画流程图就是帮助提高逻辑思维的一种好方式,请画图吧。) 89 | 90 | 图画好了,按照直观的理解,下面的代码是一个初学者常常写出来的(老鸟们不要喷,因为是代表初学者的)。 91 | 92 | #!/usr/bin/env python 93 | #coding:utf-8 94 | 95 | import random 96 | 97 | number = random.randint(1,100) 98 | 99 | print "请输入一个100以内的自然数:" 100 | 101 | input_number = raw_input() 102 | 103 | if number == int(input_number): 104 | print "猜对了,这个数是:" 105 | print number 106 | else: 107 | print "错了。" 108 | 109 | 上面的程序已经能够基本走通,但是,还有很多缺陷。 110 | 111 | 最明显的就是只能让人猜一次,不能多次。怎么修改,能够多次猜呢?动动脑筋之后看代码,或者看官在自己的代码上改改,能不能实现多次猜测? 112 | 113 | 另外,能不能增强一些友好性呢,让用户知道自己输入的数是大了,还是小了。 114 | 115 | 根据上述修改想法,新代码如下: 116 | 117 | #!/usr/bin/env python 118 | #coding:utf-8 119 | 120 | import random 121 | 122 | number = random.randint(1,100) 123 | 124 | print "请输入一个100以内的自然数:" 125 | 126 | input_number = raw_input() 127 | 128 | if number == int(input_number): 129 | print "猜对了,这个数是:" 130 | print number 131 | elif number > int(input_number): 132 | print "小了" 133 | input_number = raw_input() 134 | elif number < int(input_number): 135 | print "大了" 136 | input_number = raw_input() 137 | else: 138 | print "错了。" 139 | 140 | 嗯,似乎比原来进步一点点,因为允许用户输入第二次了。同时也告诉用户输入的是大还是小了。但,这也不行呀。应该能够输入很多次,直到正确为止。 141 | 142 | 是的。这就要用到一个新的东西:循环。如果看官心急,可以google一下while或者for循环,来进一步完善这个游戏,如果不着急,可以等等,随后我也会讲到这部分。 143 | 144 | 这个游戏还没有完呢,及时用了循环,后面还会继续。 145 | -------------------------------------------------------------------------------- /100/131.md: -------------------------------------------------------------------------------- 1 | ## 不要红头文件(2) 2 | 3 | 在前面学习了基本的打开和建立文件之后,就可以对文件进行多种多样的操作了。请看官要注意,文件,不是什么特别的东西,就是一个对象,如同对待此前学习过的字符串、列表等一样。 4 | 5 | ##文件的属性 6 | 7 | 所谓属性,就是能够通过一个文件对象得到的东西。 8 | 9 | >>> f = open("131.txt","a") 10 | >>> f.name 11 | '131.txt' 12 | >>> f.mode #显示当前文件打开的模式 13 | 'a' 14 | >>> f.closed #文件是否关闭,如果关闭,返回True;如果打开,返回False 15 | False 16 | >>> f.close() #关闭文件的内置函数 17 | >>> f.closed 18 | True 19 | 20 | ##文件的有关状态 21 | 22 | 很多时候,我们需要获取一个文件的有关状态(有时候成为属性,但是这里的文件属性和上面的文件属性是不一样的,可是,我觉得称之为文件状态更好一点),比如创建日期,访问日期,修改日期,大小,等等。在os模块中,有这样一个方法,能够解决此问题: 23 | 24 | >>> import os 25 | >>> file_stat = os.stat("131.txt") #查看这个文件的状态 26 | >>> file_stat #文件状态是这样的。从下面的内容,有不少从英文单词中可以猜测出来。 27 | posix.stat_result(st_mode=33204, st_ino=5772566L, st_dev=2049L, st_nlink=1, st_uid=1000, st_gid=1000, st_size=69L, st_atime=1407897031, st_mtime=1407734600, st_ctime=1407734600) 28 | 29 | >>> file_stat.st_ctime #这个是文件创建时间 30 | 1407734600.0882277 #换一种方式查看这个时间 31 | >>> import time 32 | >>> time.localtime(file_stat.st_ctime) #这回看清楚了。 33 | time.struct_time(tm_year=2014, tm_mon=8, tm_mday=11, tm_hour=13, tm_min=23, tm_sec=20, tm_wday=0, tm_yday=223, tm_isdst=0) 34 | 35 | 以上关于文件状态和文件属性的内容,在对文件的某些方面进行判断和操作的时候或许会用到。特别是文件属性。比如在操作文件的时候,我们经常要首先判断这个文件是否已经关闭或者打开,就需要用到file.closed这个属性来判断了。 36 | 37 | ##文件的内置函数 38 | 39 | >>> dir(file) 40 | ['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines'] 41 | >>> 42 | 43 | 这么多内置函数,不会都讲述,只能捡着重点的来实验了。 44 | 45 | >>> f = open("131.txt","r") 46 | >>> f.read() 47 | 'My name is qiwsir.\nMy website is qiwsir.github.io\nAha,I like program\n' 48 | >>> 49 | 50 | file.read()能够将文件中的内容全部读取过来。特别注意,这是返回一个字符串,而且是将文件中的内容全部读到内存中。试想,如果内容太多是不是就有点惨了呢?的确是,千万不要去读大个的文件。 51 | 52 | >>> contant = f.read() 53 | >>> type(contant) 54 | 55 | 56 | 如果文件比较大了,就不要一次都读过来,可以转而一行一行地,用readline 57 | 58 | >>> f = open("131.txt","r") 59 | >>> f.readline() #每次返回一行,然后指针向下移动 60 | 'My name is qiwsir.\n' 61 | >>> f.readline() #再读,再返回一行 62 | 'My website is qiwsir.github.io\n' 63 | >>> f.readline() 64 | 'Aha,I like program\n' 65 | >>> f.readline() #已经到最后一行了,再读,不报错,返回空 66 | '' 67 | 68 | 这个方法,看官是不是觉得太慢了呢?有没有痛快点的呢?有,请挥刀自宫,不用自宫,也能用readlines。注意区别,这个是复数,言外之意就是多行啦。 69 | 70 | >>> f = open("131.txt","r") 71 | >>> cont = f.readlines() 72 | >>> cont 73 | ['My name is qiwsir.\n', 'My website is qiwsir.github.io\n', 'Aha,I like program\n'] 74 | >>> type(cont) 75 | 76 | >>> for line in cont: 77 | ... print line 78 | ... 79 | My name is qiwsir. 80 | 81 | My website is qiwsir.github.io 82 | 83 | Aha,I like program 84 | 85 | 从实验中我们可以看到,readlines和read有一样之处,都是将文件内容一次性读出来,存放在内存,但是两者也有区别,read返回的是str类型,readlines返回的是list,而且一行一个元素,因此,就可以通过for逐行打印出来了。 86 | 87 | 在print line中,注意观察list里面的每个元素,最后都是一个\n结尾,所以打印的结果会有空行。其原因前面已经介绍过了,忘了的朋友请回滚到[上一讲](./130.md) 88 | 89 | 不过,还是要提醒列位,太大的文件不用都读到内存中。对付大点的文件,还是推荐这么做: 90 | 91 | >>> f = open("131.txt","r") 92 | >>> f 93 | 94 | >>> type(f) 95 | 96 | >>> for line in f: 97 | ... print line 98 | ... 99 | My name is qiwsir. 100 | 101 | My website is qiwsir.github.io 102 | 103 | Aha,I like program 104 | 105 | 以上都是读文件的内置函数和方法。除了读,就是要写。所谓写,就是将内容存入到文件中。用到的内置函数是write。但是,要写入文件,还要注意打开文件的模式,可以是w,也可以是a,看具体情况而定。 106 | 107 | >>> f = open("131.txt","a") #因为这个文件已经存在,我又不想清空,用追加的模式 108 | >>> f.write("There is a baby.") #这句话应该放到文件最后 109 | >>> f.close() #请看官注意,写了之后,一定要及时关闭文件。才能代表真正写入 110 | 111 | 看看写的效果: 112 | 113 | >>> f = open("131.txt","r") 114 | >>> for line in f.readlines(): 115 | ... print line 116 | ... 117 | My name is qiwsir. 118 | 119 | My website is qiwsir.github.io 120 | 121 | Aha,I like program 122 | 123 | There is a baby. #果然增加了这一行 124 | 125 | 以上是关于文件的基本操作。其实对文件远远不知这些,有兴趣的看官可以google一下pickle这个模块,是一个很好用的东西。 126 | -------------------------------------------------------------------------------- /100/README.md: -------------------------------------------------------------------------------- 1 | ## 第一部分 积小流,至江海 2 | * [Python环境安装](100/101.md) 3 | * [集成开发环境(IDE)](100/102.md) 4 | * [数的类型和四则运算](100/103.md) 5 | * [啰嗦的除法](100/104.md) 6 | * [开始真正编程](100/105.md) 7 | * [初识永远强大的函数](100/106.md) 8 | * [玩转字符串(1):基本概念、字符转义、字符串连接、变量与字符串关系](100/107.md) 9 | * [玩转字符串(2)](100/108.md) 10 | * [玩转字符串(3)](100/109.md) 11 | * [眼花缭乱的运算符](100/110.md) 12 | * [从if开始语句的征程](100/111.md) 13 | * [一个免费的实验室](100/112.md) 14 | * [有容乃大的list(1)](100/113.md) 15 | * [有容乃大的list(2)](100/114.md) 16 | * [有容乃大的list(3)](100/115.md) 17 | * [有容乃大的list(4)](100/116.md) 18 | * [list和str比较](100/117.md) 19 | * [画圈还不简单吗](100/118.md) 20 | * [再深点,更懂list](100/119.md) 21 | * [字典,你还记得吗?](100/120.md) 22 | * [字典的操作方法](100/121.md) 23 | * [有点简约的元组](100/122.md) 24 | * [一二三,集合了](100/123.md) 25 | * [集合的关系](100/124.md) 26 | * [Python数据类型总结](100/125.md) 27 | * [深入变量和引用对象](100/126.md) 28 | * [赋值,简单也不简单](100/127.md) 29 | * [坑爹的字符编码](100/128.md) 30 | * [做一个小游戏](100/129.md) 31 | * [不要红头文件(1): open, write, close](100/130.md) 32 | * [不要红头文件(2): os.stat, closed, mode, read, readlines, readline](100/131.md) 33 | -------------------------------------------------------------------------------- /200/201.md: -------------------------------------------------------------------------------- 1 | ## 正规地说一句话 2 | 3 | 小孩子刚刚开始学说话的时候,常常是一个字一个字地开始学,比如学说“饺子”,对他/她来讲,似乎有点难度,大人也聪明,于是就简化了,用“饺饺”来代替,其实就是让孩子学会一个字就能表达。当然,从教育学的角度,有人不赞成这种方法。这个此处不讨论了。如果对比学习编程,就好像是前面已经学习过的那些各种类型的数据(对应这自然语言中的单个字、词),要表达一个完整的意思,或者让计算机完成一个事情(动作),不得不通过一句话,这句话就是语句,它是按照一定规则组织起来的。自然语言中的一句话,按照主谓宾的语法方式组织,计算机编程中的语句,也是按照一定的语法要求进行组织。 4 | 5 | 虽然在第一部分中,已经零星涉及到语句问题,并且在不同场合也进行了一些应用。毕竟不那么系统。本部分,就比较系统地介绍python中的语句。 6 | 7 | 为了有总括的印象,先看看python中都包括哪些语句: 8 | 9 | - 赋值语句 10 | - if语句,当条件成立时运行语句块。经常与else, elif(相当于else if)配合使用。 11 | - for语句,遍列列表、字符串、字典、集合等迭代器,依次处理迭代器中的每个元素。 12 | - while语句,当条件为真时,循环运行语句块。 13 | - try语句。与except, finally, else配合使用处理在程序运行中出现的异常情况。 14 | - class语句。用于定义类型。 15 | - def语句。用于定义函数和类型的方法。 16 | - pass语句。表示此行为空,不运行任何操作。 17 | - assert语句。用于程序调适阶段时测试运行条件是否满足。 18 | - with语句。Python2.6以后定义的语法,在一个场景中运行语句块。比如,运行语句块前加锁,然后在语句块运行退出后释放锁。 19 | - yield语句。在迭代器函数内使用,用于返回一个元素。 20 | - raise语句。抛出一个异常。 21 | - import语句。导入一个模块或包。常用写法:from module import name, import module as name, from module import name as anothername 22 | 23 | 特别说明,以上划分也不是很严格,有的内容,有的朋友不认为属于语句。这没关系,反正就是那个东西,在编程中使用。不纠结于名词归类上。总之这些都是要掌握的,才能顺利编程呢。 24 | 25 | ## 再谈赋值语句 26 | 27 | 还记得[赋值,简单也不简单](./127.md)那一讲中所提到的赋值语句吗?既然谈语句,就应该从这个开始,一方面复习,另外一方面,希望能够深点,深点的感觉总是很好的(我说的是理解python,思无邪。前面有一个关于list的内容:[再深点,更懂list](./119.md),就有喜欢看玩笑的看官思邪了。哈哈。) 28 | ```python 29 | >>> qiwsir = 1 30 | >>> python = 2 31 | >>> x, y = qiwsir, python #相当于x=qiwsir,y=python 32 | >>> x 33 | 1 34 | >>> y 35 | 2 36 | >>> x, y #输出的是tuple 37 | (1, 2) 38 | >>> [x, y] #这就是一个list 39 | [1, 2] 40 | 41 | >>> [a, b] = [qiwsir, python] 42 | >>> a 43 | 1 44 | >>> b 45 | 2 46 | >>> a, b 47 | (1, 2) 48 | >>> [a, b] 49 | [1, 2] 50 | ``` 51 | 换一种方式,以上两种赋值方法交叉组合一下: 52 | ```python 53 | >>> [c, d] = qiwsir, python 54 | >>> c 55 | 1 56 | >>> d 57 | 2 58 | >>> c, d 59 | (1, 2) 60 | >>> f, g = [qiwsir, python] 61 | >>> f 62 | 1 63 | >>> g 64 | 2 65 | >>> f, g 66 | (1, 2) 67 | ``` 68 | 居然也行。其实,从这里我们就看出来了,赋值,就是对应着将左边的变量和右边的对象关联起来。 69 | 70 | 有这样一个有趣的问题,如果a=3,b=4,想把这两个变量的值调换一下,也就是a=4,b=3。在有的高级语言中,是要先引入另外一个变量c做为中间中专,就是这样: 71 | 72 | a = 3 73 | b = 4 74 | c = a #即c=3 75 | a = b #a=4 76 | b = c #b=3 77 | 78 | 初学者可能有点糊涂。就是我和你两只手都托着一个箱子,现在我们两个要换一下箱子,但是两个手都被占用了,无法换(当然,要求箱子不能落地,也不要放在桌子上之类的)。于是再找一个名曰张三的人来,他空着两只手,那么我先把箱子给张三,我就空出来了,然后接你的箱子,你的箱子就到我手里了。我的那个箱子现在张三手里呢,你接过来,于是我们两个就换了箱子了。 79 | 80 | 只所以这么啰嗦,就是因为我们两个没有更多的手。但是,这不是python,python有更多的手。她可以这样: 81 | ```python 82 | >>> qiwsir = 100 83 | >>> python = 200 84 | >>> qiwsir, python = python, qiwsir 85 | >>> qiwsir 86 | 200 87 | >>> python 88 | 100 89 | ``` 90 | 有点神奇,python是三头六臂的。 91 | 92 | ## 序列赋值 93 | 94 | 其实上面实验的赋值,本质上就是序列赋值。只不过这里再强化一番罢了。如果左边的变量是序列,右边的对象也是序列,两者将一一对应地进行赋值。 95 | ```python 96 | >>> [a, b, c] = (1, 2, 3) #左右序列一一对应,左边是变量,右边是对象 97 | >>> a 98 | 1 99 | >>> b 100 | 2 101 | >>> c 102 | 3 103 | >>> (a,b,c) = [1,2,3] 104 | >>> a 105 | 1 106 | >>> b 107 | 2 108 | >>> c 109 | 3 110 | >>> [a,b,c] = "qiw" #不要忘记了,str也是序列类型的数据 111 | >>> a 112 | 'q' 113 | >>> b 114 | 'i' 115 | >>> c 116 | 'w' 117 | >>> (a,b,c) = "qiw" 118 | >>> a,c 119 | ('q', 'w') 120 | >>> a,b,c = 'qiw' #与前面等价 121 | >>> a,b 122 | ('q', 'i') 123 | >>> a,b = 'qiw' #报错了,因为左边和右边不是一一对应 124 | Traceback (most recent call last): 125 | File "", line 1, in 126 | ValueError: too many values to unpack 127 | 128 | >>> (a,b),c = "qi","wei" #注意观察,这样的像是是如何对应的 129 | >>> a,b,c 130 | ('q', 'i', 'wei') 131 | >>> string = "qiwsir" 132 | >>> a,b,c = string[0],string[1],string[2] #取切片也一样 133 | >>> a,b,c 134 | ('q', 'i', 'w') 135 | >>> (a,b),c = string[:2],string[2:] 136 | >>> a,b,c 137 | ('q', 'i', 'wsir') 138 | ``` 139 | 从实验中,可以看出,要搞清楚这种眼花缭乱的赋值,就仅仅扣住“一一对应”这个命脉即可。 140 | 141 | 如果看官用python3,在赋值上还有更多有意思的东西呢。不过,本讲座用的还是python2。 142 | -------------------------------------------------------------------------------- /200/203.md: -------------------------------------------------------------------------------- 1 | ## 从格式化表达式到方法 2 | 3 | [上一讲](./202.md),主要介绍了用%表达的一种输出格式化表达式。在那一讲最后又拓展了一点东西,拓展的那点,名曰:格式化方法。因为它知识上是使用了str的__format__方法。 4 | 5 | 现在我们就格式化方法做一个详细一点的交代。 6 | 7 | ##基本的操作 8 | 9 | 所谓格式化方法,就是可以先建立一个输出字符串的模板,然后用format来填充模板的内容。 10 | 11 | >>> #先做一个字符串模板 12 | >>> template = "My name is {0}. My website is {1}. I am writing {2}." 13 | 14 | >>> #用format依次对应模板中的序号内容 15 | >>> template.format("qiwsir","qiwsir.github.io","python") 16 | 'My name is qiwsir. My website is qiwsir.github.io. I am writing python.' 17 | 18 | 当然,上面的操作如果你要这样做,也是可以的: 19 | 20 | >>> "My name is {0}. My website is {1}. I am writing {2}.".format("qiwsir","qiwsir.github.io","python") 21 | 'My name is qiwsir. My website is qiwsir.github.io. I am writing python.' 22 | 23 | 这些,跟用%写的表达式没有什么太大的区别。不过看官别着急,一般小孩子都区别不到,长大了才有区别的。慢慢看,慢慢实验。 24 | 25 | 除了可以按照对应顺序(类似占位符了)填充模板中的位置之外,还能这样,用关键字来指明所应该田中的内容。 26 | 27 | >>> template = "My name is {name}. My website is {site}" 28 | >>> template.format(site='qiwsir.github.io', name='qiwsir') 29 | 'My name is qiwsir. My website is qiwsir.github.io' 30 | 31 | 关键词所指定的内容,也不一定非是str,其它的数据类型也可以。此外,关键词和前面的位置编号,还可以混用。比如: 32 | 33 | >>> "{number} is in {all}. {0} are my number.".format("seven",number=7,all=[1,2,3,4,5,6,7,8,9,0]) 34 | '7 is in [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]. seven are my number.' 35 | 36 | 是不是开始感觉有点意思了?看输出结果,就知道,经过format方法得到是一个新的str。 37 | 38 | ##序列对象的偏移量 39 | 40 | 有这样一个要求:在输出中,显示出一个单词的第一个字母和第三个个字母。比如单词python,要告诉看官,第一字母是p,第三个字母是t。 41 | 42 | 这个问题并不难。实现方法也不少,这里主要是要展示一下偏移量在format中的应用。 43 | 44 | >>> template = "First={0[0]}, Third={0[2]}" 45 | >>> template.format(word) 46 | 'First=p, Third=t' 47 | 48 | list也是序列类型的,其偏移量也可。 49 | 50 | >>> word_lst = list(word) 51 | >>> word_lst 52 | ['p', 'y', 't', 'h', 'o', 'n'] 53 | >>> template 54 | 'First={0[0]}, Third={0[2]}' 55 | >>> template.format(word_lst) 56 | 'First=p, Third=t' 57 | 58 | 对上面的综合一下,稍微啰嗦一点的实验: 59 | 60 | >>> template = "The word is {0}, Its first is {0[0]}. Another word is {1}, Its second is {1[1]}." 61 | >>> template.format("python","learn") 62 | 'The word is python, Its first is p. Another word is learn, Its second is e.' 63 | 64 | >>> "{name}\'s first is {name[0]}".format(name="qiwsir") #指定关键词的值的偏移量 65 | "qiwsir's first is q" 66 | 67 | 值得注意的是,偏移量在序列类型的数据中,因为可以是负数,即能够从右边开始计数。 68 | 69 | >>> word 70 | 'python' 71 | >>> word[-1] 72 | 'n' 73 | >>> word[-2] 74 | 'o' 75 | 76 | 但是,在模板中,无法使用负数的偏移量。 77 | 78 | >>> "First={0[0]}, End={0[-1]}".format(word) #报错 79 | Traceback (most recent call last): 80 | File "", line 1, in 81 | TypeError: string indices must be integers, not str 82 | 83 | >>> "First={0[0]}, End={0[5]}".format(word) #把-1改为5就可以了。 84 | 'First=p, End=n' 85 | 86 | 当然,放到模板外面是完全可行的。这样就好了: 87 | 88 | >>> "First={0}, End={1}".format(word[0],word[-1]) 89 | 'First=p, End=n' 90 | 91 | ##dictionary的键 92 | 93 | 直接上实验,先观察,再得结论 94 | 95 | >>> myinfo 96 | {'website': 'qiwsir.github.io', 'name': 'qiwsir', 'room': 703} 97 | >>> template = "I am {0[name]}" 98 | >>> template.format(myinfo) 99 | 'I am qiwsir' 100 | >>> template = "I am {0[name]}. My QQ is {qq}" 101 | >>> template.format(myinfo,qq="26066913") 102 | 'I am qiwsir. My QQ is 26066913' 103 | 104 | 位置后面跟键,就能得到format的参数中字典的键对应的值。太罗嗦了吧,看例子就明白了。出了根据位置得到,还能够根据关键词得到: 105 | 106 | >>> myinfo 107 | {'website': 'qiwsir.github.io', 'name': 'qiwsir', 'room': 703} 108 | >>> "my website is {info[website]}, and I like {0}".format("python",info=myinfo) #关键词info引用的是一个字典 109 | 'my website is qiwsir.github.io, and I like python' 110 | 111 | ##模板中添加属性 112 | 113 | 看标题不懂在说什么。那就看实验吧。 114 | 115 | >>> import math 116 | >>> "PI is {PI.pi}".format(PI=math) 117 | 'PI is 3.14159265359' 118 | 119 | 这是用关键词,下面换个稍微复杂点,用位置的。 120 | 121 | >>> import sys,math 122 | >>> 'PI is {0.pi}. My lptop runs {1.platform}'.format(math,sys) 123 | 'PI is 3.14159265359. My lptop runs linux2' 124 | 125 | 看官理解了吧。 126 | 127 | ##其它进制 128 | 129 | 在这个世界上的数学领域,除了有我们常常用到的十进制、十二进制(几点了,这是你我常用到的,钟表面就是12进制)、六十进制(这个你也熟悉的)外,还有别的进制,比如二进制、八进制、十六进制等等。此处不谈进制问题,有兴趣详细了解,请各自google。不过,进制的确在计算机上很重要的。因为机器在最底层是用二进制的。 130 | 131 | 这里只是说明一下输出时候的进制问题。 132 | 133 | >>> "{0:X}, {1:o}, {2:b}".format(255,255,255) 134 | 'FF, 377, 11111111' 135 | 136 | - X:十六进制,Hex 137 | - o:八进制,octal 138 | - b:二进制,binary 139 | 140 | 顺便补充,对于数的格式化方法输出和格式化表达式一样,就不赘述了。 141 | 142 | 在格式化方法中,还能够指定字符宽度,左右对齐等简单排版格式,不过,在我的经验中,这些似乎用的不怎么多。如果看官需要,可以google或者到官方文档看看即可。 143 | 144 | 关于格式化表达式和格式化方法,有的人进行了不少比较,有的人说用这个,有的人倾向用那个。我的建议是,你用哪个顺手就用哪个。切忌门派之见呀。不过,有人传说格式化表达式可能在将来某个版本中废除。那是将来的事情,将来再说好了。现在,你就捡着顺手的用吧。 145 | -------------------------------------------------------------------------------- /200/204.md: -------------------------------------------------------------------------------- 1 | ## 复习if语句 2 | 3 | 看官是否记得,在上一部分的时候,有一讲专门介绍if语句的:[从if开始语句的征程](./111.md)。在学习if语句的时候,对python编程的基础知识了解的还不是很多,或许没有做什么太复杂的东西。本讲,要对它进行一番复习,通过复习提高一下。如果此前有的东西忘记了,建议首先回头,看看前面那讲。 4 | 5 | ##基本语句结构 6 | 7 | if 判断条件1: 8 | 执行语句1…… 9 | elif 判断条件2: 10 | 执行语句2…… 11 | elif 判断条件3: 12 | 执行语句3…… 13 | else: 14 | 执行语句4…… 15 | 16 | 只有当“判断条件”的值是True的时候,才执行下面的执行语句。 17 | 18 | 那么,在python中,怎么知道一个判断条件是不是真呢?这个问题我们在[眼花缭乱的运算符](./110.md)中已经讲解了一种数据类型:布尔类型。可以通过一个内置函数bool()来判断一个条件的结果True还是False。看看下面的例子,是不是能够理解bool()的判断规则? 19 | 20 | >>> bool("") 21 | False 22 | >>> bool(0) 23 | False 24 | >>> bool('none') 25 | True 26 | >>> bool(False) 27 | False 28 | >>> bool("False") 29 | True 30 | >>> bool(True) 31 | True 32 | >>> bool("True") 33 | True 34 | >>> bool(3>4) 35 | False 36 | >>> bool("b">"a") 37 | True 38 | >>> bool(not "") 39 | True 40 | >>> bool(not True) 41 | False 42 | 43 | 忘记了怎么办?看下面的语句: 44 | 45 | if 忘记: 46 | 复习-->眼花缭乱的运算符一讲 47 | 48 | 在执行语句中,其实不一定非要把bool()写上的。如同这样: 49 | 50 | >>> x = 9 51 | 52 | >>> if bool(x>7): #条件为True则执行下面的 53 | ... print "%d more than 7"%x 54 | ... else: 55 | ... print "%d not more than 7"%x 56 | ... 57 | 9 more than 7 58 | 59 | >>> if x>7: 60 | ... print "%d more than 7"%x 61 | ... else: 62 | ... print "%d not more than 7"%x 63 | ... 64 | 9 more than 7 65 | 66 | 以上两个写法是等效的,但是,在实际的编程中,我们不用if bool(x>7)的格式,而是使用if x>7的样式,还要特别提醒,如果写成if (x>7),用一个括号把条件表达式括起来,是不是可以呢?可以,但也不是python提倡的。 67 | 68 | >>> if (x>7): #不提倡这么写,这不是python风格 69 | ... print "%d more than 7"%x 70 | ... 71 | 9 more than 7 72 | 73 | ##拉出来溜溜 74 | 75 | 平时总有人在不服气的时候说“是骡子是马,拉出来溜溜”,赵本山有一句名言“走两步”。其本质都是说“光说不练是假把式”。今天收到一个朋友的邮件,也询问,在学习python的时候,记不住python的内容。其实不用记,我在前面的课程中已经反复讲过了。但是,在应用中,会越来越熟练。 76 | 77 | 下面就做一个练习,要求是: 78 | 79 | 1. 接收任何字符和数字的输入 80 | 2. 判断输入的内容,如果不是整数是字符,就告诉给用户;如果是小数,也告诉用户 81 | 3. 如果输入的是整数,判断这个整数是奇数还是偶数,并且告诉给用户 82 | 83 | 在这个练习中,显然要对输入的内容进行判断,以下几点需要看官注意: 84 | 85 | - 通过raw_input()得到的输入内容,都是str类型 86 | - 要判断一个字符串是否是由纯粹数字组成,可以使用str.isdigit()(建议看官查看该内置函数官方文档) 87 | 88 | 下面的代码是一个参考: 89 | 90 | #! /usr/bin/env python 91 | #coding:utf-8 92 | 93 | print "请输入字符串,然后按下回车键:" 94 | 95 | user_input = raw_input() 96 | 97 | result = user_input.isdigit() 98 | 99 | if not result: 100 | print "您输入的不完全是数字" 101 | 102 | elif int(user_input)%2==0: 103 | print "您输入的是一个偶数" 104 | elif int(user_input)%2!=0: 105 | print "您输入的是一个奇数" 106 | else: 107 | print "您没有输入什么呢吧" 108 | 109 | 特别提醒列为,这个代码不是非常完善的,还有能够修改的地方,看官能否完善之? 110 | 111 | 再来一个如何? 112 | 113 | 已知一个由整数构成的list,从中跳出奇数和偶数,并且各放在一个list中。 114 | 115 | 请看官在看下面的参考代码之前,自己写一写。 116 | 117 | #!/usr/bin/env python 118 | #coding:utf-8 119 | 120 | import random 121 | 122 | numbers = [random.randint(1,100) for i in range(20)] #以list解析的方式得到随机的list 123 | 124 | odd = [] 125 | even = [] 126 | 127 | for x in numbers: 128 | if x%2==0: 129 | even.append(x) 130 | else: 131 | odd.append(x) 132 | 133 | print numbers 134 | print "odd:",odd 135 | print "even:",even 136 | 137 | 用这个例子演示一下if在list解析中的应用。看能不能继续改进一些呢? 138 | 139 | 可以将循环的那部分用下面的list解析代替 140 | 141 | #!/usr/bin/env python 142 | #coding:utf-8 143 | 144 | import random 145 | 146 | numbers = [random.randint(1,100) for i in range(20)] #以list解析的方式得到随机的list 147 | 148 | odd = [x for x in numbers if x%2!=0] 149 | even = [x for x in numbers if x%2==0] 150 | 151 | print numbers 152 | print "odd:",odd 153 | print "even:",even 154 | 155 | ##一个有趣的赋值 156 | 157 | 对赋值,看官应该比较熟悉了吧,如果要复习,请看《[赋值,简单也不简单]》(./127.md)以及《[正规地说一句]》(./201.md)的相关内容。 158 | 159 | 这里说的有趣赋值是什么样子的呢?请看: 160 | 161 | >>> name = "qiwsir" if "laoqi" else "github" 162 | >>> name 163 | 'qiwsir' 164 | >>> name = 'qiwsir' if "" else "python" 165 | >>> name 166 | 'python' 167 | >>> name = "qiwsir" if "github" else "" 168 | >>> name 169 | 'qiwsir' 170 | 171 | 总结一下:A = Y if X else Z 172 | 173 | 什么意思,结合前面的例子,可以看出: 174 | 175 | - 如果X为真,那么就执行A=Y 176 | - 如果X为假,就执行A=Z 177 | 178 | 再看看上面的例子,是不是这样执行呢? 179 | 180 | if语句似乎简单,但是在编程时间中常用到。勤加练习吧。 181 | -------------------------------------------------------------------------------- /200/205.md: -------------------------------------------------------------------------------- 1 | ## 用while来循环 2 | 3 | while,翻译成中文是“当...的时候”,这个单词在英语中,常常用来做为时间状语,while ... someone do somthing,这种类型的说法是有的。在python中,它也有这个含义,不过有点区别的是,“当...时候”这个条件成立在一段范围或者时间间隔内,从而在这段时间间隔内让python做好多事情。就好比这样一段情景: 4 | 5 | while 年龄大于60岁:-------->当年龄大于60岁的时候 6 | 退休 -------->凡是符合上述条件就执行的动作 7 | 8 | 展开想象,如果制作一道门,这道门就是用上述的条件调控开关的,假设有很多人经过这个们,报上年龄,只要年龄大于60,就退休(门打开,人可以出去),一个接一个地这样循环下去,突然有一个人年龄是50,那么这个循环在他这里就停止,也就是这时候他不满足条件了。 9 | 10 | 这就是while循环。写一个严肃点的流程,可以看下图: 11 | 12 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/20501.png) 13 | 14 | ##再做猜数字游戏 15 | 16 | 本教程有一讲,是跟看官一同[做一个小游戏](../129.md),在里面做了一个猜数的游戏,当时遇到了一个问题,就是只能猜一两次,如果猜不到,程序就不能继续运行了。 17 | 18 | 前不久,有一个在校的大学生朋友(他叫李航),给我发邮件,让我看了他做的游戏,能够实现多次猜数,直到猜中为止。这是一个多么喜欢学习的大学生呀。 19 | 20 | 我在这里将他写的程序恭录于此,单元李航同学不要见怪,如果李航同学认为此举侵犯了自己的知识产权,可以告知我,我马上撤下此代码。 21 | 22 | #! /usr/bin/env python 23 | #coding:UTF-8 24 | 25 | import random 26 | 27 | i=0 28 | while i < 4: 29 | print'********************************' 30 | num = input('请您输入0到9任一个数:') #李同学用的是python3 31 | 32 | xnum = random.randint(0,9) 33 | 34 | x = 3 - i 35 | 36 | if num == xnum: 37 | print'运气真好,您猜对了!' 38 | break 39 | elif num > xnum: 40 | print'''您猜大了!\n哈哈,正确答案是:%s\n您还有%s次机会!''' %(xnum,x) 41 | elif num < xnum: 42 | print'''您猜小了!\n哈哈,正确答案是:%s\n您还有%s次机会!''' %(xnum,x) 43 | print'********************************' 44 | 45 | i += 1 46 | 47 | 我们就用这段程序来分析一下,首先看while i<4,这是程序中为猜测限制了次数,最大是三次,请看官注意,在while的循环体中的最后一句:i +=1,这就是说每次循环到最后,就给i增加1,当bool(i<4)=False的时候,就不再循环了。 48 | 49 | 当bool(i<4)=True的时候,就执行循环体内的语句。在循环体内,让用户输入一个整数,然后程序随机选择一个整数,最后判断随机生成的数和用户输入的数是否相等,并且用if语句判断三种不同情况。 50 | 51 | 根据上述代码,看官看看是否可以修改? 52 | 53 | 为了让用户的体验更爽,不妨把输入的整数范围扩大,在1到100之间吧。 54 | 55 | num_input = raw_input("please input one integer that is in 1 to 100:") #我用的是python2.7,在输入指令上区别于李同学 56 | 57 | 程序用num_input变量接收了输入的内容。但是,请列位看官一定要注意,看到这里想睡觉的要打起精神了,我要分享一个多年编程经验,请牢记:**任何用户输入的内容都是不可靠的。**这句话含义深刻,但是,这里不做过多的解释,需要各位在随后的编程生涯中体验了。为此,我们要检验用户输入的是否符合我们的要求,我们要求用户输入的是1到100之间的整数,那么就要做如下检验: 58 | 59 | 1. 输入的是否是整数 60 | 2. 如果是整数,是否在1到100之间。 61 | 62 | 为此,要做: 63 | 64 | if not num_input.isdigit(): #str.isdigit()是用来判断字符串是否纯粹由数字组成 65 | print "Please input interger." 66 | elif int(num_input)<0 and int(num_input)>=100: 67 | print "The number should be in 1 to 100." 68 | else: 69 | pass #这里用pass,意思是暂时省略,如果满足了前面提出的要求,就该执行此处语句 70 | 71 | 再看看李航同学的程序,在循环体内产生一个随机的数字,这样用户每次输入,面对的都是一个新的随机数字。这样的猜数字游戏难度太大了。我希望是程序产生一个数字,直到猜中,都是这个数字。所以,要把产生随机数字这个指令移动到循环之前。 72 | 73 | import random 74 | 75 | number = random.randint(1,100) 76 | 77 | while True: #不限制用户的次数了 78 | ... 79 | 80 | 观察李同学的程序,还有一点需要向列位显明的,那就是在条件表达式中,两边最好是同种类型数据,上面的程序中有:num>xnum样式的条件表达式,而一边是程序生成的int类型数据,一边是通过输入函数得到的str类型数据。在某些情况下可以运行,为什么?看官能理解吗?都是数字的时候,是可以的。但是,这样不好。 81 | 82 | 那么,按照这种思路,把这个猜数字程序重写一下: 83 | 84 | #!/usr/bin/env python 85 | #coding:utf-8 86 | 87 | import random 88 | 89 | number = random.randint(1,101) 90 | 91 | guess = 0 92 | 93 | while True: 94 | 95 | num_input = raw_input("please input one integer that is in 1 to 100:") 96 | guess +=1 97 | 98 | if not num_input.isdigit(): 99 | print "Please input interger." 100 | elif int(num_input)<0 or int(num_input)>=100: 101 | print "The number should be in 1 to 100." 102 | else: 103 | if number==int(num_input): 104 | print "OK, you are good.It is only %d, then you successed."%guess 105 | break 106 | elif number>int(num_input): 107 | print "your number is more less." 108 | elif number>> name_str = "qiwsir" 12 | >>> for i in name_str: #可以对str使用for循环 13 | ... print i, 14 | ... 15 | q i w s i r 16 | 17 | >>> name_list = list(name_str) 18 | >>> name_list 19 | ['q', 'i', 'w', 's', 'i', 'r'] 20 | >>> for i in name_list: #对list也能用 21 | ... print i, 22 | ... 23 | q i w s i r 24 | 25 | >>> name_set = set(name_str) #set还可以用 26 | >>> name_set 27 | set(['q', 'i', 's', 'r', 'w']) 28 | >>> for i in name_set: 29 | ... print i, 30 | ... 31 | q i s r w 32 | 33 | >>> name_tuple = tuple(name_str) 34 | >>> name_tuple 35 | ('q', 'i', 'w', 's', 'i', 'r') 36 | >>> for i in name_tuple: #tuple也能呀 37 | ... print i, 38 | ... 39 | q i w s i r 40 | 41 | >>> name_dict={"name":"qiwsir","lang":"python","website":"qiwsir.github.io"} 42 | >>> for i in name_dict: #dict也不例外 43 | ... print i,"-->",name_dict[i] 44 | ... 45 | lang --> python 46 | website --> qiwsir.github.io 47 | name --> qiwsir 48 | ``` 49 | 除了上面的数据类型之外,对文件也能够用for,这在前面有专门的[《不要红头文件》](./130.md)两篇文章讲解有关如何用for来读取文件对象的内容。看官若忘记了,可去浏览。 50 | 51 | for在list解析中,用途也不可小觑,这在讲解list解析的时候,也已说明,不过,还是再复习一下为好,所谓学而时常复习之,不亦哈哈乎。 52 | 53 | >>> one = range(1,9) 54 | >>> one 55 | [1, 2, 3, 4, 5, 6, 7, 8] 56 | >>> [ x for x in one if x%2==0 ] 57 | [2, 4, 6, 8] 58 | 59 | 什么也不说了,list解析的强悍,在以后的学习中会越来越体会到的,佩服佩服呀。 60 | 61 | 列位如果用python3,会发现字典解析、元组解析也是奇妙的呀。 62 | 63 | 要上升一个档次,就得进行概括。将上面所说的for循环,概括一下,就是下图所示: 64 | 65 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/20601.png) 66 | 67 | 用一个文字表述: 68 | 69 | for iterating_var in sequence: 70 | statements 71 | 72 | iterating_var是对象sequence的迭代变量,也就是sequence必须是一个能够有某种序列的对象,特别注意没某种序列,就是说能够按照一定的脚标获取元素。当然,文件对象属于序列,我们没有用脚标去获取每行,如果把它读取出来,因为也是一个str,所以依然可以用脚标读取其内容。 73 | 74 | ##zip 75 | 76 | zip是什么东西?在交互模式下用help(zip),得到官方文档是: 77 | 78 | >zip(...) 79 | >zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)] 80 | 81 | >Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence. 82 | 83 | 通过实验来理解上面的文档: 84 | 85 | >>> a = "qiwsir" 86 | >>> b = "github" 87 | >>> zip(a,b) 88 | [('q', 'g'), ('i', 'i'), ('w', 't'), ('s', 'h'), ('i', 'u'), ('r', 'b')] 89 | >>> c = [1,2,3] 90 | >>> d = [9,8,7,6] 91 | >>> zip(c,d) 92 | [(1, 9), (2, 8), (3, 7)] 93 | >>> e = (1,2,3) 94 | >>> f = (9,8) 95 | >>> zip(e,f) 96 | [(1, 9), (2, 8)] 97 | >>> m = {"name","lang"} 98 | >>> n = {"qiwsir","python"} 99 | >>> zip(m,n) 100 | [('lang', 'python'), ('name', 'qiwsir')] 101 | >>> s = {"name":"qiwsir"} 102 | >>> t = {"lang":"python"} 103 | >>> zip(s,t) 104 | [('name', 'lang')] 105 | 106 | zip是一个内置函数,它的参数必须是某种序列数据类型,如果是字典,那么键视为序列。然后将序列对应的元素依次组成元组,做为一个list的元素。 107 | 108 | 下面是比较特殊的情况,参数是一个序列数据的时候,生成的结果样子: 109 | 110 | >>> a 111 | 'qiwsir' 112 | >>> c 113 | [1, 2, 3] 114 | >>> zip(c) 115 | [(1,), (2,), (3,)] 116 | >>> zip(a) 117 | [('q',), ('i',), ('w',), ('s',), ('i',), ('r',)] 118 | 119 | 这个函数和for连用,就是实现了: 120 | 121 | >>> c 122 | [1, 2, 3] 123 | >>> d 124 | [9, 8, 7, 6] 125 | >>> for x,y in zip(c,d): #实现一对一对地打印 126 | ... print x,y 127 | ... 128 | 1 9 129 | 2 8 130 | 3 7 131 | >>> for x,y in zip(c,d): #把两个list中的对应量上下相加。 132 | ... print x+y 133 | ... 134 | 10 135 | 10 136 | 10 137 | 138 | 上面这个相加的功能,如果不用zip,还可以这么写: 139 | 140 | >>> length = len(c) if len(c)>> for i in range(length): 142 | ... print c[i]+d[i] 143 | ... 144 | 10 145 | 10 146 | 10 147 | 148 | 以上两种写法那个更好呢?前者?后者?哈哈。我看差不多了。还可以这么做呢: 149 | 150 | >>> [ x+y for x,y in zip(c,d) ] 151 | [10, 10, 10] 152 | 153 | 前面多次说了,list解析强悍呀。当然,还可以这样的: 154 | 155 | >>> [ c[i]+d[i] for i in range(length) ] 156 | [10, 10, 10] 157 | 158 | for循环语句在后面还会经常用到,其实前面已经用了很多了。所以,看官应该不感到太陌生。 159 | -------------------------------------------------------------------------------- /200/209.md: -------------------------------------------------------------------------------- 1 | ## 大话题小函数(1) 2 | 3 | 开篇就要提到一个大的话题:编程范型。什么是编程范型?引用[维基百科中的解释](http://zh.wikipedia.org/wiki/%E7%BC%96%E7%A8%8B%E8%8C%83%E5%9E%8B): 4 | 5 | >编程范型或编程范式(英语:Programming paradigm),(范即模范之意,范式即模式、方法),是一类典型的编程风格,是指从事软件工程的一类典型的风格(可以对照方法学)。如:函数式编程、程序编程、面向对象编程、指令式编程等等为不同的编程范型。 6 | 7 | >编程范型提供了(同时决定了)程序员对程序执行的看法。例如,在面向对象编程中,程序员认为程序是一系列相互作用的对象,而在函数式编程中一个程序会被看作是一个无状态的函数计算的串行。 8 | 9 | >正如软件工程中不同的群体会提倡不同的“方法学”一样,不同的编程语言也会提倡不同的“编程范型”。一些语言是专门为某个特定的范型设计的(如Smalltalk和Java支持面向对象编程,而Haskell和Scheme则支持函数式编程),同时还有另一些语言支持多种范型(如Ruby、Common Lisp、Python和Oz)。 10 | 11 | >编程范型和编程语言之间的关系可能十分复杂,由于一个编程语言可以支持多种范型。例如,C++设计时,支持过程化编程、面向对象编程以及泛型编程。然而,设计师和程序员们要考虑如何使用这些范型元素来构建一个程序。一个人可以用C++写出一个完全过程化的程序,另一个人也可以用C++写出一个纯粹的面向对象程序,甚至还有人可以写出杂揉了两种范型的程序。 12 | 13 | 不管看官是初学者还是老油条,都建议将上面这段话认真读完,不管理解还是不理解,总能有点感觉的。 14 | 15 | 这里推荐一篇文章,这篇文章来自网络:[《主要的编程范型》](https://github.com/qiwsir/ITArticles/blob/master/IT/%E4%B8%BB%E8%A6%81%E7%9A%84%E7%BC%96%E7%A8%8B%E8%8C%83%E5%9E%8B.md) 16 | 17 | 扯了不少编程范型,今天本讲要讲什么呢?今天要介绍几个python中的小函数,这几个函数都是从函数式编程借鉴过来的,它们就是: 18 | 19 | filter、map、reduce、lambda、yield 20 | 21 | 有了它们,最大的好处是程序更简洁;没有它们,程序也可以用别的方式实现,只不过麻烦一些罢了。所以,还是能用则用之吧。 22 | 23 | ##lambda 24 | 25 | lambda函数,是一个只用一行就能解决问题的函数,听着是多么诱人呀。看下面的例子: 26 | 27 | >>> def add(x): #定义一个函数,将输入的变量增加3,然后返回增加之后的值 28 | ... x +=3 29 | ... return x 30 | ... 31 | >>> numbers = range(10) 32 | >>> numbers 33 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #有这样一个list,想让每个数字增加3,然后输出到一个新的list中 34 | 35 | >>> new_numbers = [] 36 | >>> for i in numbers: 37 | ... new_numbers.append(add(i)) #调用add()函数,并append到list中 38 | ... 39 | >>> new_numbers 40 | [3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 41 | 42 | 在这个例子中,add()只是一个中间操作。当然,上面的例子完全可以用别的方式实现。比如: 43 | 44 | >>> new_numbers = [ i+3 for i in numbers ] 45 | >>> new_numbers 46 | [3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 47 | 48 | 首先说明,这种列表解析的方式是非常非常好的。 49 | 50 | 但是,我们偏偏要用lambda这个函数替代add(x),如果看官和我一样这么偏执,就可以: 51 | 52 | >>> lam = lambda x:x+3 53 | >>> n2 = [] 54 | >>> for i in numbers: 55 | ... n2.append(lam(i)) 56 | ... 57 | >>> n2 58 | [3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 59 | 60 | 这里的lam就相当于add(x),请看官对应一下,这一行lambda x:x+3就完成add(x)的三行(还是两行?),特别是最后返回值。还可以写这样的例子: 61 | 62 | >>> g = lambda x,y:x+y #x+y,并返回结果 63 | >>> g(3,4) 64 | 7 65 | >>> (lambda x:x**2)(4) #返回4的平方 66 | 16 67 | 68 | 通过上面例子,总结一下lambda函数的使用方法: 69 | 70 | - 在lambda后面直接跟变量 71 | - 变量后面是冒号 72 | - 冒号后面是表达式,表达式计算结果就是本函数的返回值 73 | 74 | 为了简明扼要,用一个式子表示是必要的: 75 | 76 | lambda arg1, arg2, ...argN : expression using arguments 77 | 78 | 要特别提醒看官:虽然lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值,但是**lambda 函数不能包含命令,包含的表达式不能超过一个。不要试图向 lambda 函数中塞入太多的东西;如果你需要更复杂的东西,应该定义一个普通函数,然后想让它多长就多长。** 79 | 80 | 就lambda而言,它并没有给程序带来性能上的提升,它带来的是代码的简洁。比如,要打印一个list,里面依次是某个数字的1次方,二次方,三次方,四次方。用lambda可以这样做: 81 | 82 | >>> lamb = [ lambda x:x,lambda x:x**2,lambda x:x**3,lambda x:x**4 ] 83 | >>> for i in lamb: 84 | ... print i(3), 85 | ... 86 | 3 9 27 81 87 | 88 | lambda做为一个单行的函数,在编程实践中,可以选择使用。根据我的经验,尽量少用,因为它或许更多地是为减少单行函数的定义而存在的。 89 | 90 | ##map 91 | 92 | 先看一个例子,还是上面讲述lambda的时候第一个例子,用map也能够实现: 93 | 94 | >>> numbers 95 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #把列表中每一项都加3 96 | 97 | >>> map(add,numbers) #add(x)是上面讲述的那个函数,但是这里只引用函数名称即可 98 | [3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 99 | 100 | >>> map(lambda x: x+3,numbers) #用lambda当然可以啦 101 | [3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 102 | 103 | map()是python的一个内置函数,它的基本样式是:map(func, seq),func是一个函数,seq是一个序列对象。在执行的时候,序列对象中的每个元素,按照从左到右的顺序,依次被取出来,并塞入到func那个函数里面,并将func的返回值依次存到一个list中。 104 | 105 | 在应用中,map的所能实现的,也可以用别的方式实现。比如: 106 | 107 | >>> items = [1,2,3,4,5] 108 | >>> squared = [] 109 | >>> for i in items: 110 | ... squared.append(i**2) 111 | ... 112 | >>> squared 113 | [1, 4, 9, 16, 25] 114 | 115 | >>> def sqr(x): return x**2 116 | ... 117 | >>> map(sqr,items) 118 | [1, 4, 9, 16, 25] 119 | 120 | >>> map(lambda x: x**2,items) 121 | [1, 4, 9, 16, 25] 122 | 123 | >>> [ x**2 for x in items ] #这个我最喜欢了,一般情况下速度足够快,而且可读性强 124 | [1, 4, 9, 16, 25] 125 | 126 | 条条大路通罗马,以上方法,在编程中,自己根据需要来选用啦。 127 | 128 | 在以上感性认识的基础上,在来浏览有关map()的官方说明,能够更明白一些。 129 | 130 | >map(function, iterable, ...) 131 | 132 | >Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. If one iterable is shorter than another it is assumed to be extended with None items. If function is None, the identity function is assumed; if there are multiple arguments, map() returns a list consisting of tuples containing the corresponding items from all iterables (a kind of transpose operation). The iterable arguments may be a sequence or any iterable object; the result is always a list. 133 | 134 | 理解要点: 135 | 136 | - 对iterable中的每个元素,依次应用function的方法(函数)(这本质上就是一个for循环)。 137 | - 将所有结果返回一个list。 138 | - 如果参数很多,则对么个参数并行执行function。 139 | 140 | 例如: 141 | 142 | >>> lst1 = [1,2,3,4,5] 143 | >>> lst2 = [6,7,8,9,0] 144 | >>> map(lambda x,y: x+y, lst1,lst2) #将两个列表中的对应项加起来,并返回一个结果列表 145 | [7, 9, 11, 13, 5] 146 | 147 | 请看官注意了,上面这个例子如果用for循环来写,还不是很难,如果扩展一下,下面的例子用for来改写,就要小心了: 148 | 149 | >>> lst1 = [1,2,3,4,5] 150 | >>> lst2 = [6,7,8,9,0] 151 | >>> lst3 = [7,8,9,2,1] 152 | >>> map(lambda x,y,z: x+y+z, lst1,lst2,lst3) 153 | [14, 17, 20, 15, 6] 154 | 155 | 这才显示出map的简洁优雅。 156 | 157 | 预告:下一讲详解reduce和filter 158 | -------------------------------------------------------------------------------- /200/210.md: -------------------------------------------------------------------------------- 1 | ## 大话题小函数(2) 2 | 3 | 上一讲和本讲的标题是“大话题小函数”,所谓大话题,就是这些函数如果溯源,都会找到听起来更高大上的东西。这种思维方式绝对我坚定地继承了中华民族的优良传统的。自从天朝的臣民看到英国人开始踢足球,一直到现在所谓某国勃起了,都一直在试图论证足球起源于该朝的前前前朝的某国时代,并且还搬出了那时候的一个叫做高俅的球星来论证,当然了,勃起的某国是挡不住该国家队在世界杯征程上的阳痿,只能用高俅来意淫一番了。这种思维方式,我是坚定地继承,因为在我成长过程中,它一直被奉为优良传统。阿Q本来是姓赵的,和赵老爷是本家,比秀才要长三辈,虽然被赵老爷打了嘴。 4 | 5 | 废话少说,书接前文,已经研究了map,下面来看reduce。 6 | 7 | 忍不住还得来点废话。不知道看官是不是听说过MapReduc,如果没有,那么Hadoop呢?如果还没有,就google一下。下面是我从[维基百科](http://zh.wikipedia.org/wiki/MapReduce)上抄下来的,共赏之。 8 | 9 | >MapReduce是Google提出的一个软件架构,用于大规模数据集(大于1TB)的并行运算。概念“Map(映射)”和“Reduce(化简)”,及他们的主要思想,都是从函数式编程语言借来的,还有从矢量编程语言借来的特性。 10 | 11 | 不用管是不是看懂,总之又可以用开头的思想意淫一下了,原来今天要鼓捣的这个reduce还跟大数据有关呀。不管怎么样,你有梦一般的感觉就行。 12 | 13 | ##reduce 14 | 15 | 回到现实,清醒一下,继续敲代码: 16 | 17 | >>> reduce(lambda x,y: x+y,[1,2,3,4,5]) 18 | 15 19 | 20 | 请看官仔细观察,是否能够看出是如何运算的呢?画一个图: 21 | 22 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/21001.png) 23 | 24 | 还记得map是怎么运算的吗?忘了?看代码: 25 | 26 | >>> list1 = [1,2,3,4,5,6,7,8,9] 27 | >>> list2 = [9,8,7,6,5,4,3,2,1] 28 | >>> map(lambda x,y: x+y, list1,list2) 29 | [10, 10, 10, 10, 10, 10, 10, 10, 10] 30 | 31 | 看官对比一下,就知道两个的区别了。原来map是上下运算,reduce是横着逐个元素进行运算。 32 | 33 | 权威的解释来自官网: 34 | 35 | >reduce(function, iterable[, initializer]) 36 | 37 | >Apply function of two arguments cumulatively to the items of iterable, from left to right, so as to reduce the iterable to a single value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates ((((1+2)+3)+4)+5). The left argument, x, is the accumulated value and the right argument, y, is the update value from the iterable. If the optional initializer is present, it is placed before the items of the iterable in the calculation, and serves as a default when the iterable is empty. If initializer is not given and iterable contains only one item, the first item is returned. Roughly equivalent to: 38 | 39 | def reduce(function, iterable, initializer=None): 40 | it = iter(iterable) 41 | if initializer is None: 42 | try: 43 | initializer = next(it) 44 | except StopIteration: 45 | raise TypeError('reduce() of empty sequence with no initial value') 46 | accum_value = initializer 47 | for x in it: 48 | accum_value = function(accum_value, x) 49 | return accum_value 50 | 51 | 如果用我们熟悉的for循环来做上面reduce的事情,可以这样来做: 52 | 53 | >>> lst = range(1,6) 54 | >>> lst 55 | [1, 2, 3, 4, 5] 56 | >>> r = 0 57 | >>> for i in range(len(lst)): 58 | ... r += lst[i] 59 | ... 60 | >>> r 61 | 15 62 | 63 | for普世的,reduce是简洁的。 64 | 65 | 为了锻炼思维,看这么一个问题,有两个list,a = [3,9,8,5,2],b=[1,4,9,2,6],计算:a[0]*b[0]+a[1]*b[1]+...的结果。 66 | 67 | >>> a 68 | [3, 9, 8, 5, 2] 69 | >>> b 70 | [1, 4, 9, 2, 6] 71 | 72 | >>> zip(a,b) #复习一下zip,下面的方法中要用到 73 | [(3, 1), (9, 4), (8, 9), (5, 2), (2, 6)] 74 | 75 | >>> sum(x*y for x,y in zip(a,b)) #解析后直接求和 76 | 133 77 | 78 | >>> new_list = [x*y for x,y in zip(a,b)] #可以看做是上面方法的分布实施 79 | >>> #这样解析也可以:new_tuple = (x*y for x,y in zip(a,b)) 80 | >>> new_list 81 | [3, 36, 72, 10, 12] 82 | >>> sum(new_list) #或者:sum(new_tuple) 83 | 133 84 | 85 | >>> reduce(lambda sum,(x,y): sum+x*y,zip(a,b),0) #这个方法是在耍酷呢吗? 86 | 133 87 | 88 | >>> from operator import add,mul #耍酷的方法也不止一个 89 | >>> reduce(add,map(mul,a,b)) 90 | 133 91 | 92 | >>> reduce(lambda x,y: x+y, map(lambda x,y: x*y, a,b)) #map,reduce,lambda都齐全了,更酷吗? 93 | 133 94 | 95 | ##filter 96 | 97 | filter的中文含义是“过滤器”,在python中,它就是起到了过滤器的作用。首先看官方说明: 98 | 99 | >filter(function, iterable) 100 | 101 | >Construct a list from those elements of iterable for which function returns true. iterable may be either a sequence, a container which supports iteration, or an iterator. If iterable is a string or a tuple, the result also has that type; otherwise it is always a list. If function is None, the identity function is assumed, that is, all elements of iterable that are false are removed. 102 | 103 | >Note that filter(function, iterable) is equivalent to [item for item in iterable if function(item)] if function is not None and [item for item in iterable if item] if function is None. 104 | 105 | 这次真的不翻译了(好像以往也没有怎么翻译呀),而且也不解释要点了。请列位务必自己阅读上面的文字,并且理解其含义。英语,无论怎么强调都是不过分的,哪怕是做乞丐,说两句英语,没准还可以讨到英镑美元呢。 106 | 107 | 通过下面代码体会: 108 | 109 | >>> numbers = range(-5,5) 110 | >>> numbers 111 | [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4] 112 | 113 | >>> filter(lambda x: x>0, numbers) 114 | [1, 2, 3, 4] 115 | 116 | >>> [x for x in numbers if x>0] #与上面那句等效 117 | [1, 2, 3, 4] 118 | 119 | >>> filter(lambda c: c!='i', 'qiwsir') #能不能对应上面文档说明那句话呢? 120 | 'qwsr' #“If iterable is a string or a tuple, the result also has that type;” 121 | 122 | 至此,用两此介绍了几个小函数,这些函数在对程序的性能提高上,并没有显著或者稳定预期,但是,在代码的简洁上,是有目共睹的。有时候是可以用来秀一秀,彰显python的优雅和自己耍酷。 123 | -------------------------------------------------------------------------------- /200/212.md: -------------------------------------------------------------------------------- 1 | ## 重回函数 2 | 3 | 在本教程的开始部分,就已经引入了函数的概念:[《永远强大的函数》](./106.md),之所以那时候就提到函数,是因为我觉得函数之重要,远远超过一般。这里,重回函数,一是复习,二是要在已经学习的基础上,对函数有更深刻的理解。 4 | 5 | ## 函数的基本结构 6 | 7 | Python中的函数基本结构: 8 | 9 | def 函数名([参数列表]): 10 | 11 | 语句 12 | 13 | 几点说明: 14 | 15 | - 函数名的命名规则要符合python中的命名要求。一般用小写字母和单下划线、数字等组合 16 | - def是函数的开始,这个简写来自英文单词define,显然,就是要定义一个什么东西 17 | - 函数名后面是圆括号,括号里面,可以有参数列表,也可以没有参数 18 | - 千万不要忘记了括号后面的冒号 19 | - 语句,相对于def缩进,按照python习惯,缩进四个空格 20 | 21 | 看简单例子,深入理解上面的要点: 22 | 23 | >>> def name(): #定义一个无参数的函数,只是通过这个函数打印 24 | ... print "qiwsir" #缩进4个空格 25 | ... 26 | >>> name() #调用函数,打印结果 27 | qiwsir 28 | 29 | >>> def add(x,y): #定义一个非常简单的函数 30 | ... return x+y #缩进4个空格 31 | ... 32 | >>> add(2,3) #通过函数,计算2+3 33 | 5 34 | 35 | 注意上面的add(x,y)函数,在这个函数中,没有特别规定参数x,y的类型。其实,这句话本身就是错的,还记得在前面已经多次提到,在python中,变量无类型,只有对象才有类型,这句话应该说成:x,y并没有严格规定其所引用的对象类型。 36 | 37 | 为什么?列位不要忘记了,这里的所谓参数,跟前面说的变量,本质上是一回事。python中不需要提前声明变量,有的语言就需要声明。只有当用到该变量的时候,才建立变量与对象的对应关系,否则,关系不建立。而对象才有不同的类型。那么,在add(x,y)函数中,x,y在引用对象之前,是完全自由的,也就是它们可以引用任何对象,只要后面的运算许可,如果后面的运算不许可,则会报错。 38 | 39 | >>> add("qiw","sir") #这里,x="qiw",y="sir",让函数计算x+y,也就是"qiw"+"sir" 40 | 'qiwsir' 41 | 42 | >>> add("qiwsir",4) 43 | Traceback (most recent call last): 44 | File "", line 1, in 45 | File "", line 2, in add 46 | TypeError: cannot concatenate 'str' and 'int' objects #仔细阅读报错信息,就明白错误之处了 47 | 48 | 从实验结果中发现:x+y的意义完全取决于对象的类型。在python中,将这种依赖关系,称之为**多态**。这是python和其它的静态语言的重要区别。在python中,代码不关心特定的数据类型。 49 | 50 | 对于python中的多态问题,以后还会遇到,这里仅仅以此例子显示一番。请看官要留心注意的:**python中为对象编写接口,而不是为数据类型。** 51 | 52 | 此外,也可以将函数通过赋值语句,与某个变量建立引用关系: 53 | 54 | >>> result = add(3,4) 55 | >>> result 56 | 7 57 | 58 | 在这里,其实解释了函数的一个秘密。add(x,y)在被运行之前,计算机内是不存在的,直到代码运行到这里的时候,在计算机中,就建立起来了一个对象,这就如同前面所学习过的字符串、列表等类型的对象一样,运行add(x,y)之后,也建立了一个add(x,y)的对象,这个对象与变量result可以建立引用关系,并且add(x,y)将运算结果返回。于是,通过result就可以查看运算结果。 59 | 60 | 如果看官上面一段,感觉有点吃力或者晕乎,也不要紧,那就再读一边。是在搞不明白,就不要搞了。随着学习的深入,它会被明白的。 61 | 62 | ##调用函数 63 | 64 | 扯了不少函数怎么编写,到底编写函数有什么用?在程序中怎么调用呢? 65 | 66 | 为什么要写函数?从理论上说,不用函数,也能够编程,我们在前面已经写了一个猜数字的程序,在那么就没有写函数,当然,用python的函数不算了。现在之所以使用函数,主要是: 67 | 68 | 1. 降低编程的难度,通常将一个复杂的大问题分解成一系列更简单的小问题,然后将小问题继续划分成更小的问题,当问题细化为足够简单时,就可以分而治之。为了实现这种分而治之的设想,就要通过编写函数,将各个小问题逐个击破,再集合起来,解决大的问题。(看官请注意,分而治之的思想是编程的一个重要思想,所谓“分治”方法也。) 69 | 2. 代码重(chong,二声音)用。在编程的过程中,比较忌讳同样一段代码不断的重复,所以,可以定义一个函数,在程序的多个位置使用,也可以用于多个程序。当然,后面我们还会讲到“模块”(此前也涉及到了,就是import导入的那个东西),还可以把函数放到一个模块中供其他程序员使用。也可以使用其他程序员定义的函数(比如import ...,前面已经用到了,就是应用了别人——创造python的人——写好的函数)。这就避免了重复劳动,提供了工作效率。 70 | 71 | 这样看来,函数还是很必要的了。废话少说,那就看函数怎么调用吧。以add(x,y)为例,前面已经演示了基本调用方式,此外,还可以这样: 72 | 73 | >>> def add(x,y): #为了能够更明了显示参数赋值特点,重写此函数 74 | ... print "x=",x #分别打印参数赋值结果 75 | ... print "y=",y 76 | ... return x+y 77 | ... 78 | >>> add(10,3) #x=10,y=3 79 | x= 10 80 | y= 3 81 | 13 82 | >>> add(x=10,y=3) #同上 83 | x= 10 84 | y= 3 85 | 13 86 | >>> add(y=10,x=3) #x=3,y=10 87 | x= 3 88 | y= 10 89 | 13 90 | >>> add(3,10) #x=3,y=10 91 | x= 3 92 | y= 10 93 | 13 94 | 95 | 在定义函数的时候,参数可以想前面那样,等待被赋值,也可以定义的时候就赋给一个默认值。例如: 96 | 97 | >>> def times(x,y=2): #y的默认值为2 98 | ... print "x=",x 99 | ... print "y=",y 100 | ... return x*y 101 | ... 102 | >>> times(3) #x=3,y=2 103 | x= 3 104 | y= 2 105 | 6 106 | 107 | >>> times(x=3) #同上 108 | x= 3 109 | y= 2 110 | 6 111 | 112 | >>> times(3,4) #x=3,y=4,y的值不再是2 113 | x= 3 114 | y= 4 115 | 12 116 | 117 | >>> times("qiwsir") #再次体现了多态特点 118 | x= qiwsir 119 | y= 2 120 | 'qiwsirqiwsir' 121 | 122 | 给列位看官提一个思考题,请在闲暇之余用python完成:写两个数的加、减、乘、除的函数,然后用这些函数,完成简单的计算。 123 | 124 | ##注意事项 125 | 126 | 下面的若干条,是常见编写代码的注意事项: 127 | 128 | 1. 别忘了冒号。一定要记住符合语句首行末尾输入“:”(if,while,for等的第一行) 129 | 2. 从第一行开始。要确定顶层(无嵌套)程序代码从第一行开始。 130 | 3. 空白行在交互模式提示符下很重要。模块文件中符合语句内的空白行常被忽视。但是,当你在交互模式提示符下输入代码时,空白行则是会结束语句。 131 | 4. 缩进要一致。避免在块缩进中混合制表符和空格。 132 | 5. 使用简洁的for循环,而不是while or range.相比,for循环更易写,运行起来也更快 133 | 6. 要注意赋值语句中的可变对象。 134 | 7. 不要期待在原处修改的函数会返回结果,比如list.append() 135 | 8. 一定要之用括号调用函数 136 | 9. 不要在导入和重载中使用扩展名或路径。 137 | -------------------------------------------------------------------------------- /200/214.md: -------------------------------------------------------------------------------- 1 | ## 总结参数的传递 2 | 3 | 就前面所讲,函数的基本内容已经完毕。但是,函数还有很多值得不断玩味的细节。这里进行阐述。 4 | 5 | ##参数的传递 6 | 7 | python中函数的参数通过赋值的方式来传递引用对象。下面总结通过总结常见的函数参数定义方式,来理解参数传递的流程。 8 | 9 | ###def foo(p1,p2,p3,...) 10 | 11 | 这种方式最常见了,列出有限个数的参数,并且彼此之间用逗号隔开。在调用函数的时候,按照顺序以此对参数进行赋值,特备注意的是,参数的名字不重要,重要的是位置。而且,必须数量一致,一一对应。第一个对象(可能是数值、字符串等等)对应第一个参数,第二个对应第二个参数,如此对应,不得偏左也不得偏右。 12 | 13 | >>> def foo(p1,p2,p3): 14 | ... print "p1==>",p1 15 | ... print "p2==>",p2 16 | ... print "p3==>",p3 17 | ... 18 | >>> foo("python",1,["qiwsir","github","io"]) #一一对应地赋值 19 | p1==> python 20 | p2==> 1 21 | p3==> ['qiwsir', 'github', 'io'] 22 | 23 | >>> foo("python") 24 | Traceback (most recent call last): 25 | File "", line 1, in 26 | TypeError: foo() takes exactly 3 arguments (1 given) #注意看报错信息 27 | 28 | >>> foo("python",1,2,3) 29 | Traceback (most recent call last): 30 | File "", line 1, in 31 | TypeError: foo() takes exactly 3 arguments (4 given) #要求3个参数,实际上放置了4个,报错 32 | 33 | ###def foo(p1=value1,p2=value2,...) 34 | 35 | 这种方式比前面一种更明确某个参数的赋值,貌似这样就不乱子了,很明确呀。颇有一个萝卜对着一个坑的意味。 36 | 37 | 还是上面那个函数,用下面的方式赋值,就不用担心顺序问题了。 38 | 39 | >>> foo(p3=3,p1=10,p2=222) 40 | p1==> 10 41 | p2==> 222 42 | p3==> 3 43 | 44 | 也可以采用下面的方式定义参数,给某些参数有默认的值 45 | 46 | >>> def foo(p1,p2=22,p3=33): #设置了两个参数p2,p3的默认值 47 | ... print "p1==>",p1 48 | ... print "p2==>",p2 49 | ... print "p3==>",p3 50 | ... 51 | >>> foo(11) #p1=11,其它的参数为默认赋值 52 | p1==> 11 53 | p2==> 22 54 | p3==> 33 55 | >>> foo(11,222) #按照顺序,p2=222,p3依旧维持原默认值 56 | p1==> 11 57 | p2==> 222 58 | p3==> 33 59 | >>> foo(11,222,333) #按顺序赋值 60 | p1==> 11 61 | p2==> 222 62 | p3==> 333 63 | 64 | >>> foo(11,p2=122) 65 | p1==> 11 66 | p2==> 122 67 | p3==> 33 68 | 69 | >>> foo(p2=122) #p1没有默认值,必须要赋值的,否则报错 70 | Traceback (most recent call last): 71 | File "", line 1, in 72 | TypeError: foo() takes at least 1 argument (1 given) 73 | 74 | ###def foo(*args) 75 | 76 | 这种方式适合于不确定参数个数的时候,在参数args前面加一个*,注意,仅一个哟。 77 | 78 | >>> def foo(*args): #接收不确定个数的数据对象 79 | ... print args 80 | ... 81 | >>> foo("qiwsir.github.io") #以tuple形式接收到,哪怕是一个 82 | ('qiwsir.github.io',) 83 | >>> foo("qiwsir.github.io","python") 84 | ('qiwsir.github.io', 'python') 85 | 86 | 上一讲中已经有例子说明,可以和前面的混合使用。此处不赘述。 87 | 88 | ####def foo(**args) 89 | 90 | 这种方式跟上面的区别在于,必须接收类似arg=val形式的。 91 | 92 | >>> def foo(**args): #这种方式接收,以dictionary的形式接收数据对象 93 | ... print args 94 | ... 95 | 96 | >>> foo(1,2,3) #这样就报错了 97 | Traceback (most recent call last): 98 | File "", line 1, in 99 | TypeError: foo() takes exactly 0 arguments (3 given) 100 | 101 | >>> foo(a=1,b=2,c=3) #这样就可以了,因为有了键值对 102 | {'a': 1, 'c': 3, 'b': 2} 103 | 104 | 下面来一个综合的,看看以上四种参数传递方法的执行顺序 105 | 106 | >>> def foo(x,y=2,*targs,**dargs): 107 | ... print "x==>",x 108 | ... print "y==>",y 109 | ... print "targs_tuple==>",targs 110 | ... print "dargs_dict==>",dargs 111 | ... 112 | 113 | >>> foo("1x") 114 | x==> 1x 115 | y==> 2 116 | targs_tuple==> () 117 | dargs_dict==> {} 118 | 119 | >>> foo("1x","2y") 120 | x==> 1x 121 | y==> 2y 122 | targs_tuple==> () 123 | dargs_dict==> {} 124 | 125 | >>> foo("1x","2y","3t1","3t2") 126 | x==> 1x 127 | y==> 2y 128 | targs_tuple==> ('3t1', '3t2') 129 | dargs_dict==> {} 130 | 131 | >>> foo("1x","2y","3t1","3t2",d1="4d1",d2="4d2") 132 | x==> 1x 133 | y==> 2y 134 | targs_tuple==> ('3t1', '3t2') 135 | dargs_dict==> {'d2': '4d2', 'd1': '4d1'} 136 | 137 | 通过上面的例子,看官是否看出什么名堂了呢? 138 | -------------------------------------------------------------------------------- /200/215.md: -------------------------------------------------------------------------------- 1 | ## 传说中的函数编写条规 2 | 3 | 关于函数的事情,总是说不完的,下面就罗列一些编写函数的注意事项。特别声明,这些事项不是我总结的,我是从一本名字为《Learning Python》的书里面抄过来的,顺便写成了汉语,当然,是按照自己的视角翻译的,里面也夹杂了一些自己的观点。看官也可以理解为源于《Learning Python》但又有点儿不同。 4 | 5 | - 函数具有独立性。也就是常说的不要有太强的耦合性。要让函数能够独立于外部的东西。参数和return语句就是实现这种独立性的最好方法。 6 | - 尽量不要使用全局变量,这也是让函数具有低耦合度的方法。全局变量虽然进行了函数内外通信,但是它强化了函数对外部的依赖,常常让函数的修改和程序调试比较麻烦。 7 | - 如果参数的对象是可变类型的数据,在函数中,不要做对它的修改操作。当然,更多时候,参数传入的最好是不可变的。 8 | - 函数实现的功能和目标要单一化。每个函数的开头,都要有简短的一句话来说明本函数的功能和目标。 9 | - 函数不要太大,能小则小,根据前一条的原则,功能目标单一,则代码条数就小了。如果感觉有点大,看看能不能拆解开,分别为几个函数。 10 | - 不要修改另外一个模块文件中的变量。这跟前面的道理是一样的,目的是降低耦合性。 11 | 12 | ## 小试一下递归 13 | 14 | 对于在python中使用递归,我一项持谨慎态度,能不用就不用,为什么呢?一方面深恐自己学艺不精,另外,递归不仅消耗资源,而且很多时候速度也不如for循环快。 15 | 16 | 不过,做为程序员,递归还是需要了解的。这里就列举一个简单的例子。 17 | 18 | >>> def newsum(lst): 19 | ... if not lst: 20 | ... return 0 21 | ... else: 22 | ... return lst[0] + newsum(lst[1:]) 23 | ... 24 | >>> newsum([1,2,3]) 25 | 6 26 | 27 | 这是一个对list进行求和的函数(看官可能想到了,不是在python中有一个sum内置函数来求和么?为什么要自己写呢?是的,在实际的编程中,没有必要自己写,用sum就可以了。这里用这个例子,纯粹是为了说明递归,没有编程实践的意义),当然,我没有判断传给函数的参数是否为完全由数字组成的list,所以,如果输入的list中字母,就会编程这样了: 28 | 29 | >>> newsum([1,2,3,'q']) 30 | Traceback (most recent call last): 31 | File "", line 1, in 32 | File "", line 5, in newsum 33 | File "", line 5, in newsum 34 | File "", line 5, in newsum 35 | File "", line 5, in newsum 36 | TypeError: cannot concatenate 'str' and 'int' objects 37 | 38 | 这就是本函数的缺憾了。但是,为了说明递归,我们就顾不了这么多了。暂且忽略这个缺憾。看官注意上面的函数中,有一句:return lst(0)+newsum(lst[1:]),在这句话中,又调用了一边函数本身。对了,这就递归,在函数中调用本函数自己。当然,区别在于传入的参数有变化了。为了清除函数的调用流程,我们可以将每次传入的参数打印出来: 39 | 40 | >>> def newsum(lst): 41 | ... print lst 42 | ... if not lst: 43 | ... return 0 44 | ... else: 45 | ... return lst[0] + newsum(lst[1:]) 46 | ... 47 | >>> newsum([1,2,3]) 48 | [1, 2, 3] 49 | [2, 3] 50 | [3] 51 | [] 52 | 6 53 | 54 | 这就是递归了。 55 | 56 | 其实,看官或许已经想到了,即使不用sum,也可以用for来事项上述操作。 57 | 58 | >>> lst = [1,2,3] 59 | >>> sum_result = 0 60 | >>> for x in lst: sum_result += x 61 | ... 62 | >>> sum_result 63 | 6 64 | 65 | ##铭记:函数是对象 66 | 67 | 还记得,在第一部分学习的时候,不断强调的:**变量无类型,数据有类型**,那时候遇到的数据包括字符串、数值、列表、元组、字典、文件,这些东西,都被视为对象。函数跟它们类似,也是对象。因此就可以像以前的对象一样进行赋值、传递给其它函数、嵌入到数据结构、从一个函数返回给另一个函数等等面向对象的操作。当然,函数这个对象也有特殊性,就是它可以由一个函数表达式后面的括号中的列表参数调用。 68 | 69 | >>> def newsum(lst): #依然以这个递归的函数为例 70 | ... print lst 71 | ... if not lst: 72 | ... return 0 73 | ... else: 74 | ... return lst[0] + newsum(lst[1:]) 75 | ... 76 | 77 | >>> lst = [1,2,3] 78 | 79 | >>> newsum(lst) #这是前面已经常用的方法 80 | [1, 2, 3] 81 | [2, 3] 82 | [3] 83 | [] 84 | 6 85 | >>> recusion_fun = newsum #通过赋值语句,让变量recusion_fun也引用了函数newsum(lst)对象 86 | >>> recusion_fun(lst) #从而变量能够实现等同函数调用的操作 87 | [1, 2, 3] 88 | [2, 3] 89 | [3] 90 | [] 91 | 6 92 | 93 | 再看一个例子,在这个例子中,一定要谨记函数是对象。看官曾记否?在list中,可以容纳任何对象,那么,是否能够容纳一个函数中呢? 94 | 95 | >>> fun_list = [(newsum,[1,2,3]),(newsum,[1,2,3,4,5])] 96 | >>> for fun,arg in fun_list: 97 | ... fun(arg) 98 | ... 99 | [1, 2, 3] 100 | [2, 3] 101 | [3] 102 | [] 103 | 6 104 | [1, 2, 3, 4, 5] 105 | [2, 3, 4, 5] 106 | [3, 4, 5] 107 | [4, 5] 108 | [5] 109 | [] 110 | 15 111 | 112 | 函数,真的就是对象啊。 113 | 114 | 既然是对象,就可以用dir(object)方式查看有关信息喽: 115 | 116 | >>> dir(newsum) 117 | ['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name'] 118 | >>> dir(newsum.__code__) 119 | ['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames'] 120 | >>> newsum.__code__.__doc__ 121 | 'code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\nCreate a code object. Not for the faint of heart.' 122 | >>> newsum.__code__.co_varnames 123 | ('lst',) 124 | >>> newsum.__code__.co_argcount 125 | 1 126 | 127 | 所以,各位看官,在使用函数的时候,首先要把它放在对象的层面考量,它不是什么特殊的东西,尽管我们使用了不少篇幅讲述它,但它终归还是一个对象。 128 | -------------------------------------------------------------------------------- /200/216.md: -------------------------------------------------------------------------------- 1 | ## 关于类的基本认识 2 | 3 | 在开始部分,请看官非常非常耐心地阅读下面几个枯燥的术语解释,本来这不符合本教程的风格,但是,请看官谅解,因为列位将来一定要阅读枯燥的东西的。这些枯燥的属于解释,均来自维基百科。 4 | 5 | **1、问题空间** 6 | 7 | >问题空间是问题解决者对一个问题所达到的全部认识状态,它是由问题解决者利用问题所包含的信息和已贮存的信息主动地构成的。 8 | 9 | 一个问题一般有下面三个方面来定义: 10 | 11 | - 初始状态——一开始时的不完全的信息或令人不满意的状况; 12 | - 目标状态——你希望获得的信息或状态; 13 | - 操作——为了从初始状态迈向目标状态,你可能采取的步骤。 14 | 15 | 这三个部分加在一起定义了问题空间(problem space)。 16 | 17 | **2、对象** 18 | 19 | >对象(object),台湾译作物件,是面向对象(Object Oriented)中的术语,既表示客观世界问题空间(Namespace)中的某个具体的事物,又表示软件系统解空间中的基本元素。 20 | 21 | 对象这个属于,比较抽象。因此,有人认为,将object翻译为“对象”,常常让人迷茫,不如翻译为“物件”更好。因为“物件”让人感到一种具体的东西,而所谓对象,就是指那种具体的东西。 22 | 23 | 这种看法在某些语言中是非常适合的。但是,在Python中,则无所谓,不管怎样,python中的一切都是对象,不管是字符串、函数、模块还是类,都是对象。“万物皆对象”。 24 | 25 | 都是对象有什么优势吗?太有了。这说明python天生就是OOP的。也说明,python中的所有东西,都能够进行拼凑组合应用,因为对象就是可以拼凑组合应用的。 26 | 27 | 对于对象这个东西,OOP大师Grandy Booch的定义,应该是权威的,相关定义的内容包括: 28 | 29 | - **对象**:一个对象有自己的状态、行为和唯一的标识;所有相同类型的对象所具有的结构和行为在他们共同的类中被定义。 30 | - **状态(state)**:包括这个对象已有的属性(通常是类里面已经定义好的)在加上对象具有的当前属性值(这些属性往往是动态的) 31 | - **行为(behavior)**:是指一个对象如何影响外界及被外界影响,表现为对象自身状态的改变和信息的传递。 32 | - **标识(identity)**:是指一个对象所具有的区别于所有其它对象的属性。(本质上指内存中所创建的对象的地址) 33 | 34 | **3、面向对象** 35 | 36 | >面向对象程序设计(英语:Object-oriented programming,缩写:OOP)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。 37 | 38 | >面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对电脑下达的指令。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,因此它们都可以被看作一个小型的“机器”,即对象。 39 | 40 | >目前已经被证实的是,面向对象程序设计推广了程序的灵活性和可维护性,并且在大型项目设计中广为应用。 此外,支持者声称面向对象程序设计要比以往的做法更加便于学习,因为它能够让人们更简单地设计并维护程序,使得程序更加便于分析、设计、理解。反对者在某些领域对此予以否认。 41 | 42 | >当我们提到面向对象的时候,它不仅指一种程序设计方法。它更多意义上是一种程序开发方式。在这一方面,我们必须了解更多关于面向对象系统分析和面向对象设计(Object Oriented Design,简称OOD)方面的知识。 43 | 44 | 下面再引用一段来自维基百科中关于OOP的历史。 45 | 46 | >面向对象程序设计的雏形,早在1960年的Simula语言中即可发现,当时的程序设计领域正面临着一种危机:在软硬件环境逐渐复杂的情况下,软件如何得到良好的维护?面向对象程序设计在某种程度上通过强调可重复性解决了这一问题。20世纪70年代的Smalltalk语言在面向对象方面堪称经典——以至于30年后的今天依然将这一语言视为面向对象语言的基础。 47 | 48 | >计算机科学中对象和实例概念的最早萌芽可以追溯到麻省理工学院的PDP-1系统。这一系统大概是最早的基于容量架构(capability based architecture)的实际系统。另外1963年Ivan Sutherland的Sketchpad应用中也蕴含了同样的思想。对象作为编程实体最早是于1960年代由Simula 67语言引入思维。Simula这一语言是奥利-约翰·达尔和克利斯登·奈加特在挪威奥斯陆计算机中心为模拟环境而设计的。(据说,他们是为了模拟船只而设计的这种语言,并且对不同船只间属性的相互影响感兴趣。他们将不同的船只归纳为不同的类,而每一个对象,基于它的类,可以定义它自己的属性和行为。)这种办法是分析式程序的最早概念体现。在分析式程序中,我们将真实世界的对象映射到抽象的对象,这叫做“模拟”。Simula不仅引入了“类”的概念,还应用了实例这一思想——这可能是这些概念的最早应用。 49 | 50 | >20世纪70年代施乐PARC研究所发明的Smalltalk语言将面向对象程序设计的概念定义为,在基础运算中,对对象和消息的广泛应用。Smalltalk的创建者深受Simula 67的主要思想影响,但Smalltalk中的对象是完全动态的——它们可以被创建、修改并销毁,这与Simula中的静态对象有所区别。此外,Smalltalk还引入了继承性的思想,它因此一举超越了不可创建实例的程序设计模型和不具备继承性的Simula。此外,Simula 67的思想亦被应用在许多不同的语言,如Lisp、Pascal。 51 | 52 | >面向对象程序设计在80年代成为了一种主导思想,这主要应归功于C++——C语言的扩充版。在图形用户界面(GUI)日渐崛起的情况下,面向对象程序设计很好地适应了潮流。GUI和面向对象程序设计的紧密关联在Mac OS X中可见一斑。Mac OS X是由Objective-C语言写成的,这一语言是一个仿Smalltalk的C语言扩充版。面向对象程序设计的思想也使事件处理式的程序设计更加广泛被应用(虽然这一概念并非仅存在于面向对象程序设计)。一种说法是,GUI的引入极大地推动了面向对象程序设计的发展。 53 | 54 | >苏黎世联邦理工学院的尼克劳斯·维尔特和他的同事们对抽象数据和模块化程序设计进行了研究。Modula-2将这些都包括了进去,而Oberon则包括了一种特殊的面向对象方法——不同于Smalltalk与C++。 55 | 56 | >面向对象的特性也被加入了当时较为流行的语言:Ada、BASIC、Lisp、Fortran、Pascal以及种种。由于这些语言最初并没有面向对象的设计,故而这种糅合常常会导致兼容性和维护性的问题。与之相反的是,“纯正的”面向对象语言却缺乏一些程序员们赖以生存的特性。在这一大环境下,开发新的语言成为了当务之急。作为先行者,Eiffel成功地解决了这些问题,并成为了当时较受欢迎的语言。 57 | 58 | >在过去的几年中,Java语言成为了广为应用的语言,除了它与C和C++语法上的近似性。Java的可移植性是它的成功中不可磨灭的一步,因为这一特性,已吸引了庞大的程序员群的投入。 59 | 60 | >在最近的计算机语言发展中,一些既支持面向对象程序设计,又支持面向过程程序设计的语言悄然浮出水面。它们中的佼佼者有Python、Ruby等等。 61 | 62 | >正如面向过程程序设计使得结构化程序设计的技术得以提升,现代的面向对象程序设计方法使得对设计模式的用途、契约式设计和建模语言(如UML)技术也得到了一定提升。 63 | 64 | 列位看官,当您阅读到这句话的时候,我就姑且认为您已经对面向对象有了一个模糊的认识了。那么,类和OOP有什么关系呢? 65 | 66 | [维基百科](http://zh.wikipedia.org/wiki/%E7%B1%BB_%28%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%29)中这样定义了类: 67 | 68 | >在面向对象程式设计,类(class)是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法。 69 | 70 | >类的更严格的定义是由某种特定的元数据所组成的内聚的包。它描述了一些对象的行为规则,而这些对象就被称为该类的实例。类有接口和结构。接口描述了如何通过方法与类及其实例互操作,而结构描述了一个实例中数据如何划分为多个属性。类是与某个层的对象的最具体的类型。类还可以有运行时表示形式(元对象),它为操作与类相关的元数据提供了运行时支持。 71 | 72 | 支持类的编程语言在支持与类相关的各种特性方面都多多少少有一些微妙的差异。大多数都支持不同形式的类继承。许多语言还支持提供封装性的特性,比如访问修饰符。类的出现,为面向对象编程的三个最重要的特性(封装性,继承性,多态性),提供了实现的手段。 73 | 74 | 看到这里,看官或许有一个认识,要OOP编程,就得用到类。可以这么说,虽然不是很严格。但是,反过来就不能说了。不是说用了类就一定是OOP。 75 | 76 | ##编写类 77 | 78 | 对类的理解,需要看官有一定的抽象思维。因为类(Class)本身所定义的是某事物的抽象特点。例如定义一个类: 79 | 80 | class Human: #这是定义类的方法,通常类的名称用首字母大写的单词或者单词拼接 81 | pass 82 | 83 | 好,现在就从这里开始,编写一个类,不过这次我们暂时不用python,而是用伪代码,当然,这个代码跟python相去甚远。如下: 84 | 85 | class Human: 86 | 四肢 87 | 性格 88 | 爱好 89 | 学习() 90 | 91 | 对象(Object)是类的实例。刚才已经定义了一个名字为Human的类,从而定义了世界上所有的Human,但是这是一个抽象的Human,不是具体某个人。而对一个具体的人,他的四肢特点、性格、爱好等都是具体的,这些东西在这里被称之为属性。 92 | 93 | 下面就找一个具体的人:王二麻子,把上面的类实例化。 94 | 95 | 王二麻子 = Human() 96 | 王二麻子.四肢 = 修长 97 | 王二麻子.爱好 = 看MM 98 | 99 | 在这里,王二麻子就是Human这个类的一个实例。一个具体对象属性的值被称作它的“状态”。(系统给对象分配内存空间,而不会给类分配内存空间,这很好理解,类是抽象的系统不可能给抽象的东西分配空间,对象是具体的) 100 | 101 | 行文至此,看官是不是大概对类有了一个模糊的认识了呢? 102 | 103 | 鉴于类,距离我们的直观感觉似乎有点远。所以,要慢慢道来。本讲内容不多,盼望看官能理解。 104 | -------------------------------------------------------------------------------- /200/218.md: -------------------------------------------------------------------------------- 1 | ## 编写类之二方法 2 | 3 | [上一讲](./217.md)中创建了类,并且重点讲述了构造函数以及类实例,特别是对那个self,描述了不少。在讲述构造函数的时候特别提到,__init__()是一个函数,只不过在类中有一点特殊的作用罢了,每个类,首先要运行它,它规定了类的基本结构。 4 | 5 | ## 数据流转过程 6 | 7 | 除了在类中可以写这种函数之外,在类中还可以写别的函数,延续上一讲的例子: 8 | 9 | #!/usr/bin/env python 10 | #coding:utf-8 11 | 12 | class Person: 13 | def __init__(self, name, lang="golang", website="www.google.com"): 14 | self.name = name 15 | self.lang = lang 16 | self.website = website 17 | self.email = "qiwsir@gmail.com" 18 | 19 | def author(self): 20 | return self.name 21 | 22 | laoqi = Person("LaoQi") 23 | info = Person("qiwsir",lang="python",website="qiwsir.github.io") 24 | 25 | print "Author name from laoqi:",laoqi.author() 26 | print "Author name from info:",info.author() 27 | 28 | #运行结果 29 | 30 | Author name from laoqi: LaoQi 31 | Author name from info: qiwsir 32 | 33 | 看官可能已经注意了,这段代码比上一讲多了一个函数author(self),这个我们先不管,稍后会详细分解。首先看看数据是如何在这个代码中流转的。为了能够清楚,画一张图,所谓一图胜千言万语,有图有真相。 34 | 35 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/21801.png) 36 | 37 | 定义类Person,然后创建实例laoqi=Person("LaoQi"),看官注意观察图上的箭头方向。laoqi这个实例和Person类中的self对应,它们都是引用了实例对象(很多时候简化说成是实例对象)。"LaoQi"是一个具体的数据,通过构造函数中的name参数,传给实例的属性self.name,在类Person中的另外一个方法author的参数列表中第一个就是self,表示要承接self对象,return self.name,就是在类内部通过self对象,把它的属性self.name的数据传导如author。 38 | 39 | 当运行laoqi.author()的时候,就是告诉上面的代码,调用laoqi实例对象,并得到author()方法的结果,laoqi这个实例就自动被告诉了author()(注意,self参数在这里不用写,这个告诉过程是python自动完成的,不用我们操心了),author方法就返回laoqi实例的属性,因为前面已经完成了laoqi与self的对应过程,所以这时候author里面的self就是laoqi,自然self.name=laoqi.name。 40 | 41 | 看官可以跟随我在做一个实验,那就是在author中,return laoqi.name,看看什么效果。因为既然laoqi和self是同一个实例对象,直接写成laoqi.name是不是也可以呢? 42 | 43 | #!/usr/bin/env python 44 | #coding:utf-8 45 | 46 | class Person: 47 | def __init__(self, name, lang="golang", website="www.google.com"): 48 | self.name = name 49 | self.lang = lang 50 | self.website = website 51 | self.email = "qiwsir@gmail.com" 52 | 53 | def author(self): 54 | #return self.name 55 | return laoqi.name #返回 56 | 57 | laoqi = Person("LaoQi") 58 | info = Person("qiwsir",lang="python",website="qiwsir.github.io") 59 | 60 | print "Author name from laoqi:",laoqi.author() 61 | print "Author name from info:",info.author() 62 | 63 | #输出结果 64 | Author name from laoqi: LaoQi #laoqi实例输出结果 65 | Author name from info: LaoQi #info实例输出结果 66 | 67 | 从结果中可以看出,没有报错。但是,info这个实例输出的结果和laoqi实例输出的结果一样。原来,当调用了info实例之后,运行到author(),返回的是laoqi.name。所以,这里一定要用self实例。在调用不同的实例时,self会自动的进行匹配,当然,匹配过程是python完成,仍然不用我们操心。 68 | 69 | 70 | OK,数据流转过程,看官是否理解了呢?下面进入方法编写的环节 71 | 72 | ##为什么要用到方法 73 | 74 | 在类里面,可以用def语句来编写函数,但是,通常这个函数的样子是这样的: 75 | 76 | class ClassName: 77 | def __init__(self,*args): 78 | ... 79 | def method(self,*args): #是一个在类里面的函数 80 | ... 81 | 82 | 在类ClassName里面,除了前面那个具有初始化功能的构造函数之外,还有一个函数method,这个函数和以前学习过的函数一样,函数里面要写什么,也没有特别的规定。但是,这个函数的第一个参数必须是self,或者说,可以没有别的参数,但是self是必须写上并且是第一个。这个self参数的作用前面已经说过了。 83 | 84 | 这样看来,类里面的这个函数还有点跟以前函数不同的地方。 85 | 86 | 类里面的这个函数,我们就称之为**方法**。 87 | 88 | 之所以用方法,也是用类的原因,也是用函数的原因,都是为了减少代码的冗余,提高代码的重用性,这也是OOP的原因。 89 | 90 | 方法怎样被重用呢?看本最开始的那段代码,里面有一个author方法,不管是laoqi还是info实例,都用这个方法返回实例导入的名字。这就是体现了重用。 91 | 92 | ##编写和操作方法 93 | 94 | 编写方法的过程和编写一个函数的过程一样,需要注意的就是要在参数列表中第一个写上self,即使没有其它的参数。 95 | 96 | #!/usr/bin/env python 97 | #coding:utf-8 98 | 99 | class Person: 100 | def __init__(self, name, lang="golang", website="www.google.com"): 101 | self.name = name 102 | self.lang = lang 103 | self.website = website 104 | self.email = "qiwsir@gmail.com" 105 | 106 | def author(self, address): 107 | #return self.name 108 | return laoqi.name+" in "+address 109 | 110 | laoqi = Person("LaoQi") 111 | info = Person("qiwsir",lang="python",website="qiwsir.github.io") 112 | 113 | print "Author name from laoqi:",laoqi.author("China") 114 | print "Author name from info:",info.author("Suzhou") 115 | 116 | #运行结果 117 | 118 | Author name from laoqi: LaoQi in China 119 | Author name from info: LaoQi in Suzhou 120 | 121 | 这段代码中,对author方法增加了一个参数address,当调用这个方法的时候:laoqi.author("China"),要对这个参数赋值,看官特别注意,在类中,这个方法显示是有两个参数(self,address),但是在调用的时候,第一个参数是自动将实例laoqi与之对应起来,不需要显化赋值,可以理解成是隐含完成的(其实,也可以将laoqi看做隐藏的主体,偷偷地更self勾搭上了)。 122 | 123 | 通过上面的讲述,看官可以试试类了。提醒,一定要对类的数据流通过程清晰。 124 | -------------------------------------------------------------------------------- /200/219.md: -------------------------------------------------------------------------------- 1 | ## 编写类之三子类 2 | 3 | 关于类,看官想必已经有了感觉,看下面的代码,请仔细阅读,并看看是否能够发现点什么问题呢? 4 | 5 | #!/usr/bin/env python 6 | #coding:utf-8 7 | 8 | class Person: 9 | def __init__(self, name, lang, email): 10 | self.name = name 11 | self.lang = lang 12 | self.email = email 13 | 14 | def author(self): 15 | return self.name 16 | 17 | class Programmer: 18 | def __init__(self, name, lang, email, system, website): 19 | self.name = name 20 | self.lang = lang 21 | self.email = email 22 | self.system = system 23 | self.website = website 24 | 25 | def pythoner(self): 26 | pythoner_list = [ self.name, self.lang, self.email, self.system, self.website ] 27 | return pythoner_list 28 | 29 | if __name__=="__main__": 30 | writer = Person("qiwsir","Chinese","qiwsir@gmail.com") 31 | python = Programmer("qiwsir","Python","qiwsir@gmail.com","Ubutun","qiwsir.github.io") 32 | print "My name is:%s"%writer.author() 33 | print "I write program by:%s"%python.pythoner()[1] 34 | 35 | 上面这段代码,运行起来没有什么问题,但是,仔细看,发现有两个类,一个名字叫做Person,另外一个叫做Programmer,这还不是问题所在,问题所在是这两个类的构造函数中,存在这相同的地方:self.name=name,self.lang=lang,self.email=email,这对于追求代码质量的程序员,一般是不允许的。最好不要有重复代码或者冗余代码。可是,在两个类中都要有这些参数,应该怎么办呢? 36 | 37 | ##子类、父类和继承 38 | 39 | 看下面的代码,里面有两个类A,B。这段程序能够正确运行,每个类的功能是仅仅打印指定的内容。 40 | 41 | #!/usr/bin/env python 42 | #coding:utf-8 43 | 44 | class A: 45 | def __init__(self): 46 | print "aaa" 47 | 48 | class B: 49 | def __init__(self): 50 | print "bbb" 51 | 52 | if __name__=="__main__": 53 | a = A() 54 | b = B() 55 | 56 | #运行结果 57 | aaa 58 | bbb 59 | 60 | 上面的两个类彼此之间没有所谓的父子关系。现在稍加改变,将类B改写,注意观察与上面的差异。 61 | 62 | #!/usr/bin/env python 63 | #coding:utf-8 64 | 65 | class A: 66 | def __init__(self): 67 | print "aaa" 68 | 69 | class B(A): #这里和上面程序不同。B继承了A 70 | def __init__(self): 71 | print "bbb" 72 | 73 | if __name__=="__main__": 74 | a = A() 75 | b = B() 76 | 77 | #运行结果 78 | aaa 79 | bbb 80 | 81 | 这段程序中,类B跟前面的那段有一点不同,class B(A):,这样写就表明了B相对A的关系:B是A的子类,B从A继承A的所有东西(子承父业)。 82 | 83 | 但是,看官发现了没有,运行结果一样。是的,那是以为在B中尽管继承了A,但是没有调用任何A的东西,就好比儿子从老爸那里继承了财富,但是儿子一个子也没动,外界看到的和没有继承一样。 84 | 85 | #!/usr/bin/env python 86 | #coding:utf-8 87 | 88 | class A: 89 | def __init__(self): 90 | print "aaa" 91 | 92 | class B(A): 93 | def __init__(self): 94 | #print "bbb" 95 | A.__init__(self) #运行继承的父类 96 | 97 | if __name__=="__main__": 98 | a = A() 99 | b = B() 100 | 101 | #运行结果 102 | aaa 103 | aaa 104 | 105 | 这回运行结果有了变化,本来b=B()是运行类B,但是B继承了A,并且在初始化的构造函数中,引入A的构造函数,所以,就运行A的结果相应结果了。 106 | 107 | 下面把最开头的那端程序用子类继承的方式重写,可以是这样的: 108 | 109 | #!/usr/bin/env python 110 | #coding:utf-8 111 | 112 | class Person: 113 | def __init__(self, name, lang, email): 114 | self.name = name 115 | self.lang = lang 116 | self.email = email 117 | 118 | def author(self): 119 | return self.name 120 | """ 121 | class Programmer: 122 | def __init__(self, name, lang, email, system, website): 123 | self.name = name 124 | self.lang = lang 125 | self.email = email 126 | self.system = system 127 | self.website = website 128 | 129 | def pythoner(self): 130 | pythoner_list = [ self.name, self.lang, self.email, self.system, self.website ] 131 | return pythoner_list 132 | """ 133 | 134 | class Programmer(Person): #继承父类Person 135 | def __init__(self, name, lang, email, system, website): 136 | Person.__init__(self,name,lang,email) #将Person.__init__()的功能继承到这里 137 | #self.name = name #这三句是Person中已经搞定的,就不用重复 138 | #self.lang = lang #通过继承已经实现了这三句的功能 139 | #self.email = email 140 | self.system = system #子类中不同于Person父类部分 141 | self.website = website 142 | 143 | def pythoner(self): 144 | pythoner_list = [ self.name, self.lang, self.email, self.system, self.website ] 145 | return pythoner_list 146 | 147 | if __name__=="__main__": 148 | writer = Person("qiwsir","Chinese","qiwsir@gmail.com") 149 | python = Programmer("qiwsir","Python","qiwsir@gmail.com","Ubutun","qiwsir.github.io") 150 | print "My name is:%s"%writer.author() 151 | print "I write program by:%s"%python.pythoner()[1] 152 | 153 | 代码运行结果与前面一样。 154 | 155 | 列位是否理解了子类和父类、继承的特点。如果你有一个老爹,是一个高官或者富豪,那么你就官二代或者富二代了,你就从他们那里继承了很多财富,所以生活就不用太劳累了。这就是继承的作用。在代码中,也类似,继承能够让写代码的少劳累一些。 156 | 157 | 需要提供注意的是,在子类中,如果要继承父类,必须用显明的方式将所继承的父类方法写出来,例如上面的Person.__init__(self,name,lang,email),必须这样写,才能算是在子类中进行了继承。如果不写上,是没有继承的。用编程江湖的黑话(比较文雅地称为“行话”)说就是“显式调用父类方法”。 158 | 159 | 对于为什么要用继承,好友@令狐虫 大侠给了以非常精彩的解释: 160 | 161 | >从技术上说,OOP里,继承最主要的用途是实现多 态。对于多态而言,重要的是接口继承性,属性和行为是否存在继承性,这是不一定的。事实上,大量工程实践表明,重度的行为继承会导致系统过度复杂和臃肿, 反而会降低灵活性。因此现在比较提倡的是基于接口的轻度继承理念。这种模型里因为父类(接口类)完全没有代码,因此根本谈不上什么代码复用了。 162 | 163 | >在Python里,因为存在Duck Type,接口定义的重要性大大的降低,继承的作用也进一步的被削弱了。 164 | 165 | >另外,从逻辑上说,继承的目的也不是为了复用代码,而是为了理顺关系。 166 | 167 | 我表示完全赞同上述解释。不过看官如果不理解,也没有关系,上述解释中的精神,的确需要在编程实践中感悟才能领会到的。 168 | -------------------------------------------------------------------------------- /200/220.md: -------------------------------------------------------------------------------- 1 | ## 编写类之四再论继承 2 | 3 | 在上一讲代码的基础上,做进一步修改,成为了如下程序,请看官研习这个程序: 4 | 5 | #!/usr/bin/env python 6 | #coding:utf-8 7 | 8 | class Person: 9 | def __init__(self, name, email): 10 | self.name = name 11 | self.email = email 12 | 13 | class Programmer(Person): 14 | def __init__(self, name,email,lang, system, website): 15 | Person.__init__(self,name,email) 16 | self.lang = lang 17 | self.system = system 18 | self.website = website 19 | 20 | class Pythoner(Programmer): 21 | def __init__(self,name,email): 22 | Programmer.__init__(self,name,email,"python","Ubuntu","qiwsir.github.io") 23 | 24 | if __name__=="__main__": 25 | writer = Pythoner("qiwsir","qiwsir@gmail.com") 26 | print "name=",writer.name 27 | print "lang=",writer.lang 28 | print "email=",writer.email 29 | print "system=",writer.system 30 | print "website=",writer.website 31 | 32 | #运行结果 33 | 34 | name= qiwsir 35 | lang= python 36 | email= qiwsir@gmail.com 37 | system= Ubuntu 38 | website= qiwsir.github.io 39 | 40 | 对结果很满意,再看程序中的继承关系:Pythoner <-- Programmer <-- Person,从上面的过程中不难看出,继承能够减少代码重复,是的代码更简练。另外,在继承的时候,也可以在函数中对参数进行默认赋值。 41 | 42 | 为了能够突出继承问题的探究,还是用那种简单的类来做实验。 43 | 44 | ##多余的B 45 | 46 | #!/usr/bin/env python 47 | #coding:utf-8 48 | 49 | class A: 50 | def __init__(self): 51 | print "aaa" 52 | 53 | class B(A): 54 | pass 55 | 56 | if __name__=="__main__": 57 | a = A() 58 | b = B() 59 | 60 | #运行结果 61 | 62 | aaa 63 | aaa 64 | 65 | B继承A,没有任何修改地继承,B就可以不用写任何东西了,或者说B本质上就是一个多余。在真实的编程过程中,没有这样写的,这里仅仅是为了向看官展示一下继承的含义罢了。 66 | 67 | ##首个继承有效 68 | 69 | #!/usr/bin/env python 70 | #coding:utf-8 71 | 72 | class A: 73 | def __init__(self): 74 | print "aaa" 75 | 76 | class B: 77 | def __init__(self): 78 | print "bbb" 79 | 80 | class C1(A,B): 81 | pass 82 | 83 | class C2(B,A): 84 | pass 85 | 86 | if __name__=="__main__": 87 | print "A--->", 88 | a = A() 89 | print "B--->", 90 | b = B() 91 | print "C1(A,B)--->", 92 | c1 = C1() 93 | print "C2(B,A)--->", 94 | c2 = C2() 95 | 96 | #运行结果 97 | 98 | A---> aaa 99 | B---> bbb 100 | C1(A,B)---> aaa 101 | C2(B,A)---> bbb 102 | 103 | 列位看官是否注意了,类C1继承了两个类A,B;类C2也继承了两个类,只不过书写顺序有点区别(B,A)。从运行结果可以看出,当子类继承多个父类的时候,对于构造函数`__init__()`,只有第一个能够被继承,第二个就等掉了。所以,一般情况下,不会在程序中做关于构造函数的同时多个继承,不过可以接力继承,就如同前面那个比较真实的代码一样。 104 | 105 | ##其它方法的继承 106 | 107 | #!/usr/bin/env python 108 | #coding:utf-8 109 | 110 | class A: 111 | def __init__(self): 112 | print "aaa" 113 | def amethod(self): 114 | print "method a" 115 | 116 | class B(A): 117 | def __init__(self): 118 | print "bbb" 119 | 120 | 121 | if __name__=="__main__": 122 | print "A--->" 123 | a = A() 124 | a.amethod() 125 | print "B--->" 126 | b = B() 127 | b.amethod() 128 | 129 | #运行结果 130 | 131 | A---> 132 | aaa 133 | method a 134 | B---> 135 | bbb 136 | method a 137 | 138 | 为了说明白上面的情况,还是画了一张图,不过,我画完之后,就后悔了,看这张图好像更糊涂了。怎么着也画了,还是贴出来,如果能够协助理解更好了。 139 | 140 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/22001.png) 141 | 142 | A的实例和调用,就不多说了。重点看B,类B继承了A,同时,B在构造函数中自己做了规定,也就是B的构造函数是按照B的意愿执行,不执行A的内容,但是,A还有一个amethod(self)方法,B则继承了这个方法。当通过类B的实例调用这个方法的时候,就能够成功了:b.amethod() 143 | 144 | 这就是方法的继承和调用方法。 145 | 146 | 所谓继承,就是从下到上一级一级地找相应的继承对象,找到了就继承之。如果有同名的怎么办?按照什么顺序找呢? 147 | 148 | 应用网上的一段: 149 | 150 | [在Python中,可以進行多重繼承,這個時候要注意搜尋的順序,是從子類別開始,接著是同一階層父類別由左至右搜尋,再至更上層同一階層父類別由左至右搜尋,直到達到頂層為止。](http://openhome.cc/Gossip/Python/Inheritance.html) 151 | 152 | 代码举例: 153 | 154 | class A(object): 155 | def method1(self): 156 | print('A.method1') 157 | 158 | def method2(self): 159 | print('A.method2') 160 | 161 | class B(A): 162 | def method3(self): 163 | print('B.method3') 164 | 165 | class C(A): 166 | def method2(self): 167 | print('C.method2') 168 | 169 | def method3(self): 170 | print('C.method3') 171 | 172 | class D(B, C): 173 | def method4(self): 174 | print('C.method4') 175 | 176 | d = D() 177 | d.method4() # 在 D 找到,C.method4 178 | d.method3() # 以 D->B 順序找到,B.method3 179 | d.method2() # 以 D->B->C 順序找到,C.method2 180 | d.method1() # 以 D->B->C->A 順序找到,A.method1 181 | 182 | 务必请真正的学习者要对照每个类的每个方法,依次找到相应的输出结果。从而理解继承的顺序。学习,就要点滴积累。 183 | -------------------------------------------------------------------------------- /200/221.md: -------------------------------------------------------------------------------- 1 | ## 命名空间 2 | 3 | 命名空间,英文名字:namespaces 4 | 5 | 在研习命名空间以前,请打开在python的交互模式下,输入:import this 6 | 7 | >>> import this 8 | The Zen of Python, by Tim Peters 9 | 10 | Beautiful is better than ugly. 11 | Explicit is better than implicit. 12 | Simple is better than complex. 13 | Complex is better than complicated. 14 | Flat is better than nested. 15 | Sparse is better than dense. 16 | Readability counts. 17 | Special cases aren't special enough to break the rules. 18 | Although practicality beats purity. 19 | Errors should never pass silently. 20 | Unless explicitly silenced. 21 | In the face of ambiguity, refuse the temptation to guess. 22 | There should be one-- and preferably only one --obvious way to do it. 23 | Although that way may not be obvious at first unless you're Dutch. 24 | Now is better than never. 25 | Although never is often better than *right* now. 26 | If the implementation is hard to explain, it's a bad idea. 27 | If the implementation is easy to explain, it may be a good idea. 28 | Namespaces are one honking great idea -- let's do more of those! 29 | 30 | 这里列位看到的就是所谓《python之禅》,在本教程的[第零部分:唠叨一些关于Python的事情](./001.md)有专门的翻译,这里再次列出,是要引用其中的一句话。请看官看最后一句: Namespaces are one honking great idea -- let's do more of those! 31 | 32 | 这是为了向看官说明Namespaces、命名空间值重要性。 33 | 34 | ##什么是命名空间 35 | 36 | 从“一切皆为对象”开始说起吧。对象,很多时候我们直接使用它并不方便,因此要给它取一个名字。打个比方,有这样一个物种,它是哺乳纲灵长目人科人属智人种,这就是所谓的对象,但是,在平时提及这个对象的时候,总是要说“哺乳纲灵长目人科人属智人种”,是不是太麻烦了?于是聪明的这个物种就为这个世界上的各种对象命名,例如将“哺乳纲灵长目人科人属智人种”这个对象命名为“人”。 37 | 38 | 在编程中也是如此,前面在讲述变量相关知识的时候已经说明了变量和引用对象的关系。 39 | 40 | >>> a = 7 41 | >>> id(7) 42 | 137589400 43 | >>> id(a) 44 | 137589400 45 | >>> id(7)==id(a) 46 | True 47 | 48 | 看这个例子。7就是一个计算机内存中存在的对象,用id()这个内置函数可以查看7在内存(在RAM)中的地址。a 就是为这个对象预备的名字,如前面所讲的,它与内存中的一个编号为137589400的对象关联,或者说引用了这个对象,这个对象就是7. 49 | 50 | 如果做了下面的操作: 51 | 52 | >>> a = a+1 53 | >>> id(a) 54 | 137589388 55 | >>> a 56 | 8 57 | >>> id(8) 58 | 137589388 59 | 60 | 其实,上面操作中的a+1完成的是a引用的对象7+1,只不过是顺着对象7的命名a导入了对象7罢了,这样就在内存中建立了一个新的对象8,同样通过id()函数查看到内存中的地址,通过地址可以看到,这时候的a又自动引用对象8了. 61 | 62 | >>> id(7) #对象7在内存中的地址没变 63 | 137589400 64 | >>> b = 7 #b引用此对象 65 | >>> id(b) 66 | 137589400 67 | 68 | 上面a转换引用对象的过程,是自动完成的。而当b=7的时候,并不是在内存中从新建立一个对象7,而是b引用了已有的对象。这就是python的所谓动态语言的特点。 69 | 70 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/22101.png) 71 | 72 | 当然,可以给任何对象取名字,或者说为任何对象都可以建立一个所引用的变量。比如函数、类都可以,此处不赘述,前面已经多次用到了。 73 | 74 | 现在已经又一次明确了,每个名称(命名)——英文中的NAME有动词和名字两种,所以,由于中文的特点,似乎怎么说都可以,只要明白所指,因为中文是强调语境的语言——都与某个对象有对应关系。那么所谓的命名空间,就是这些命名(名称)的集合,它们分别与相应的对象有对应关系。 75 | 76 | 用一句比较学术化的语言说: 77 | 78 | **命名空间是从所定义的命名到对象的映射集合。** 79 | 80 | 不同的命名空间,可以同时存在,当彼此相互独立互不干扰。 81 | 82 | 命名空间因为对象的不同,也有所区别,可以分为如下几种: 83 | 84 | - 内置命名空间(Built-in Namespaces):Python运行起来,它们就存在了。内置函数的命名空间都属于内置命名空间,所以,我们可以在任何程序中直接运行它们,比如前面的id(),不需要做什么操作,拿过来就直接使用了。 85 | - 全局命名空间(Module:Global Namespaces):每个模块创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间,也会因为模块的不同而不相互干扰。 86 | - 本地命名空间(Function&Class: Local Namespaces):模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间。如果函数返回了结果或者抛出异常,则本地命名空间也结束了。 87 | 88 | 从网上盗取了一张图,展示一下上述三种命名空间的关系 89 | 90 | ![](https://raw.githubusercontent.com/qiwsir/ITArticles/master/Pictures/22102.png) 91 | 92 | 那么程序在查询上述三种命名空间的时候,就按照从里到外的顺序,即:Local Namespaces --> Global Namesspaces --> Built-in Namesspaces 93 | 94 | 还要补充说一下,既然命名空间中存在着命名和对象的映射,不知道看官看到这句话能想到什么?启发一下,回忆以往学过的那种类型数据也存在对应关系呢?字典,就是那个dictionary,是“键值”对应的,例如:{"name":"qiwsir","lang":"python"} 95 | 96 | >>> def foo(num,str): 97 | ... name = "qiwsir" 98 | ... print locals() 99 | ... 100 | >>> foo(221,"qiwsir.github.io") 101 | {'num': 221, 'name': 'qiwsir', 'str': 'qiwsir.github.io'} 102 | >>> 103 | 104 | 这是一个访问本地命名空间的方法,用print locals() 完成,从这个结果中不难看出,所谓的命名空间中的数据存储结构和dictionary是一样的。 105 | 106 | 根据习惯,看官估计已经猜测到了,如果访问全局命名空间,可以使用 print globals()。 107 | 108 | ##作用域 109 | 110 | 作用域是指 Python 程序可以直接访问到的命名空间。“直接访问”在这里意味着访问命名空间中的命名时无需加入附加的修饰符。(这句话是从网上抄来的) 111 | 112 | 程序也是按照搜索命名空间的顺序,搜索相应空间的能够访问到的作用域。 113 | 114 | def outer_foo(): 115 | b = 20 116 | def inner_foo(): 117 | c = 30 118 | a = 10 119 | 120 | 加入我现在位于inner_foo()函数内,那么c对我来讲就在本地作用域,而b和a就不是。如果我在inner_foo()内再做:b=50,这其实是在本地命名空间内新创建了对象,和上一层中的b=20毫不相干。可以看下面的例子: 121 | 122 | 123 | #!/usr/bin/env python 124 | #coding:utf-8 125 | 126 | def outer_foo(): 127 | a = 10 128 | def inner_foo(): 129 | a = 20 130 | print "inner_foo,a=",a #a=20 131 | 132 | inner_foo() 133 | print "outer_foo,a=",a #a=10 134 | 135 | a = 30 136 | outer_foo() 137 | print "a=",a #a=30 138 | 139 | #运行结果 140 | 141 | inner_foo,a= 20 142 | outer_foo,a= 10 143 | a= 30 144 | 145 | 如果要将某个变量在任何地方都使用,且能够关联,那么在函数内就使用global 声明,其实就是曾经讲过的全局变量。请参考[《变量和参数》](./213.md) 146 | -------------------------------------------------------------------------------- /200/222.md: -------------------------------------------------------------------------------- 1 | ## 类的细节 2 | 3 | 前面对类的有关内容已经描述不少了,其实话题远远没有结束,不过对于初学者,掌握这些已经算是入门,在以后的实践中,还需要进行体会和感悟。 4 | 5 | 这几天和几个朋友以各种途径讨论过OOP的相关问题,他们是:令狐虫、Frank、晋剑、小冯 6 | 7 | 大家对OOP有不同看法,所谓工程派和学院派看法不一致。从应用的角度看,工程派的观点是值得推荐的,那就是:不用太在意内部是怎么工作的,只要能够解决眼下的问题即可。但是,对于学习者而言,如果仅仅停留在工程派的层面(特别提醒,上述几位朋友都是工程派的大侠,他们可不是简单地能够使用,其实是更高层次的“无招胜有招”),学习者可能感觉有点不透彻。所以,学习者,特别是初学者,要知道一些内部原因,但是也别为了钻研内部原因而忘记了应用的目的。看来两者协调还是一个难办的事情。不用着急,随着实践的深入,就逐渐有体会了。 8 | 9 | 下面我根据MARK Lutz的《Learning Python》中的“大师眼中的OOP”,列一些使用OOP的常见原因。 10 | 11 | - 代码重用。这是很简单(并且是使用OOP的最主要原因)。通过支持继承,类允许通过定制来编程,而不是每次都从头开始一个项目。 12 | - 封装。在对象接口后包装其实现的细节,从而隔离了代码的修改对用户产生的影响。 13 | - 结构。类提供了一个新的本地作用域,最小化了变量名冲突。他们还提供了一种编写和查找实现代码,以及去管理对象状态的自然场所。 14 | - 维护性。类自然而然地促进了代码的分解,这让我们减少了冗余。对亏支持类的结构以及代码重用,这样每次只需要修改代码中一个拷贝就可以了。 15 | - 一致性。类和继承可以实现通用的接口。这样代码不仅有了统一的外表和观感,还简化了代码的调试、理解以及维护。 16 | - 多态。多态让代码更灵活和有了广泛的适用性。(这似乎是OOP的属性,不是使用它的理由) 17 | 18 | 不管怎么样,类是一个非常重要的东西,看官在学习的时候,一定要多加运用。 19 | 20 | 此外,对于python2来说,还有一个叫做“新式类”(new-style)的东西,这个对应于前面讲过的类,那么前面讲过的类就称为“经典”(classic)类。但是,对于Python3来讲,没有这种区别,二者融合。只是在Python2中,两个是有区别的。本教程在基础部分,依然不讲授新式类的问题,如果看官有兴趣,可以自己在GOOGLE中查找有关资料,也可以随着本课程深入,到下一个阶段来学习。 21 | 22 | ##绑定和无绑定方法 23 | 24 | 看官是否还记得,在学习类的方法的时候,提到过,类的方法就是函数,只不过这个函数的表现有点跟前面学过的函数不一样,比如有个self。当然,也不是必须要有的,下面看官就会看到没有self的。既然方法和函数一样,本质上都是函数,那么,函数那部分学习的时候已经明确了:函数是对象,所以,类方法也是对象。正如刚才说的,类的方法中,有的可以有self,有的可以没有。为了进行区别,进一步做了这样的定义: 25 | 26 | - 无绑定类方法对象:无self 27 | - 绑定实例方法对象:有self 28 | 29 | ###调用绑定实例方法对象 30 | 31 | >>> class MyClass: 32 | ... def foo(self,text): 33 | ... print text 34 | ... 35 | 36 | 可以用下面的方式调用实例方法 37 | 38 | >>> a = MyClass() #创建类实例 39 | >>> a.foo('qiwsir.github.io') #调用实例方法 40 | qiwsir.github.io 41 | >>> a.foo 42 | > 43 | 44 | 在这个实例方法调用的时候,其数据传递流程,在[《编写类之二方法》](./218.md)中有一张图,图中显示了,上述的调用方法中,其实已经将实例名称a传给了self,这就是调用绑定实例方法对象,有self。 45 | 46 | 上面的调用过程,还可以这样来实现: 47 | 48 | >>> a = MyClass() 49 | >>> x = a.foo #把实例a和方法函数foo绑定在一起 50 | >>> x 51 | > 52 | >>> x("qiwsir.github.io") 53 | qiwsir.github.io 54 | 55 | 在上面的调用中,其实相当于前面的调用过程的分解动作。即先将实例a和方法函数foo绑定在一起,然后赋值给x,这时候x就相当于一个简单函数一样,可以通过上述方式传入参数。这里将实例和方法函数绑定的方式就是运用点号运算(object.method_function) 56 | 57 | ###调用无绑定类方法对象 58 | 59 | 所谓类方法对象,就是不通过实例,而是用类进行点号运算来获得方法函数(ClassName.method_function) 60 | 61 | >>> a = MyClass() 62 | >>> y = MyClass.foo #这里没有用类调用 63 | >>> y 64 | 65 | 66 | 这样的调用,就得到了无绑定方法对象,但是,调用的时候必须传入实例做为第一参数,如下 67 | 68 | >>> y(a,"qiwsir.github.io") 69 | qiwsir.github.io 70 | 71 | 否则,就报错。请看官特别注意报错信息 72 | 73 | >>> y("qiwsir.github.io") 74 | Traceback (most recent call last): 75 | File "", line 1, in 76 | TypeError: unbound method foo() must be called with MyClass instance as first argument (got str instance instead) 77 | >>> 78 | 79 | 在编程实践中,似乎用实例方法调用更多一下。 80 | 81 | ##文档字符串 82 | 83 | 在写程序的时候,必须要写必要的文字说明,没别的原因,除非你的代码写的非常容易理解,特别是各种变量、函数和类等的命名任何人都能够很容易理解,否则,文字说明是不可缺少的。 84 | 85 | 在函数、类或者文件开头的部分写文档字符串说明,一般采用三重引号。这样写的最大好处是能够用help()函数看。 86 | 87 | """This is python lesson""" 88 | 89 | def start_func(arg): 90 | """This is a function.""" 91 | pass 92 | 93 | class MyClass: 94 | """Thi is my class.""" 95 | def my_method(self,arg): 96 | """This is my method.""" 97 | pass 98 | 99 | 这样的文档是必须的。 100 | 101 | 当然,在编程中,有不少地方要用“#”符号来做注释。一般用这个来注释局部。 102 | 103 | 类其实并没有结束,不过本讲座到此对类暂告一段。看官要多实践。 104 | -------------------------------------------------------------------------------- /200/224.md: -------------------------------------------------------------------------------- 1 | ## 模块的加载 2 | 3 | 不管是用import还是用`from mmmm import *`的方式导入模块,当程序运行之后,回头在看那个存储着mmmm.py文件的目录中(关于[mmmm.py文件可以看上一讲](./223.md)),多了一个文件: 4 | 5 | qw@qw-Latitude-E4300:~/Documents/ITArticles/BasicPython/codes$ ls mmm* 6 | mmmm.py mmmm.pyc 7 | 8 | 在这个目录下面,除了原来的那个mmmm.py之外,又多了一个mmmm.pyc文件,这个文件不是我写的,是哪里来的呢? 9 | 10 | 要破开此迷,需要用import的过程说起。 11 | 12 | ##import的工作流程 13 | 14 | import mmmm,并不是仅仅将mmmm.py这个文件装载到当前位置(文件内),其实是首先进行了一次运算。当mmmm.py被第一次导入的时候,python首先要对其进行编译,生成扩展名为.pyc的同名文件,然后才执行mmmm模块的代码,创建相应的对象等。就如同把大象装进冰箱,有三步要执行: 15 | 16 | 1. **搜索**。就是python要能够找到import的模块。怎么找到,后面讲述。 17 | 2. **编译**。找到模块文件之后,将其编译成字节码,就是那个.pyc文件里面的(关于字节码,下面会介绍,请继续阅读)。注意,不是什么时候都编译的,只有第一次运行时候才编译,如果mmmm.py文件改变了,相当于又一个新文件,也会从新编译。其实就是.pyc文件中有一个时间戳,python会自动检查这个时间戳,如果它比同名的.py文件时间戳旧,就会从新编译。否则跳过。当然,如果根本就没有找到同名的.py源文件,只有字节码文件.pyc,那么就只能运行这个了。 18 | 3. **运行**。这就没什么好说的了,生米已经淘干净了,并且放到锅里,开始加热了,最后就只能熟饭了。执行就是前面已经编译的模块字节码文件,顺理成章要执行了。 19 | 20 | ##搜索模块 21 | 22 | 一般情况下,python会自动的完成模块搜索过程。但是,在某些情况下,或许会要求程序员来设定搜索路径。当import一个模块后,python会按照下面的顺序来找那个将要导入的模块文件 23 | 24 | 1. 程序的主目录。上一讲中,在codes这个目录中运行交互模式,这时候的主目录就是codes,当在那个交互模式中运行import mmmm的时候,就首先在codes这个目录中搜索相应的文件(找到.py之后编译成为.pyc)。当然,后面在网页编程中,看官会看到,所谓主目录是可以通过顶层文件设置的目录。 25 | 2. PYTHONPATH目录。这是一个环境变量设置,如果没有设置则滤去。如何进行环境变量设置,请看官google啦。 26 | 3. 标准库目录。已经随着Python的安装进入到计算机中的那个。 27 | 4. 任何.pth文件的内容。如果有这类文件,最后要在这类文件中搜索一下。这是一个简单的方法,在.pth文件中,加入有效目录,使之成为搜索路径。下图就是我的计算机上,存放.pth文件的位置以及里面放着的.pth文件 28 | 29 | ![](images/224_1.png) 30 | 31 | 看官也可以自己编写.pth文件,里面是有关搜索目录,保存到这里。比如,打开目录中的easy-install.pth文件,发现的内容: 32 | 33 | ![](images/224_2.png) 34 | 35 | 搜索就是这么一个过程。这里建议看官了解即可,不一定非要进行什么设置,在很多情况下,python都是会自动完成的。特别是初学者,暂且不要轻举妄动。 36 | 37 | ##重载模块 38 | 39 | 以mmmm模块为例(在这里要特别提醒看官:我这样命名是相当不好滴,只不过是为了恶搞才这样命名的)。 40 | 41 | 在一个shell里面,运行了python,并且做了如下操作: 42 | 43 | >>> import mmmm 44 | >>> mmmm.web 45 | 'https://qiwsir.github.io' 46 | 47 | 下面我再打开一个shell,编辑mmmm.py这个文件,进行适当修改: 48 | 49 | ![](images/224_3.png) 50 | 51 | 保存之后,切换到原来的那个导入了模块的交互模式: 52 | 53 | >>> mmmm.web 54 | 'https://qiwsir.github.io' 55 | 56 | 输出的跟前面的一样,没有任何变化,这是为什么呢? 57 | 58 | 原来,当导入模块的时候,只会在第一次导入时加载和执行模块代码,之后就不会重新加载或重新执行了,如果模块代码修改了,但是这里执行的还是修改之前的。 59 | 60 | 怎么实现代码修改之后,执行新的呢?一种方式就是退出原来的交互模式,再重新进入,再import mmmm。呵呵,这种方法有点麻烦。Python提供了另外一个函数——reload函数,能够实现模块的重新加载(简称重载),重载后模块代码重新执行。如下继续: 61 | 62 | >>> reload(mmmm) 63 | 64 | >>> mmmm.web 65 | 'https://qiwsir.github.io, I am writing a python book on line.' 66 | 67 | 这下就显示修改之后的内容了。 68 | 69 | 特别提醒注意: 70 | 71 | - reload是内置函数 72 | - reload(module),module是一个已经存在的模块,不是变量名。 73 | -------------------------------------------------------------------------------- /200/225.md: -------------------------------------------------------------------------------- 1 | ## 私有和专有 2 | 3 | 在任何语言中,都会规定某些对象(属性、方法、函数、类等)只能够在某个范围内访问,出了这个范围就不能访问了。这是“公”、“私”之分。此外,还会专门为某些特殊的东西指定一些特殊表示,比如类的名字就不能用class,def等,这就是保留字。除了保留字,python中还为类的名字做了某些特殊准备,就是“专有”的范畴。 4 | 5 | ##私有函数 6 | 7 | 在某些时候,会看到有一种方法命名比较特别,是以“__”双划线开头的,将这类命名的函数/方法称之为“私有函数”。 8 | 9 | 所谓私有函数,就是: 10 | 11 | - 私有函数不可以从它们的模块外面被调用 12 | - 私有类方法不能够从它们的类外面被调用 13 | - 私有属性不能够从它们的类外面被访问 14 | 15 | 跟私有对应的,就是所谓的公有啦。有的编程语言用特殊的关键词来说明某函数或方法或类是私有还是公有。但是python仅仅用名字来说明,因为python深刻理解了2k年前孔先生丘所说的“名不正言不顺”的含义。 16 | 17 | 如果一个 Python 函数,类方法,或属性的名字以两个下划线开始 (但不是结束),它是私有的;其它所有的都是公有的。类方法或者是私有 (只能在它们自已的类中使用) 或者是公有 (任何地方都可使用)。例如: 18 | 19 | class Person: 20 | def __init__(self,name): 21 | self.name = name 22 | 23 | def __work(self,salary): 24 | print "%s salary is:%d"%(self.name,salary) 25 | 26 | 这里边定义的方法'\__work()'就是一个私有方法。 27 | 28 | 下面把上面的类进行完善,然后运行,通过实例来调用这个私有方法 29 | 30 | #!/usr/bin/env python 31 | #coding:utf-8 32 | 33 | class Person: 34 | def __init__(self,name): 35 | self.name = name 36 | print self.name 37 | 38 | def __work(self,salary): 39 | print "%s salary is: %d"%(self.name,salary) 40 | 41 | if __name__=="__main__": 42 | officer = Person("Tom") 43 | officer.__work(1000) 44 | 45 | #运行结果 46 | 47 | Tom 48 | Traceback (most recent call last): 49 | File "225.py", line 14, in 50 | officer.__work(1000) 51 | AttributeError: Person instance has no attribute '__work' 52 | 53 | 从运行结果中可以看出,当运行到officer.__work(1000)的时候,报错了。并且从报错信息中说,没有该方法。这说明,这个私有方法,无法在类意外调用(其实类意外可以调用私有方法,就是太麻烦,况且也不提倡,故本教程滤去)。 54 | 55 | 下面将上述代码进行修改,成为: 56 | 57 | #!/usr/bin/env python 58 | #coding:utf-8 59 | 60 | class Person: 61 | def __init__(self,name): 62 | self.name = name 63 | print self.name 64 | 65 | def __work(self,salary): 66 | print "%s salary is: %d"%(self.name,salary) 67 | 68 | def worker(self): 69 | self.__work(500) #在类内部调用私有方法 70 | 71 | if __name__=="__main__": 72 | officer = Person("Tom") 73 | #officer.__work(1000) 74 | officer.worker() 75 | 76 | #运行结果 77 | 78 | Tom 79 | Tom salary is: 500 80 | 81 | 结果正是要得到的。看官是否理解私有方法的用法了呢? 82 | 83 | ##专有方法 84 | 85 | 如果是以双划线开头,但不是以它结尾,所命名的方法是私有方法; 86 | 87 | 如果以双划线开头,并且以双划线结尾,所命名的方法就是专有方法。 88 | 89 | 这是python规定的。所以在写程序的时候要执行,不执行就是跟python过不去,过不去就报错了。 90 | 91 | 比如前面反复提到的'\__init\__()',就是一个典型的专有方法。那么自己在写别的方法时,就不要用“__”开头和结尾了。虽然用了也大概没有什么影响,但是在可读性上就差很多了,一段程序如果可读性不好,用不了多长时间自己就看不懂了,更何况别人呢? 92 | 93 | 关于专有方法,出了'\__init\__()'之外,还有诸如:'\__str\__','\__setitem\__'等等,要向看,可以利用dir()函数在交互模式下看看某个函数里面的专有东西。当然,也可以自己定义啦。 94 | 95 | 因为'\__init\__'用的比较多,所以前面很多例子都是它。 96 | -------------------------------------------------------------------------------- /200/README.md: -------------------------------------------------------------------------------- 1 | ## 第二部分 穷千里目,上一层楼 2 | * [正规地说一句话](200/201.md) 3 | * [print能干的事情](200/202.md) 4 | * [从格式化表达式到方法](200/203.md) 5 | * [复习if语句](200/204.md) 6 | * [用while来循环](200/205.md) 7 | * [难以想象的for](200/206.md) 8 | * [关于循环的小伎俩](200/207.md) 9 | * [让人欢喜让人忧的迭代](200/208.md) 10 | * [大话题小函数(1)](200/209.md) 11 | * [大话题小函数(2)](200/210.md) 12 | * [python文档](200/211.md) 13 | * [重回函数](200/212.md) 14 | * [变量和参数](200/213.md) 15 | * [总结参数的传递](200/214.md) 16 | * [传说中的函数条规](200/215.md) 17 | * [关于类的基本认识](200/216.md) 18 | * [编写类之一创建实例](200/217.md) 19 | * [编写类之二方法](200/218.md) 20 | * [编写类之三子类](200/219.md) 21 | * [编写类之四再论继承](200/220.md) 22 | * [命名空间](200/221.md) 23 | * [类的细节](200/222.md) 24 | * [Import 模块](200/223.md) 25 | * [模块的加载](200/224.md) 26 | * [私有和专有](200/225.md) 27 | * [折腾一下目录: os.path.](200/226.md) 28 | -------------------------------------------------------------------------------- /200/images/224_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/200/images/224_1.png -------------------------------------------------------------------------------- /200/images/224_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/200/images/224_2.png -------------------------------------------------------------------------------- /200/images/224_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/200/images/224_3.png -------------------------------------------------------------------------------- /300/305.md: -------------------------------------------------------------------------------- 1 | ## 用Python操作数据库(3) 2 | 3 | 通过python操作数据库的行为,除了能够完成前面两讲中的操作之外(当然,那是比较常用的),其实任何对数据库进行的操作,都能够通过python-mysqldb来实现。 4 | 5 | ##建立数据库 6 | 7 | 在[《用python操作数据库(1)》](./303.md)中,我是通过`mysql>`写SQL语句,建立了一个名字叫做qiwsirtest的数据库,然后用下面的方式跟这个数据库连接 8 | 9 | >>> import MySQLdb 10 | >>> conn = MySQLdb.connect(host="localhost",user="root",passwd="123123",db="qiwsirtest",charset="utf8") 11 | 12 | 在上面的连接中,参数`db="qiwsirtest"`其实可以省略,如果省略,就是没有跟任何具体的数据库连接,只是连接了mysql。 13 | 14 | >>> import MySQLdb 15 | >>> conn = MySQLdb.connect("localhost","root","123123",port=3306,charset="utf8") 16 | 17 | 这种连接没有指定具体数据库,接下来就可以用类似`mysql>`交互模式下的方式进行操作。 18 | 19 | >>> conn.select_db("qiwsirtest") 20 | >>> cur = conn.cursor() 21 | >>> cur.execute("select * from users") 22 | 7L 23 | >>> cur.fetchall() 24 | ((1L, u'qiwsir', u'123123', u'qiwsir@gmail.com'), (2L, u'mypython', u'123456', u'python@gmail.com'), (3L, u'google', u'111222', u'g@gmail.com'), (4L, u'facebook', u'222333', u'f@face.book'), (5L, u'github', u'333444', u'git@hub.com'), (6L, u'docker', u'444555', u'doc@ker.com'), (7L, u'\u8001\u9f50', u'9988', u'qiwsir@gmail.com')) 25 | 26 | 用`conn.select_db()`选择要操作的数据库,然后通过指针就可以操作这个数据库了。其它的操作跟前两讲一样了。 27 | 28 | 如果不选数据库,而是要新建一个数据库,如何操作? 29 | 30 | >>> cur = conn.cursor() 31 | >>> cur.execute("create database newtest") 32 | 1L 33 | 34 | 建立数据库之后,就可以选择这个数据库,然后在这个数据库中建立一个数据表。 35 | 36 | >>> cur.execute("create table newusers (id int(2) primary key auto_increment, username varchar(20), age int(2), email text)") 37 | 0L 38 | 39 | 括号里面是引号,引号里面就是创建数据表的语句,看官一定是熟悉的。这样就在newtest这个数据库中创建了一个名为newusers的表 40 | 41 | >>> cur.execute("show tables") 42 | 1L 43 | >>> cur.fetchall() 44 | ((u'newusers',),) 45 | 46 | 这是查看表的方式。当然,看官可以在`mysql>`交互模式下查看是不是存在这个表。如下: 47 | 48 | mysql> use newtest; 49 | Reading table information for completion of table and column names 50 | You can turn off this feature to get a quicker startup with -A 51 | 52 | Database changed 53 | mysql> show tables; 54 | +-------------------+ 55 | | Tables_in_newtest | 56 | +-------------------+ 57 | | newusers | 58 | +-------------------+ 59 | 1 row in set (0.00 sec) 60 | 61 | mysql> desc newusers; 62 | +----------+-------------+------+-----+---------+----------------+ 63 | | Field | Type | Null | Key | Default | Extra | 64 | +----------+-------------+------+-----+---------+----------------+ 65 | | id | int(2) | NO | PRI | NULL | auto_increment | 66 | | username | varchar(20) | YES | | NULL | | 67 | | age | int(2) | YES | | NULL | | 68 | | email | text | YES | | NULL | | 69 | +----------+-------------+------+-----+---------+----------------+ 70 | 4 rows in set (0.00 sec) 71 | 72 | 以上就通过python-mysqldb实现了对数据库和表的建立。 73 | 74 | 当然,能建就能删除。看官可以自行尝试,在这里就不赘述,原理就是在`cur.execute()`中写SQL语句。 75 | 76 | ##关闭一切 77 | 78 | 当进行完有关数据操作之后,最后要做的就是关闭游标(指针)和连接。用如下命令实现: 79 | 80 | >>> cur.close() 81 | >>> conn.close() 82 | 83 | 注意关闭顺序,和打开的顺序相反。 84 | 85 | 为什么要关闭?这个问题有点那个了。你把房子里面都收拾好了,如果离开房子,不关门吗?不要以为自己生活在那个理想社会。树欲静而风不止,小偷在行动。更何况,如果不关闭,服务器的内容总塞着那些东西而没有释放,早晚就满了。所以,必须关闭。必须的。 86 | 87 | ##关于乱码问题 88 | 89 | 这个问题是编写web时常常困扰程序员的问题,乱码的本质来自于编码格式的设置混乱。所以,要特别提醒诸位注意。在用python-mysqldb的时候,为了放置乱码,可以做如下统一设置: 90 | 91 | 1. Python文件设置编码 utf-8(文件前面加上 #encoding=utf-8) 92 | 2. MySQL数据库charset=utf8(数据库的设置方法,可以网上搜索) 93 | 3. Python连接MySQL是加上参数 charset=utf8(在前面教程中都这么演示了,很重要) 94 | 4. 设置Python的默认编码为 utf-8 (sys.setdefaultencoding(utf-8),这个后面会讲述) 95 | 96 | 代码示例: 97 | 98 | #encoding=utf-8 99 | 100 | import sys 101 | import MySQLdb 102 | 103 | reload(sys) 104 | sys.setdefaultencoding('utf-8') 105 | 106 | db=MySQLdb.connect(user='root',charset='utf8') 107 | 108 | MySQL的配置文件设置也必须配置成utf8 设置 MySQL 的 my.cnf 文件,在 [client]/[mysqld]部分都设置默认的字符集(通常在/etc/mysql/my.cnf): 109 | 110 | [client] default-character-set = utf8 111 | [mysqld] default-character-set = utf8 112 | 113 | windows操作系统请看官自己google。 114 | -------------------------------------------------------------------------------- /300/306.md: -------------------------------------------------------------------------------- 1 | >"One does not live by bread alone,but by every word that comes from the mouth of God" 2 | >--(MATTHEW4:4) 3 | 4 | ## python开发框架 5 | 6 | 不管是python,还是php,亦或别的做web项目的语言,乃至于做其它非web项目的开发,一般都要用到一个称之为什么什么框架的东西。 7 | 8 | ##框架的基本概念 9 | 10 | 开发这对框架的认识,由于工作习惯和工作内容的不同,有很大差异,这里姑且截取[维基百科中的一种定义](http://zh.wikipedia.org/wiki/%E8%BB%9F%E9%AB%94%E6%A1%86%E6%9E%B6),之所以要给出一个定义,无非是让看官有所了解,但是是否知道这个定义,丝毫不影响后面的工作。 11 | 12 | >软件框架(Software framework),通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。 13 | 14 | >框架的功能类似于基础设施,与具体的软件应用无关,但是提供并实现最为基础的软件架构和体系。软件开发者通常依据特定的框架实现更为复杂的商业运用和业务逻辑。这样的软件应用可以在支持同一种框架的软件系统中运行。 15 | 16 | >简而言之,框架就是制定一套规范或者规则(思想),大家(程序员)在该规范或者规则(思想)下工作。或者说就是使用别人搭好的舞台,你来做表演。 17 | 18 | 我比较喜欢最后一句的解释,别人搭好舞台,我来表演。这也就是说,如果我在做web项目的时候,能够省却很多开发工作。的确是。所有,做web开发,要用一个框架。 19 | 20 | 有高手工程师鄙视框架,认为自己编写的才是王道。这方面不争论,框架是开发中很流行的东西,我还是固执地认为用框架来开发,更划算。 21 | 22 | ##python框架 23 | 24 | 有人说php(什么是php,严肃的说法,这是另外一种语言,更高雅的说法,是某个活动的汉语拼音简称)框架多,我不否认,php的开发框架的确很多很多。不过,python的web开发框架,也足够使用了,列举几种常见的web框架: 25 | 26 | - Django:这是一个被广泛应用的框架,如果看官在网上搜索,会发现很多公司在招聘的时候就说要会这个,其实这种招聘就暴露了该公司的开发水平要求不高。框架只是辅助,真正的程序员,用什么框架,都应该是根据需要而来。当然不同框架有不同的特点,需要学习一段时间。 27 | - Flask:一个用Python编写的轻量级Web应用框架。基于Werkzeug WSGI工具箱和Jinja2模板引擎。 28 | - Web2py:是一个为Python语言提供的全功能Web应用框架,旨在敏捷快速的开发Web应用,具有快速、安全以及可移植的数据库驱动的应用,兼容Google App Engine(这是google的元计算引擎,后面我会单独介绍)。 29 | - Bottle: 微型Python Web框架,遵循WSGI,说微型,是因为它只有一个文件,除Python标准库外,它不依赖于任何第三方模块。 30 | - Tornado:全称是Torado Web Server,从名字上看就可知道它可以用作Web服务器,但同时它也是一个Python Web的开发框架。最初是在FriendFeed公司的网站上使用,FaceBook收购了之后便开源了出来。 31 | - webpy: 轻量级的Python Web框架。webpy的设计理念力求精简(Keep it simple and powerful),源码很简短,只提供一个框架所必须的东西,不依赖大量的第三方模块,它没有URL路由、没有模板也没有数据库的访问。 32 | 33 | 说明:以上信息选自:http://blog.jobbole.com/72306/,这篇文章中还有别的框架,由于不是web框架,我没有选摘,有兴趣的去阅读。 34 | 35 | ##Tornado 36 | 37 | 一看到这个标题就知道,本教程中将选择使用这个框架。此前有朋友建议我用Django,首先它是一个好东西。但是,我更愿意用Tornado,为什么呢?因为......,看下边或许是理由,也或许不是。 38 | 39 | Tornado全称Tornado Web Server,是一个用Python语言写成的Web服务器兼Web应用框架,由FriendFeed公司在自己的网站FriendFeed中使用,被Facebook收购以后框架以开源软件形式开放给大众。看来Tornado的出身高贵呀,对了,如果是在天朝的看官,可能对Facebook有风闻,但是要一睹其芳容,还要努力。或者有人是不是怀疑这个地球上就没有这个网站呢?哈哈。按照某个地方的网络,它是存在的。废话不说,还是看Tornado的性能,因为选框架,一定要选好性能的,没准儿什么时候你也开发高大上的东西了。 40 | 41 | Tornado的性能是相当优异的,因为它试图解决一个被称之为“C10k”问题,就是处理大于或等于一万的并发。一万呀,这可是不小的量。(关于C10K问题,看官可以浏览:[C10k problem](http://en.wikipedia.org/wiki/C10k_problem)) 42 | 43 | 下表是和一些其他Web框架与服务器的对比,供看官参考(数据来源:https://developers.facebook.com/blog/post/301) 44 | 45 | 条件:处理器为 AMD Opteron, 主频2.4GHz, 4核 46 | 47 | |服务| 部署 | 请求/每秒| 48 | |----|-------|-----------| 49 | |Tornado| nginx, 4进程|8213| 50 | |Tornado|1个单线程进程|3353| 51 | |Django|Apache/mod_wsgi|2223| 52 | |web.py|Apache/mod_wsgi|2066| 53 | |CherryPy|独立|785| 54 | 55 | 看了这个对比表格,还有什么理由不选择Tornado呢? 56 | 57 | 就是它了——**Tornado** 58 | 59 | ##安装Tornado 60 | 61 | Tornado的官方网站:[http://www.tornadoweb.org](http://www.tornadoweb.org/en/latest/) 62 | 63 | 在官网上,有安装方法,其实,看官也可以直接在官方上学习。另外,有一个中文镜像网站,看官也可以访问:http://www.tornadoweb.cn/ 64 | 65 | 我在自己电脑中(ubuntu12.04),用下面方法安装,只需要一句话即可: 66 | 67 | pip install tornado 68 | 69 | 这是因为Tornado已经列入PyPI,因此可以通过 pip 或者 easy_install 来安装。 70 | 71 | 如果你没有安装 libcurl 的话,你需要将其单独安装到系统中。请参见下面的安装依赖一节。 72 | 73 | 如果不用这种方式安装,下面的页面中有可以供看官下载的最新源码版本和安装方式: 74 | 75 | [https://pypi.python.org/pypi/tornado/](https://pypi.python.org/pypi/tornado/) 76 | 77 | 此外,在github上也有托管,看官可以通过上述页面进入到github看源码。 78 | 79 | 最后要补充一个要点,就是上述下载的Tornado无法直接安装在windows上,如果要在windows上安装,建议使用pypm(这是一个什么东西,关于这个东西,可以访问官方文档:http://docs.activestate.com/activepython/2.6/pypm.html,说实话,我也没有用过它,只是看了看文档罢了。看官如果有使用的,可以写一个教程共享之。),如下安装: 80 | 81 | C:\> pypm install tornado 82 | 83 |
84 | 85 | [首页](./index.md)|[上一讲:用python操作数据库 3](./305.md) 86 | -------------------------------------------------------------------------------- /300/README.md: -------------------------------------------------------------------------------- 1 | ## 第三部分 昨夜西风,亭台谁登 2 | * [网站的结构:网站组成、MySQL数据库的安装和配置、MySQL的运行](300/301.md) 3 | * [通过Python连接数据库:安装python-MySQLdb,连接MySQL](300/302.md) 4 | * [用Pyton操作数据库(1):建立连接和游标,并insert and commit](300/303.md) 5 | * [用Python操作数据库(2)](300/304.md) 6 | * [用Python操作数据库(3)](300/305.md) 7 | * [python开发框架:框架介绍、Tornado安装](300/306.md) 8 | * [第一个网页分析:tornado网站的基本结构剖析](300/307.md) 9 | * [实例分析get和post](300/308.md) 10 | * [问候世界:利用GAE建立tornado框架网站](300/309.md) 11 | * [使用表单和模板:tornado模板self.render和模板变量传递](300/311.md) 12 | * [模板中的语法:tornado模板中的for,if,set等语法](300/312.md) 13 | * [静态文件以及一个项目框架](300/313.md) 14 | * [模板转义](300/314.md) 15 | -------------------------------------------------------------------------------- /400/402.md: -------------------------------------------------------------------------------- 1 | > He called the crowd with his disciples, and said to them,"If any want to become my followers, let them deny themseleves and take up their cross and follow me. For those who want to save their life will lose it, and those who lose their life for my sake, and for the sake fo the gospel, will save it. For what will it profit them to gain the whole world and forfeit their life? Indeed, what can they give in return for their life? Those who are ashamed of me and of my words in this adulterous and sinful generation, of them the Son of Man will also be ashamed when he comes in the glory of his Father with the holy angels."(MARK 9:34-38) 2 | 3 | ## 比较json/dictionary的库 4 | 5 | 在某些情况下,比较两个json/dictionary,或许这样就可以实现: 6 | 7 | >>> a 8 | {'a': 1, 'b': 2} 9 | >>> b 10 | {'a': 2, 'c': 2} 11 | >>> cmp(a,b) #-1或者1,代表两个dict不一样 12 | -1 13 | >>> c=a.copy() 14 | >>> c 15 | {'a': 1, 'b': 2} 16 | >>> cmp(a,c)  #两者相同 17 | 0 18 | 19 | 但是,这只能比较两个是不是一样,不能深入各处哪里不一样的比较结果。 20 | 21 | 有这样一个库,就能解决这个问题,它就是**json_tools** 22 | 23 | ## 安装 24 | 25 | 方法1: 26 | 27 | >>> pip install json_tools 28 | 29 | 或者 30 | 31 | >>> easy_install json_tools 32 | 33 | 方法2:到这里下载源码:https://pypi.python.org/pypi/json_tools,然后进行安装 34 | 35 | ## 比较json 36 | 37 | 首先看看都有哪些属性或者方法,用万能的实验室来看: 38 | 39 | >>> import json_tools 40 | >>> dir(json_tools) 41 | ['__builtins__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '_patch_main', '_printer_main', 'diff', 'patch', 'path', 'print_function', 'print_json', 'print_style', 'printer'] 42 | 43 | 从上面的结果中,可以看到`json_tools`的各种属性和方法。 44 | 45 | 我在一个项目中使用了diff,下面演示一下使用过程 46 | 47 | >>> a 48 | {'a': 1, 'b': 2} 49 | >>> b 50 | {'a': 2, 'c': 2} 51 | >>> json_tools.diff(a,b) 52 | [{'prev': 1, 'value': 2, 'replace': '/a'}, {'prev': 2, 'remove': '/b'}, {'add': '/c', 'value': 2}] 53 | 54 | 上面这个比较是比较简单的,显示的是b相对于a的变化,特别注意,如果是b相对a,就要这样写:`json_tools.diff(a,b)`,如果是`json_tools.diff(b,a)`,会跟上面有所不同,请看结果: 55 | 56 | >>> json_tools.diff(b,a) 57 | [{'prev': 2, 'value': 1, 'replace': '/a'}, {'prev': 2, 'remove': '/c'}, {'add': '/b', 'value': 2}] 58 | 59 | 以`json_tools(a,b)`,即b相对a发生的变化为例进行说明。 60 | 61 | - b和a都有键`'a'`,但是b相对a,键`'a'`的值发生了变化,由原来的`1`,变为了`2`。所以在比较结果的list中,有一个元素反应了这个结果`{'prev': 1, 'value': 2, 'replace': '/a'}`,其中,replace表示发生变化的键,value表示变化后即当前该键的值,prev表示该键此前的值。 62 | - b中的`'c'`相对与a,是新增的键。于是比较结果中这样反应出来:`{'add': '/c', 'value': 2}` 63 | - b相对于a没有`'b'`这个键,也就是在b中将其删除了,于是比较结果中这样来显示:`{'prev': 2, 'remove': '/c'}` 64 | 65 | 通过上述结果,就显示出来的详细的比较结果,不仅如此,还能对多层嵌套的json进行比较。例如: 66 | 67 | >>> a={"a":{"aa":{"aaa":333,"aaa2":3332},"b":22}} 68 | >>> b={"a":{"aa":{"aaa":334,"bbb":339},"b":22}} 69 | >>> json_tools.diff(a,b) 70 | [{'prev': 3332, 'remove': '/a/aa/aaa2'}, {'prev': 333, 'value': 334, 'replace': '/a/aa/aaa'}, {'add': '/a/aa/bbb', 'value': 339}] 71 | 72 | 这里就显明了发生变化的key的嵌套关系。比如`'/a/aa/aaa2'`,就表示`{"a":{"aa":{"aaa2":...}}}`的值发生了变化。 73 | 74 | 这里有了一个key的嵌套字符串,在真实的使用中,有时候需要将字符串转为json的格式,即`{'prev': 3332, 'remove': '/a/aa/aaa2'}`转化为`{"a":{"aa":{"aaa2":3332}}}`。 75 | 76 | ##将字符串组装成json格式 77 | 78 | 首先,回答前面的问题,可以自己写一个函数,实现那种组装。 79 | 80 | 但是,我是懒惰地程序员,我更喜欢python的原因就是它允许我懒惰。 81 | 82 | from itertools import izip 83 | 84 | 具体这个模块如何使用,请看官到我做过的一个小项目中看看:https://github.com/qiwsir/json-diff 85 | -------------------------------------------------------------------------------- /400/403.md: -------------------------------------------------------------------------------- 1 | ## defaultdict 模块和 namedtuple 模块 2 | 3 | author: Wuxiaolong 4 | 5 | 在Python中有一些内置的数据类型,比如int, str, list, tuple, dict等。Python的collections模块在这些内置数据类型的基础上,提供了几个额外的数据类型:namedtuple, defaultdict, deque, Counter, OrderedDict等,其中defaultdict和namedtuple是两个很实用的扩展类型。defaultdict继承自dict,namedtuple继承自tuple。 6 | 7 | ## defaultdict 8 | 9 | ###1. 简介 10 | 11 | 在使用Python原生的数据结构dict的时候,如果用d[key]这样的方式访问,当指定的key不存在时,是会抛出KeyError异常的。但是,如果使用defaultdict,只要你传入一个默认的工厂方法,那么请求一个不存在的key时, 便会调用这个工厂方法使用其结果来作为这个key的默认值。 12 | 13 | defaultdict在使用的时候需要传一个工厂函数(function_factory),defaultdict(function_factory)会构建一个类似dict的对象,该对象具有默认值,默认值通过调用工厂函数生成。 14 | 15 | ### 2. 示例 16 | 17 | 下面给一个defaultdict的使用示例: 18 | 19 | >>> from collections import defaultdict 20 | >>> s = [('xiaoming', 99), ('wu', 69), ('zhangsan', 80), ('lisi', 96), ('wu', 100), ('wu', 100), ('yuan', 98), ('xiaoming', 89)] 21 | >>> d = defaultdict(list) 22 | >>> for k, v in s: 23 | ... d[k].append(v) 24 | ... 25 | >>> d 26 | defaultdict(, {'lisi': [96], 'xiaoming': [99, 89], 'yuan': [98], 'zhangsan': [80], 'wu': [69, 100, 100]}) 27 | >>> for k,v in d.items(): 28 | ... print '%s: %s' % (k, v) 29 | ... 30 | lisi: [96] 31 | xiaoming: [99, 89] 32 | yuan: [98] 33 | zhangsan: [80] 34 | wu: [69, 100, 100] 35 | >>> 36 | 37 | 对Python比较熟悉的同学可以发现defaultdict(list)的用法和dict.setdefault(key, [])比较类似,上述代码使用setdefault实现如下: 38 | 39 | >>> s 40 | [('xiaoming', 99), ('wu', 69), ('zhangsan', 80), ('lisi', 96), ('wu', 100), ('wu', 100), ('yuan', 98), ('xiaoming', 89)] 41 | >>> d = {} 42 | >>> for k,v in s: 43 | ... d.setdefault(k, []).append(v) 44 | ... 45 | >>> d 46 | {'lisi': [96], 'xiaoming': [99, 89], 'yuan': [98], 'zhangsan': [80], 'wu': [69, 100, 100]} 47 | 48 | ### 3. 原理 49 | 50 | 从以上的例子中,我们可以基本了defaultdict的用法,下面我们可以通过help(defaultdict)了解一下defaultdict的原理。通过Python console打印出的help信息来看,我们可以发现defaultdict具有默认值主要是通过missing方法实现的,如果工厂函数不为None,则通过工厂方法返回默认值,具体如下: 51 | 52 | | __missing__(...) 53 | | __missing__(key) # Called by __getitem__ for missing key; pseudo-code: 54 | | if self.default_factory is None: raise KeyError((key,)) 55 | | self[key] = value = self.default_factory() 56 | | return value 57 | 58 | 从上面的说明中,我们可以发现一下几个需要注意的地方: 59 | 60 | 1. missing方法是在调用getitem方法发现KEY不存在时才调用的,所以,defaultdict也只会在使用d[key]或者d.getitem(key)的时候才会生成默认值;如果使用d.get(key)是不会返回默认值的,会出现KeyError; 61 | 62 | 2. defaultdict主要是通过missing方法实现,所以,我们也可以通过实现该方法来生成自己的defaultdict,代码入下 63 | 64 | ### 4. 版本 65 | 66 | defaultdict是在Python 2.5之后才加入的功能,在旧版本的Python中是不支持这个功能的,不过,知道了它的原理,我们可以自己实现一个defaultdict。 67 | 68 | try: 69 | from collections import defaultdict 70 | except: 71 | class defaultdict(dict): 72 | 73 | def __init__(self, default_factory=None, *a, **kw): 74 | if (default_factory is not None and not hasattr(default_factory, '__call__')): 75 | raise TypeError('first argument must be callable') 76 | dict.__init__(self, *a, **kw) 77 | self.default_factory = default_factory 78 | 79 | 80 | def __getitem__(self, key): 81 | try: 82 | return dict.__getitem__(self, key) 83 | except KeyError: 84 | return self.__missing__(key) 85 | 86 | def __missing__(self, key): 87 | if self.default_factory is None: 88 | raise KeyError(key) 89 | self[key] = value = self.default_factory() 90 | return value 91 | 92 | def __reduce__(self): 93 | if self.default_factory is None: 94 | args = tuple() 95 | else: 96 | args = self.default_factory, 97 | return type(self), args, None, None, self.items() 98 | 99 | def copy(self): 100 | return self.__copy__() 101 | 102 | def __copy__(self): 103 | return type(self)(self.default_factory, self) 104 | 105 | def __deepcopy__(self, memo): 106 | import copy 107 | return type(self)(self.default_factory, copy.deepcopy(self.items())) 108 | 109 | def __repr__(self): 110 | return 'defaultdict(%s, %s)' % (self.default_factory, dict.__repr__(self)) 111 | 112 | ## 二、namedtuple 113 | 114 | namedtuple主要用来产生可以使用名称来访问元素的数据对象,通常用来增强代码的可读性,在访问一些tuple类型的数据时尤其好用。其实,在大部分时候你应该使用namedtuple替代tuple,这样可以让你的代码更容易读懂,更加pythonic。举个例子: 115 | 116 | from collections import namedtuple 117 | 118 | # 变量名和namedtuple中的第一个参数一般保持一致,但也可以不一样 119 | Student = namedtuple('Student', 'id name score') 120 | # 或者 Student = namedtuple('Student', ['id', 'name', 'score']) 121 | 122 | students = [(1, 'Wu', 90), (2, 'Xing', 89), (3, 'Yuan', 98), (4, 'Wang', 95)] 123 | 124 | for s in students: 125 | stu = Student._make(s) 126 | print stu 127 | 128 | # Output: 129 | # Student(id=1, name='Wu', score=90) 130 | # Student(id=2, name='Xing', score=89) 131 | # Student(id=3, name='Yuan', score=98) 132 | # Student(id=4, name='Wang', score=95) 133 | 134 | 在上面的例子中,Student就是一个namedtuple,它和tuple的使用方法一样,可以通过index直接取,而且是只读的。这种方式比tuple容易理解多了,可以很清楚的知道每个值代表的含义。 135 | 136 | Over! 137 | 138 | var:http://segmentfault.com/blog/wuxianglong/1190000002399119?_ea=78694 139 | -------------------------------------------------------------------------------- /400/README.md: -------------------------------------------------------------------------------- 1 | ## 第四部分 暮然回首,灯火阑珊处 2 | * [requests库](400/401.md) 3 | * [比较json/dictionary的库](400/402.md) 4 | * [defaultdict 模块和 namedtuple 模块](400/403.md) 5 | -------------------------------------------------------------------------------- /500/501.md: -------------------------------------------------------------------------------- 1 | ## 基本的(字面量)值 2 | 3 | |类型|描述|语法示例| 4 | |----|----|--------| 5 | |整型|无小数部分的数|42| 6 | |长整型|大整数|42L| 7 | |浮点型|有小数部分的数|42.5, 42.5e-2| 8 | |复合型|实数(整数或浮点数)和虚数的和|38+4j, 42j| 9 | |字符串|不可变的字符序列|"foo", 'bar', """baz""", r'\n'| 10 | |Unicode|不可变的Unicode字符序列|u'foo', u"bar", u"""baz"""| 11 | -------------------------------------------------------------------------------- /500/502.md: -------------------------------------------------------------------------------- 1 | ## 运算符 2 | 3 | |运算符|描述|优先级| 4 | |------|----|------| 5 | |lambda|lambda表达式|1| 6 | |or|逻辑或|2| 7 | |and|逻辑与|3| 8 | |not|逻辑非|4| 9 | |in|成员资格测试|5| 10 | |not in|非成员资格测试|5| 11 | |is|一致性测试|6| 12 | |is not|非一致性测试|6| 13 | |<|小于|7| 14 | |>|大于|7| 15 | |<=|小于或等于|7| 16 | |>=|大于或等于|7| 17 | |==|等于|7| 18 | |!=|不等于|7| 19 | |\||按位或|8| 20 | |^|按位异或|9| 21 | |&|按位与|10| 22 | |<<|左移|11| 23 | |>>|右移|11| 24 | |+|加法|12| 25 | |-|减法|12| 26 | |*|乘法|13| 27 | |/|除法|13| 28 | |%|求余|13| 29 | |+|一元一致性|14| 30 | |-|一元不一致性|14| 31 | |~|按位补码|15| 32 | |**|幂|16| 33 | |x.attribute|特性引用|17| 34 | |x[index]|项目访问|18| 35 | |x[index1:index2[:index3]]|切片|19| 36 | |f(arg...)|函数调用|20| 37 | |(...)|将表达式加圆括号或元组显示|21| 38 | |[...]|列表显示|22| 39 | |{key:value, ...}|字典显示|23| 40 | |'expressions...'|字符串转化|24| 41 | -------------------------------------------------------------------------------- /500/503.md: -------------------------------------------------------------------------------- 1 | ## 一些重要的内建函数 2 | 3 | |函数|描述| 4 | |----|----| 5 | |abs(number)|返回一个数的绝对值| 6 | |apply(function[, args[, kwds]])|调用给定函数,可选择提供参数| 7 | |all(iterable)|如果所有iterable的元素均为真则返回True, 否则返回False| 8 | |any(iterable)|如果有任一iterable的元素为真则返回True,否则返回False| 9 | |basestring()|str和unicode抽象超类,用于检查类型| 10 | |bool(object)|返回True或False,取决于Object的布尔值| 11 | |callable(object)|检查对象是否可调用| 12 | |chr(number)|返回ASCII码为给定数字的字符| 13 | |classmethod(func)|通过一个实例方法创建类的方法| 14 | |cmp(x, y)|比较x和y——如果xy则返回证书;如果x==y,返回0| 15 | |complex(real[, imag])|返回给定实部(以及可选的虚部)的复数| 16 | |delattr(object, name)|从给定的对象中删除给定的属性| 17 | |dict([mapping-or-sequence])|构造一个字典,可选择从映射或(键、值)对组成的列表构造。
也可以使用关键字参数调用。| 18 | |dir([object])|当前可见作用于域的(大多数)名称的列表,
或者是选择性地列出给定对象的(大多数)特性| 19 | |divmod(a, b)|返回(a//b, a%b)(float类型有特殊规则)| 20 | |enumerate(iterable)|对iterable中的所有项迭代(索引,项目)对| 21 | |eval(string[, globals[, locals]])|对包含表达式的字符串进行计算。
可选择在给定的全局作用域或者局部作用域中进行| 22 | |execfile(file[, globals[, locals]])|执行一个python文件,
可选在给定全局作用域或者局部作用域中进行| 23 | |file(filename[, mode[, bufsize]])|创建给定文件名的文件,
可选择使用给定的模式和缓冲区大小| 24 | |filter(function, sequence)|返回给定序列中函数返回值的元素的列表| 25 | |float(object)|将字符串或者数值转换为float类型| 26 | |frozenset([iterable])|创建一个不可变集合,这意味着不能将添加到其它集合中| 27 | |getattr(object, name[, default])|返回给定对象中所指定的特性的值,可选择给定默认值| 28 | |globals()|返回表示当前作用域的字典| 29 | |hasattr(object, name)|检查给定的对象是否有指定的属性| 30 | |help([object])|调用内建的帮助系统,或者打印给定对象的帮助信息| 31 | |id(number)|返回给定对象的唯一ID| 32 | |input([prompt])|等同于eval(raw_input(prompt)| 33 | |int(object[, radix])|将字符串或者数字(可以提供基数)转换为整数| 34 | |isinstance(object, classinfo)|检查给定的对象object是否是给定的classinfo值的实例,
classinfo可以是类对象、类型对象或者类对象和类型对象的元组| 35 | |issubclass(class1, class2)|检查class1是否是class2的子类(每个类都是自身的子类)| 36 | |iter(object[, sentinel])|返回一个迭代器对象,可以是用于迭代序列的object_iter()迭代器
(如果object支持_getitem_方法的话),或者提供一个sentinel,
迭代器会在每次迭代中调用object,直到返回sentinel| 37 | |len(object)|返回给定对象的长度(项的个数)| 38 | |list([sequence])|构造一个列表,可选择使用与所提供序列squence相同的项| 39 | |locals()|返回表示当前局部作用域的字典(不要修改这个字典)| 40 | |long(object[, radix])|将字符串(可选择使用给定的基数radix)或者数字转化为长整型| 41 | |map(function, sequence, ...)|创建由给定函数function应用到所提供列表sequence每个项目时返回的值组成的列表| 42 | |max(object1, [object2, ...])|如果object1是非空序列,那么就返回最大的元素。
否则返回所提供参数(object1,object2...)的最大值| 43 | |min(object1, [object2, ...])|如果object1是非空序列,那么就返回最小的元素。
否则返回所提供参数(object1,object2...)的最小值| 44 | |object()|返回所有新式类的技术Object的实例| 45 | |oct(number)|将整型数转换为八进制表示的字符串| 46 | |open(filename[, mode[, bufsize]])|file的别名(在打开文件的时候使用open而不是file| 47 | |ord(char)|返回给定单字符(长度为1的字符串或者Unicode字符串)的ASCII值| 48 | |pow(x, y[, z])|返回x的y次方,可选择模除z| 49 | |property([fget[, fset[, fdel[, doc]]]])|通过一组访问器创建属性| 50 | |range([start, ]stop[, step])|使用给定的起始值(包括起始值,默认为0)和结束值(不包括)
以及步长(默认为1)返回数值范围(以列表形式)| 51 | |raw_input([prompt])|将用户输入的数据作为字符串返回,可选择使用给定的提示符prompt| 52 | |reduce(function, sequence[, initializer])|对序列的所有渐增地应用于给定的函数,
使用累积的结果作为第一个参数,
所有的项作为第二个参数,可选择给定的起始值(initializer)| 53 | |reload(module)|重载入一个已经载入的模块并将其返回| 54 | |repr(object)|返回表示对象的字符串,一般作为eval的参数使用| 55 | |reversed(sequence)|返回序列的反向迭代器| 56 | |round(float[, n])|将给定的浮点数四舍五入,小数点后保留n位(默认为0)| 57 | |set([iterable)|返回从iterable(如果给出)生成的元素集合| 58 | |setattr(object, name, value)|设定给定对象的指定属性的值为给定的值| 59 | |sorted(iterable[, cmp][,key][, reverse])|从iterable的项目中返回一个新的排序后的列表。
可选的参数和列表方法与sort中的相同| 60 | |staticmethod(func)|从一个实例方法创建静态(类)方法| 61 | |str(object)|返回表示给定对象object的格式化好的字符串| 62 | |sum(seq[, start])|返回添加到可选参数start(默认为0)中的一系列数字的和| 63 | |super(type[, obj/type)|返回给定类型(可选为实例化的)的超类| 64 | |tuple([sequence])|构造一个元祖,可选择使用同提供的序列sequence一样的项| 65 | |type(object)|返回给定对象的类型| 66 | |type(name, base, dict)|使用给定的名称、基类和作用域返回一个新的类型对象| 67 | |unichr(number)|chr的Unicode版本| 68 | |unicode(object[, encoding[, errors]])|返回给定对象的Unicode编码版本,可以给定编码方式和处理错误的模式
('strict'、'replace'或者'ignore','strict'为默认模式)| 69 | |vars([object])|返回表示局部作用域的字典,或者对应给定对象特性的字典| 70 | |xrange([start, ]stop[, step])|类似于range,但是返回的对象使用内存较少,而且只用于迭代| 71 | |zip(sequence1, ...)|返回元组的列表,每个元组包括一个给定序列中的项。
返回的列表的长度和所提供的序列的最短长度相同| 72 | -------------------------------------------------------------------------------- /500/README.md: -------------------------------------------------------------------------------- 1 | ## 第五部分 Python备忘录 2 | * [基本的(字面量)值](500/501.md) 3 | * [运算符](500/502.md) 4 | * [常用的内建函数](500/503.md) 5 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [第零部分 独上高楼,望尽天涯路](README.md) 4 | * [唠叨一些关于python的事情](001.md) 5 | * [Python现在成为美国名校中最流行的编程入门语言](reading/Python现在成为美国名校中最流行的编程入门语言.md) 6 | * [第一部分 积小流,至江海](100/README.md) 7 | * [Python环境安装](100/101.md) 8 | * [集成开发环境(IDE)](100/102.md) 9 | * [数的类型和四则运算](100/103.md) 10 | * [啰嗦的除法](100/104.md) 11 | * [开始真正编程](100/105.md) 12 | * [初识永远强大的函数](100/106.md) 13 | * [玩转字符串(1):基本概念、字符转义、字符串连接、变量与字符串关系](100/107.md) 14 | * [玩转字符串(2)](100/108.md) 15 | * [玩转字符串(3)](100/109.md) 16 | * [眼花缭乱的运算符](100/110.md) 17 | * [从if开始语句的征程](100/111.md) 18 | * [一个免费的实验室](100/112.md) 19 | * [有容乃大的list(1)](100/113.md) 20 | * [有容乃大的list(2)](100/114.md) 21 | * [有容乃大的list(3)](100/115.md) 22 | * [有容乃大的list(4)](100/116.md) 23 | * [list和str比较](100/117.md) 24 | * [画圈还不简单吗](100/118.md) 25 | * [再深点,更懂list](100/119.md) 26 | * [字典,你还记得吗?](100/120.md) 27 | * [字典的操作方法](100/121.md) 28 | * [有点简约的元组](100/122.md) 29 | * [一二三,集合了](100/123.md) 30 | * [集合的关系](100/124.md) 31 | * [Python数据类型总结](100/125.md) 32 | * [深入变量和引用对象](100/126.md) 33 | * [赋值,简单也不简单](100/127.md) 34 | * [坑爹的字符编码](100/128.md) 35 | * [做一个小游戏](100/129.md) 36 | * [不要红头文件(1): open, write, close](100/130.md) 37 | * [不要红头文件(2): os.stat, closed, mode, read, readlines, readline](100/131.md) 38 | * [第二部分 穷千里目,上一层楼](200/README.md) 39 | * [正规地说一句话](200/201.md) 40 | * [print能干的事情](200/202.md) 41 | * [从格式化表达式到方法](200/203.md) 42 | * [复习if语句](200/204.md) 43 | * [用while来循环](200/205.md) 44 | * [难以想象的for](200/206.md) 45 | * [关于循环的小伎俩](200/207.md) 46 | * [让人欢喜让人忧的迭代](200/208.md) 47 | * [大话题小函数(1)](200/209.md) 48 | * [大话题小函数(2)](200/210.md) 49 | * [python文档](200/211.md) 50 | * [重回函数](200/212.md) 51 | * [变量和参数](200/213.md) 52 | * [总结参数的传递](200/214.md) 53 | * [传说中的函数条规](200/215.md) 54 | * [关于类的基本认识](200/216.md) 55 | * [编写类之一创建实例](200/217.md) 56 | * [编写类之二方法](200/218.md) 57 | * [编写类之三子类](200/219.md) 58 | * [编写类之四再论继承](200/220.md) 59 | * [命名空间](200/221.md) 60 | * [类的细节](200/222.md) 61 | * [Import 模块](200/223.md) 62 | * [模块的加载](200/224.md) 63 | * [私有和专有](200/225.md) 64 | * [折腾一下目录: os.path.<attribute>](200/226.md) 65 | * [第三部分 昨夜西风,亭台谁登](300/README.md) 66 | * [网站的结构:网站组成、MySQL数据库的安装和配置、MySQL的运行](300/301.md) 67 | * [通过Python连接数据库:安装python-MySQLdb,连接MySQL](300/302.md) 68 | * [用Pyton操作数据库(1):建立连接和游标,并insert and commit](300/303.md) 69 | * [用Python操作数据库(2)](300/304.md) 70 | * [用Python操作数据库(3)](300/305.md) 71 | * [python开发框架:框架介绍、Tornado安装](300/306.md) 72 | * [第一个网页分析:tornado网站的基本结构剖析](300/307.md) 73 | * [实例分析get和post](300/308.md) 74 | * [问候世界:利用GAE建立tornado框架网站](300/309.md) 75 | * [使用表单和模板:tornado模板self.render和模板变量传递](300/311.md) 76 | * [模板中的语法:tornado模板中的for,if,set等语法](300/312.md) 77 | * [静态文件以及一个项目框架](300/313.md) 78 | * [模板转义](300/314.md) 79 | * [第四部分 暮然回首,灯火阑珊处](400/README.md) 80 | * [requests库](400/401.md) 81 | * [比较json/dictionary的库](400/402.md) 82 | * [defaultdict 模块和 namedtuple 模块](400/403.md) 83 | * [第五部分 Python备忘录](500/README.md) 84 | * [基本的(字面量)值](500/501.md) 85 | * [运算符](500/502.md) 86 | * [常用的内建函数](500/503.md) 87 | * [扩展阅读(来自网络文章)](reading/README.md) 88 | * [人生苦短,我用Python](reading/01.md) 89 | -------------------------------------------------------------------------------- /assets/12801.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/assets/12801.png -------------------------------------------------------------------------------- /assets/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/assets/python.png -------------------------------------------------------------------------------- /assets/wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/assets/wechat.jpg -------------------------------------------------------------------------------- /assets/weixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/assets/weixin.png -------------------------------------------------------------------------------- /assets/支付宝.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/assets/支付宝.jpg -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "AllenIverson", 3 | "description": "零基础学Python(第一版)", 4 | "gitbook": "3.2.3", 5 | "language": "zh-hans", 6 | "title": "零基础学Python(第一版)", 7 | "pdf": { 8 | "fontFamily": "等线" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /codes/105-1.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | #coding:utf-8 3 | 4 | """ 5 | 请计算:19+2*4-8/2 6 | """ 7 | 8 | a = 19+2*4-8/2 9 | print a 10 | -------------------------------------------------------------------------------- /codes/105.py: -------------------------------------------------------------------------------- 1 | print "Hello,World" 2 | -------------------------------------------------------------------------------- /codes/106-1.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | def add_function(a,b): 4 | c = a+b 5 | print c 6 | 7 | if __name__=="__main__": 8 | add_function(2,3) 9 | -------------------------------------------------------------------------------- /codes/109.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | print "please write your name:" 4 | 5 | name=raw_input() 6 | 7 | print "Hello,%s"%name 8 | 9 | 10 | -------------------------------------------------------------------------------- /codes/111-1.py: -------------------------------------------------------------------------------- 1 | # /usr/bin/env python 2 | #coding:utf-8 3 | 4 | print "请输入任意一个整数数字:" 5 | 6 | number = int(raw_input()) #通过raw_input()输入的数字是字符串 7 | #用int()将该字符串转化为整数 8 | 9 | if number == 10: 10 | print "您输入的数字是:%d"%number 11 | print "You are SMART." 12 | elif number > 10: 13 | print "您输入的数字是:%d"%number 14 | print "This number is more than 10." 15 | elif number < 10: 16 | print "您输入的数字是:%d"%number 17 | print "This number is less than 10." 18 | else: 19 | print "Are you a human?" 20 | 21 | -------------------------------------------------------------------------------- /codes/118-1.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | #coding:utf-8 3 | 4 | aliquot = [] 5 | 6 | for n in range(1,100): 7 | if n%3 == 0: 8 | aliquot.append(n) 9 | 10 | print aliquot 11 | -------------------------------------------------------------------------------- /codes/129-1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | import random 5 | 6 | number = random.randint(1,100) 7 | 8 | print "请输入一个100以内的自然数:" 9 | 10 | input_number = raw_input() 11 | 12 | if number == int(input_number): 13 | print "猜对了,这个数是:" 14 | print number 15 | else: 16 | print "错了。" 17 | -------------------------------------------------------------------------------- /codes/129-2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | import random 5 | 6 | number = random.randint(1,100) 7 | 8 | print "请输入一个100以内的自然数:" 9 | 10 | input_number = raw_input() 11 | 12 | if number == int(input_number): 13 | print "猜对了,这个数是:" 14 | print number 15 | elif number > int(input_number): 16 | print "小了" 17 | input_number = raw_input() 18 | elif number < int(input_number): 19 | print "大了" 20 | input_number = raw_input() 21 | else: 22 | print "错了。" 23 | -------------------------------------------------------------------------------- /codes/130.txt: -------------------------------------------------------------------------------- 1 | learn python 2 | http://qiwsir.github.io 3 | qiwsir@gmail.com 4 | hello 5 | -------------------------------------------------------------------------------- /codes/131.txt: -------------------------------------------------------------------------------- 1 | My name is qiwsir. 2 | My website is qiwsir.github.io 3 | Aha,I like program 4 | There is a baby. -------------------------------------------------------------------------------- /codes/204-1.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | #coding:utf-8 3 | 4 | print "请输入字符串,然后按下回车键:" 5 | 6 | user_input = raw_input() 7 | 8 | result = user_input.isdigit() 9 | 10 | if not result: 11 | print "您输入的不完全是数字" 12 | 13 | elif int(user_input)%2==0: 14 | print "您输入的是一个偶数" 15 | elif int(user_input)%2!=0: 16 | print "您输入的是一个奇数" 17 | else: 18 | print "您没有输入什么呢吧" 19 | -------------------------------------------------------------------------------- /codes/204-2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | import random 5 | 6 | numbers = [random.randint(1,100) for i in range(20)] 7 | 8 | """ 9 | odd = [] 10 | even = [] 11 | 12 | for x in numbers: 13 | if x%2==0: 14 | even.append(x) 15 | else: 16 | odd.append(x) 17 | """ 18 | 19 | odd = [x for x in numbers if x%2!=0] 20 | even = [x for x in numbers if x%2==0] 21 | 22 | print numbers 23 | print "odd:",odd 24 | print "even:",even 25 | -------------------------------------------------------------------------------- /codes/205-1.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | #coding:UTF-8 3 | 4 | import random 5 | i=0 6 | while i < 4: 7 | print'********************************' 8 | num = input('请您输入0到9任一个数:') 9 | 10 | xnum = random.randint(0,9) 11 | 12 | x = 3 - i 13 | 14 | if num == xnum: 15 | print'运气真好,您猜对了!' 16 | break 17 | elif num > xnum: 18 | print'''您猜大了!\n哈哈,正确答案是:%s\n您还有%s次机会!''' %(xnum,x) 19 | elif num < xnum: 20 | print'''您猜小了!\n哈哈,正确答案是:%s\n您还有%s次机会!''' %(xnum,x) 21 | print'********************************' 22 | i += 1 23 | 24 | """ 25 | 此代码是一个名曰李航的大学生发给我的,我用在了教程中 26 | """ 27 | -------------------------------------------------------------------------------- /codes/205-2.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | This is a game. 4 | I am Qiwei. 5 | I like python. 6 | I am writing python articles in my website. 7 | My website is http://qiwsir.github.io 8 | You can learn python free in it. 9 | """ 10 | 11 | #!/usr/bin/env python 12 | #coding:utf-8 13 | 14 | import random 15 | 16 | number = random.randint(1,100) 17 | 18 | guess = 0 19 | 20 | while True: 21 | 22 | num_input = raw_input("please input one integer that is in 1 to 100:") 23 | guess +=1 24 | 25 | if not num_input.isdigit(): 26 | print "Please input interger." 27 | elif int(num_input)<0 or int(num_input)>=100: 28 | print "The number should be in 1 to 100." 29 | else: 30 | if number==int(num_input): 31 | print "OK, you are good.It is only %d, then you successed."%guess 32 | break 33 | elif number>int(num_input): 34 | print "your number is more less." 35 | elif number",x 10 | 11 | funcx() 12 | print "--------------------------" 13 | print "this x is out of funcx:-->",x 14 | 15 | -------------------------------------------------------------------------------- /codes/213-2.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | #coding:utf-8 3 | 4 | def add(x,*arg): 5 | print x 6 | result = x 7 | print arg 8 | for i in arg: 9 | result +=i 10 | return result 11 | 12 | print add(1,2,3,4,5,6,7,8,9) 13 | 14 | -------------------------------------------------------------------------------- /codes/217.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | """ 5 | class Person: 6 | def __init__(self, name, lang, website): 7 | self.name = name 8 | self.lang = lang 9 | self.website = website 10 | self.email = "qiwsir@gmail.com" 11 | """ 12 | class Person: 13 | def __init__(self, name, lang="golang", website="www.google.com"): 14 | self.name = name 15 | self.lang = lang 16 | self.website = website 17 | self.email = "qiwsir@gmail.com" 18 | 19 | def author(self, address): 20 | #return self.name 21 | return laoqi.name+" in "+address 22 | 23 | laoqi = Person("LaoQi") 24 | info = Person("qiwsir",lang="python",website="qiwsir.github.io") 25 | 26 | #print "laoqi.name=",laoqi.name 27 | print "Author name from laoqi:",laoqi.author("China") 28 | print "Author name from info:",info.author("Suzhou") 29 | #print "info.name=",info.name 30 | #print "-------" 31 | #print "laoqi.lang=",laoqi.lang 32 | #print "info.lang=",info.lang 33 | #print "-------" 34 | #print "laoqi.website=",laoqi.website 35 | #print "info.website=",#info.website 36 | 37 | -------------------------------------------------------------------------------- /codes/219-2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | class A: 5 | def __init__(self): 6 | print "aaa" 7 | 8 | class B(A): 9 | pass 10 | 11 | if __name__=="__main__": 12 | a = A() 13 | b = B() 14 | -------------------------------------------------------------------------------- /codes/220-2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | class A: 5 | def __init__(self): 6 | print "aaa" 7 | def amethod(self): 8 | print "method a" 9 | 10 | class B(A): 11 | def __init__(self): 12 | print "bbb" 13 | 14 | 15 | if __name__=="__main__": 16 | print "A--->" 17 | a = A() 18 | a.amethod() 19 | print "B--->" 20 | b = B() 21 | b.amethod() 22 | -------------------------------------------------------------------------------- /codes/220.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | class Person: 5 | def __init__(self, name, email): 6 | self.name = name 7 | self.email = email 8 | 9 | class Programmer(Person): 10 | def __init__(self, name,email,lang, system, website): 11 | Person.__init__(self,name,email) 12 | self.lang = lang 13 | self.system = system 14 | self.website = website 15 | 16 | class Pythoner(Programmer): 17 | def __init__(self,name,email): 18 | Programmer.__init__(self,name,email,"python","Ubuntu","qiwsir.github.io") 19 | 20 | if __name__=="__main__": 21 | writer = Pythoner("qiwsir","qiwsir@gmail.com") 22 | print "name=",writer.name 23 | print "lang=",writer.lang 24 | print "email=",writer.email 25 | print "system=",writer.system 26 | print "website=",writer.website 27 | -------------------------------------------------------------------------------- /codes/221.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | def outer_foo(): 5 | a = 10 6 | def inner_foo(): 7 | a = 20 8 | print "inner_foo,a=",a 9 | 10 | inner_foo() 11 | print "outer_foo,a=",a 12 | 13 | a = 30 14 | outer_foo() 15 | print "a=",a 16 | -------------------------------------------------------------------------------- /codes/225.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | class Person: 5 | def __init__(self,name): 6 | self.name = name 7 | print self.name 8 | 9 | def __work(self,salary): 10 | print "%s salary is: %d"%(self.name,salary) 11 | 12 | def worker(self): 13 | self.__work(500) 14 | 15 | if __name__=="__main__": 16 | officer = Person("Tom") 17 | #officer.__work(1000) 18 | officer.worker() 19 | 20 | -------------------------------------------------------------------------------- /codes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/codes/__init__.py -------------------------------------------------------------------------------- /codes/hello.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | import tornado.httpserver 5 | import tornado.ioloop 6 | import tornado.options 7 | import tornado.web 8 | 9 | from tornado.options import define, options 10 | define("port", default=8000, help="run on the given port", type=int) 11 | 12 | class IndexHandler(tornado.web.RequestHandler): 13 | def get(self): 14 | greeting = self.get_argument('greeting', 'Hello') 15 | self.write(greeting + ', welcome you to read: www.itdiffer.com') 16 | 17 | if __name__ == "__main__": 18 | tornado.options.parse_command_line() 19 | app = tornado.web.Application(handlers=[(r"/", IndexHandler)]) 20 | http_server = tornado.httpserver.HTTPServer(app) 21 | http_server.listen(options.port) 22 | tornado.ioloop.IOLoop.instance().start() 23 | -------------------------------------------------------------------------------- /codes/mmmm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | web = "https://qiwsir.github.io, I am writing a python book on line." 5 | 6 | def my_name(name): 7 | print name 8 | 9 | class pythoner: 10 | def __init__(self,lang): 11 | self.lang = lang 12 | def programmer(self): 13 | print "python programmer language is: ",self.lang 14 | -------------------------------------------------------------------------------- /codes/request_url.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | import textwrap 5 | 6 | import tornado.httpserver 7 | import tornado.ioloop 8 | import tornado.options 9 | import tornado.web 10 | 11 | from tornado.options import define, options 12 | define("port", default=8000, help="Please send email to me", type=int) 13 | 14 | class ReverseHandler(tornado.web.RequestHandler): 15 | def get(self, input_word): 16 | self.write(input_word[::-1]) 17 | 18 | 19 | class WrapHandler(tornado.web.RequestHandler): 20 | def post(self): 21 | text = self.get_argument("name") 22 | width = self.get_argument("width", 40) 23 | self.write(textwrap.fill(word, width)) 24 | 25 | if __name__ == "__main__": 26 | tornado.options.parse_command_line() 27 | app = tornado.web.Application( 28 | handlers = [ 29 | (r"/reverse/(\w+)", ReverseHandler), 30 | (r"/wrap/(/w+)", WrapHandler) 31 | ] 32 | ) 33 | http_server = tornado.httpserver.HTTPServer(app) 34 | http_server.listen(options.port) 35 | tornado.ioloop.IOLoop.instance().start() 36 | -------------------------------------------------------------------------------- /codes/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sign in your name 5 | 6 | 7 |

Please sing in.

8 |
9 |

Name:

10 |

Email:

11 |

Website:

12 |

Language:

13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /codes/template/user.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sign in your name 5 | 6 | 7 |

Your Information

8 |

Your name is {{username}}

9 |

Your email is {{email}}

10 |

Your website is {{website}}, it is very good. This website is make by {{language}}

11 | 12 | 13 | -------------------------------------------------------------------------------- /codes/template/userscontroller.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | 4 | import os.path 5 | 6 | import tornado.httpserver 7 | import tornado.ioloop 8 | import tornado.options 9 | import tornado.web 10 | 11 | from tornado.options import define, options 12 | define("port", default=8000, help="run on the given port", type=int) 13 | 14 | class IndexHandler(tornado.web.RequestHandler): 15 | def get(self): 16 | self.render("index.html") 17 | 18 | class UserHandler(tornado.web.RequestHandler): 19 | def post(self): 20 | user_name = self.get_argument("username") 21 | user_email = self.get_argument("email") 22 | user_website = self.get_argument("website") 23 | user_language = self.get_argument("language") 24 | self.render("user.html",username=user_name,email=user_email,website=user_website,language=user_language) 25 | 26 | handlers = [ 27 | (r"/", IndexHandler), 28 | (r"/user", UserHandler) 29 | ] 30 | 31 | template_path = os.path.join(os.path.dirname(__file__),"template") 32 | 33 | if __name__ == "__main__": 34 | tornado.options.parse_command_line() 35 | app = tornado.web.Application(handlers, template_path) 36 | http_server = tornado.httpserver.HTTPServer(app) 37 | http_server.listen(options.port) 38 | tornado.ioloop.IOLoop.instance().start() 39 | -------------------------------------------------------------------------------- /codes/temploop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Loop in template 5 | 6 | 7 |

There is a list, it is {{info}}

8 |

I will print the elements of this list in order.

9 | {% for element in info %} 10 |

{{element}}

11 | {% end %} 12 |
13 | {% for index,element in enumerate(info) %} 14 |

info[{{index}}] is {{element}} 15 | {% if element == "python" %} 16 |

I love this language--{{element}}

17 | {% end %} 18 | {% end %} 19 | 20 | {% if "qiwsir@gmail.com" in info %} 21 |

A Ha, this the python lesson of LaoQi, It is good! His email is {{info[2]}}

22 | {% end %} 23 |

Next, I set "python-tornado"(a string) to a variable(var)

24 | {% set var="python-tornado" %} 25 |

Would you like {{var}}?

26 | 27 | 28 | -------------------------------------------------------------------------------- /codes/temploop/index.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | 4 | import os.path 5 | import tornado.httpserver 6 | import tornado.ioloop 7 | import tornado.web 8 | import tornado.options 9 | 10 | from tornado.options import define, options 11 | define("port", default=8000, help="run on the given port", type=int) 12 | 13 | class IndexHandler(tornado.web.RequestHandler): 14 | def get(self): 15 | lst = ["python","www.itdiffer.com","qiwsir@gmail.com"] 16 | self.render("index.html", info=lst) 17 | 18 | handlers = [(r"/", IndexHandler),] 19 | 20 | template_path = os.path.join(os.path.dirname(__file__), "temploop") 21 | 22 | if __name__ == "__main__": 23 | tornado.options.parse_command_line() 24 | app = tornado.web.Application(handlers,template_path) 25 | http_server = tornado.httpserver.HTTPServer(app) 26 | http_server.listen(options.port) 27 | tornado.ioloop.IOLoop.instance().start() 28 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/cover.jpg -------------------------------------------------------------------------------- /cover.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/cover.psd -------------------------------------------------------------------------------- /cover_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/learn-python-from-zero/eec2f772f3f36fd08bf923708695d8a6d055d151/cover_small.jpg -------------------------------------------------------------------------------- /reading/Python现在成为美国名校中最流行的编程入门语言.md: -------------------------------------------------------------------------------- 1 | ## Python现在成为美国名校中最流行的编程入门语言 2 | 3 | ## 摘要 4 | 5 | 在成文之时(2014年7月),Python是美国名校中最流行的计算机编程入门语言,高校排名前10名中的8个,前39名中的24个学校的计算机科学入门课程都选择了Python。 6 | 7 | ## 成文动机 8 | 9 | Python在编程新手中变得越来越流行。3年前,Mark Guzdial贴出一篇博文,讨论了Python在教育领域呈现的上升态势,并预测了未来的编程教学语言。现在, MIT、UC Berkeley、MOOC(edX, Coursera和Udacity)都提供了Python语言的编程入门课程。一些子领域的教授也在倡导将Python作为初学者的入门语言。我开发的Online Python Tutor也验证了这一点。 10 | 11 | 因为没有明确的报告阐明Python在名校中的现状,所以,我做了一些调查,与此同时,也汇总了其他教学语言的流行情况。 12 | 13 | 为什么要分析这个现状?因为编程语言的选择反映了学校的教育哲学,同时也会影响学生对计算机科学的第一印象,与此同时,名校对编程语言的选择也会对其余学校产生影响。 14 | 15 | ## 方法 16 | 17 | 我选择了前39所学校,每所学校,我调查了CS、CSE或者EECS专业的CS0和CS1的课程,我将CS1定义为CS专业的基础课程,CS0为非主修计算机专业或者是在CS1之前需要打基础的学生开设的入门课,这里不包括小课、选修课、或者是其他专业提供的编程课,在结果中,我将CS1和CS0合并在了一起。 18 | 19 | ## 调查结果 20 | 21 | 结果如图表所示,纵坐标之和是超过39的,因为有些学校既提供了CS0,也提供了CS1。 22 | 23 | ![](../assets/python.png) 24 | 25 | ## 结果讨论 26 | 27 | 虽然我是一个Python的推动者,我还是要客观给出调查结果。 28 | 29 | Python稍稍领先Java,Java在大学先修课程(Advanced Placement Computer Science)中仍然在使用。在科学家和工程师的编程入门中,Matlab优先考虑。C++、C被逐渐替代。基于Scheme的语言只是在计算机语言研修学者中使用,在调查的39所学校中,只有3所学校使用。Scratch是K-12教育中的主角,还没有到大学的层面。 30 | 31 | 当然还有三种类型的编程语言是图表中没有涉及的,因为在统计结果中很少有学校将它们作为编程入门语言,它们是:静态函数语言(Haskell和OCaml等)、动态函数语言(JavaScript, Ruby以及PHP等)、广泛使用的开发语言(Objective-C等)。 32 | 33 | var:http://top.jobbole.com/5028/ 34 | -------------------------------------------------------------------------------- /reading/README.md: -------------------------------------------------------------------------------- 1 | ## 扩展阅读(来自网络文章) 2 | * [人生苦短,我用Python](reading/01.md) 3 | * [Python现在成为美国名校中最流行的编程入门语言](reading/Python现在成为美国名校中最流行的编程入门语言.md) 4 | --------------------------------------------------------------------------------