Python语言学习之简明python指南(预览版)
小标 2019-04-04 来源 : 阅读 1120 评论 0

摘要:本文主要向大家介绍了Python语言学习之简明python指南(预览版),通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。

本文主要向大家介绍了Python语言学习之简明python指南(预览版),通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。

Python语言学习之简明python指南(预览版)

因为,全文比较长,没有经过完整的校对,纰漏难免。

以下内容是为了方便搜索引擎索引特别加上的,不是给人看的。因此不进行频繁修补,只做积累更新(最后更新于2015年10月14日)。

PS:全文两万六千余字,目前32页,因为字数限制,不能完整复制进来。加之简书的功能实在很烂,于是图片和脚注就不一一补充了


本来这个是某系列连载文章中的第二期的第十五篇,不过限于篇幅,我觉得还是独立出来比较好。写这个指南的目的,是帮助大多数想接触python的人更方便更全面的认识这门编程语言并学会如何运用这套工具集。

与此同时我觉得现如今关于python的书大多都是多余的,它们花了很大的篇幅在讲些没用或者不相干的东西。很多书假定你对编程的理解还很模糊,假定你可能用着不同的操作系统,其实这对于大多数我的目标读者来讲,都是多余的。当然那也是出版社的无奈,我自然无所谓,我可以假定大家都用的windows,还都是xp以上,只要不影响行文就好。另外这个标题里的简明一词,是相对一本书的厚度而言的。

我最早知道python是09年,那时候还在用塞班的s60手机。后来是GAE,那时候版本还是2.5.x,不过因为已经高三了也就没去折腾。最初开始用python大概是从2012年秋季休学的时候算起,现在转眼都2.7.9了。眼看着python2的时代已然走到了尽头,虽然大家都还会继续用,只是过去的时光早已凶猛地从身边流逝了。

最初打算写关于python的教程是在2013年春。之前2011年刚高考完的时候想自己做个网站,于是2012年春的时候决定学python(主要受豆瓣的启发)。然而拖拖拉拉,直到那年秋末休学才开始投入起来。到2013年的时候基本的东西都会的差不多了,正好社团里有不少新人感兴趣,于是也打算教他们来一起玩,大概写教程的想法最早是这时候有的。后来就是一个悲剧的故事,我复学之后没能掌控好自己的节奏挂了许多课,社团这边的活动也没组织得好,外面帮公益机构做的东西也是一拖再拖直到烂尾。最后我选择降级到13级,虽然去年秋季有写些教程的草稿,但后来今年上半年因为个人问题不得不在家待半年,差不多都忘了。直到七月我回到学校,八月有人有重新跟我提起python的时候,这个中断了N次的想法才得以重新唤醒,虽然最后那个网站我并没有做出来。其实相比13/14年时候的想法,这些年来我对python的理解也有不少变化,尤其是在我接触了erlang和APL以后。这也是我决定丢掉去年的草稿重新写过的主要原因之一(另一方面是我忘记存哪了不太好找……)。

不过由于第一次写这种稍微正式一点的教程,字数会有点多。也许精简一下,或者说真正有用的部分估计不到6000字,然而这个环节要我自己察觉出来很不容易,所以如果能收到些反馈建议,而我也会对应做些改进,两全之策,岂不美哉。

另外,我建议记性不太好或者动手能力较差的,去打印一份(或者一部分)纸质版放在床头,虽然第一版是有点坑,不过我想说的其实是,有些时候纸质版的东西看上去更入眼。

目标读者

其实并没有很具体的目标,用这个二级标题只是在假装很严肃的样子。一开始定位在大一大二的小盆友(那是14年的时候,现在他们都大三大四了),不过就现在的情况发展下去,小学六年级以上也是可以的。

为什么学python?

这是很多书要跟你讲的第一章,很遗憾,我不会告诉你为什么。因为老实说python并不是一门很适合用来教学的语言,不过呢,它就是能用来偷懒,所以大家都用它。本质上来说,学会python并不是简单的学习它的语法和各种概念,而是学会读懂别人的python代码,学会自己写python,以及熟悉整个python的工具链和生态环境以致如何做项目等等。就是这样。而实际上学python是一个实践和积累的过程,也就是说本文并不能帮你太多。

准备工作

你需要装一个python解释器。我不会跟你解释具体解释器是什么鬼以及和编译器有什么差别,你所需要做的,就是理解这个过程并照着做一遍,碰到看不懂的地方,自己去搜一下或者直接问我也行->absente@live.cn。

同样的,我也不会跟你讲太多什么是python2和python3的区别。这里你只需要下载个anaconda python2的集成环境就好。

然后是编辑器。初学我觉得sublime text 3或者notepad2-mod都可以,当然如果要推荐的话,我觉得sublime和pycharm就够了。vs2015其实也可以,不过有点太重型了,而且关键是我并不太熟悉…

还有就是备上两份文档,python2和python3的。Anaconda实际上会附上一份python2的chm文档,然而要自己去目录里找出来。这里个人觉得chm文档还是够用的,当然,如果你习惯多标签阅读,那么html的更适合你,如果是电子书的话,官网也有pdf。另外我推荐用那种专门的离线文档工具,比如zealdocs(mac下的是dash)。

这里附上windows下可用的anaconda和sublime text 3以及pycharm,zeal和官方的chm/html/pdf文档:

#百度网盘链接(合集)://pan.baidu.com/s/1dD6nVn7

Python:https://www.python.org/

Anaconda://continuum.io/downloads

Sublime text 3://www.sublimetext.com/

Pycharm 4:https://www.jetbrains.com/pycharm/

Zeal / Dash:https://zealdocs.org/

装anaconda的时候一路默认next,这样python的执行路径应该也就在PATH环境变量里了,当然如果你实在是闲anaconda太大,也可以自己下个官方的Python,然后选择加到环境变量里。其实加到PATH里面并不是总是必须的,只是通常为了方便调试就成了潜规则。

语法概要

你可能觉得上来就讲语法会不会有点消化不良?其实不会的。所谓编程语言的语法,就是按照一定的符号规则去表达你的逻辑和程序流程。

在这里我觉得有必要列举一下其他语言的语法。首先是c语言(以下都是单行代码):

void main(){}

上面是一段合法且并没有什么卵用的c代码。本来想举个java的例子,不过好像不太确定怎么写,就搜了一下hello world,然后改了改,但是不确定是否一定合法,于是就放弃了。换成js:function

main(){}或者匿名函数形式的main = function(){}

然后是python:

def main(): pass或main =lambda: None

我们在这里不是要对比出什么优劣,那是西方人喜欢干的事情,而且相对没什么意义。这里我们需要做的是寻找其中的共性。比如你会发现它们都可以用圆括号来表示参数区域。

感觉真要讲语法的话,到这里就差不多了,最多给你强调一下,缩进一定要用四个空格,区块注释要用双引号。实际上python的语法并没有多复杂。很多语法关键字刚入门的话根本用不到,而且也不是那么容易搞懂(比如with和yield)。于是你只需明白几个基本概念就可以写python代码了。当然这里并不鼓励你马上去写个hello world,因为那也没什么实际意义,而且不太符合我国的教育习惯。这里我的思路是先讲点概念,然后教你怎么读懂python代码,然后再去改或者去写。当然,语法不可能就说这么点,那是开玩笑的。在讲概念之前,正经地补充点语法常识还是有必要的。

首先,python用缩进替代了大括号来限定作用域(缩进这个设定有好有坏,不过算是python比较明显的一个特征之一),当然,和传统编程语言一样,实际上限定作用域(或者说语法单元)的还是小括号。然后你可能会说为什么不强调没有分号这个问题,其实,python是允许分号的,只是依照潜规则,大家都不用而已。而且,如果你喜欢的话,还可以开启大括号缩进模式…不过出于人身安全考虑,不要这么做,这样只会被当作异教徒。

先说逻辑相关的,有几个关键字:and,or,not和is,==,!=,虽然这个用来替换&&, ||,!好像更直观了,但是有时候也会搞晕人。另外,逻辑运算的返回值只有两个,True和False,首字母大写。至于None这个是独立出来的一个值,对应C里面的null。容易搞混的地方自己动手试试最好做个笔记。is和==通常是不会等价的,所以如果一个值你能确定全等的时候,才尽量用is。用is的好处是有时候逻辑表达可以更连贯一点(有些时候计算效率也更高),比如A is B。但有时候也不一定符合表达习惯,比如A is not B。还有就是要明白,[] is []这种肯定是False的,因为不同的列表指向的内存空间肯定不同。

除了前面说到None,Python和C里面很多概念都是可以对应上的,这个往后用久了会有更多体会,但是要注意的是python也有自己提倡的一些潜规则,比如PEP8,然而这里面的很多规则实际上和C是不完全对应的,这也是我为什么个人并不提倡完全遵循pep8的原因之一。

说到这种潜规则,不得不提一下python的命名规则,变量和函数命名也是很重要的一个细节,python推荐用小写字母加下划线比如:blue_shit,如果是class的话会推荐你写作HolyShit,至于class method很多人也推荐小写加下划线(eat_shit)不过个人觉得继续用java那种小写字母开头的驼峰写法(eatShit)也不是什么坏事(毕竟Google也是这么玩的不是么)。不过通常来讲,个人自从用惯erlang之后就不再特别讲究这个了。比如前面的blue_shit可以缩写作S或BS/SB随意,有时候变量本身的意义并不是那么重要,只要不影响逻辑就好。所谓的代码可读性,其实只在你需要读懂代码的前提下才有意义,而有时候我们不用搞懂代码,只要会用就好了,这个概念比较类似道家的无用,不过外国人多半是搞不懂的。

流程控制方面,主要就是if和for,然后while用的很少(一般也就是结合yield或者来个mainloop),没有switch,switch用if和elif的组合代替。然后,python的else比较奇葩,if,for,while都可以在屁股后面加个else。if...else比较好理解,for...in后面的else只在for循环没有break的情况下最后执行(也就是补刀用,如果for没有完整走完是不会有的),while后面的else同理。然后,break跟continue是想反的,和c一样。不过python里面有个pass,这个语句没有啥作用,一般用在def后面临时写个空函数,然后结果和def a():return None是一样的。下写if分支的时候,你可以用pass临时占个位置。因为单独写个注释在build的时候还是会报错的,而补上pass就没事了。另外如果习惯了pass之后,可以用来标注某些未实现的功能,方便查找。还有就是,如果你习惯c里面的三元表达式即Z=X?A:B这种,python也提供了一个类似的语法糖即Y=A if X else B。后者可能对于印欧语系的人更为直观一点,然而对于天朝群众开讲可能还是c的写法更好记些吧。

补充说明一下,python的for和c看上去是不太一样的,因为python默认采取for in这种遍历的形式。如果要当c的for来用,一般是foriin range(N)。原理是这样的,range这个内置函数可以自动生成一个[0…9]的整数列表,然后for in会逐个提取出来赋值到i上面。

流程控制这部分,最重要的还是异常处理。老实说python的异常处理并不是很高明,只是勉强够用的那种(这方面erlang是目前做的最好的,没有之一)。一般最简形式是try…except,然后是try…except…else还有try…except…else…finally。except的意思就是catch住某个异常。最基础的异常是Exception,只要出错了都可以抓住它。else就是没异常的时候走的流程,finally就是无论怎样都会有的最后一步,之所以会有这个设定是因为缩进层级会影响到作用域。简单说,如果你在try的下一级缩进里写了个a=1,那么在try语句的外层是访问不到的,而finally可以解决这个问题因为缩进的层级是一样的。

其实try语句除了用来写这种防御性的代码,还有一个用途就算做一些判定,比如类型比较,因为对于动态语言来讲有时候你要确定一个对象的类型不一定很容易,类似isinstance这种,只能在有限个基类中做判定,无法应对那种过于未知的情况,而try就不同了,你只用确定你的假设是否正确,那就可以认为这个是足以满足需求的。实际上,我用try比较少,反而是用raise更多。这个可能是受了erlang和其他参考资料的某些影响。

剩下的,补充一下with,装饰器decorator和匿名函数lambda我放到后面再讲。这个就是个语法糖,可以免去一个子流程过程中的临时变量定义及预处理步骤或后续必要操作对整体流程的干扰,最常见的是open和with的结合,例如with open('target.txt') as f: len(f),然后你就可以省略掉f.close()这个过程了,一般都是类似这样的。不过要想自己写个with的流程,放在这里来讲就有点复杂了。

然后是操作相关的语法。这里我不太想讲yield,因为篇幅可能会更长。不过我想举个斐波那契数列的例子应该就够了。下面的代码如果看不懂也没关系,我会到后面的章节重新解释一遍,现在只要关注里面的yield就好。

图1:yield演示

然后是raise和return。return比较好理解,就是返回值,不过python里面允许忽略返回值,也就是说直接写return是合法的,即等价于return None。return和c里面比较的区别用法就是返回多个值,其原理后面讲元组的时候会补充。raise可能没那么好理解,不过通常来讲,raise是补刀用的。有时候显式地抛出异常,更利于维护整体的代码和业务逻辑。

倒数第三个是赋值,包括匹配赋值。Python里面的赋值和c以及js不太一样,比如你不能这么写:(a=(b=1))。不过你可以这么写:a=b=1。当然,还可以这么写来交换两个变量的值:a,b = b,a。这个交换赋值的原理实际上是等长元组(tuple)的匹配,即在(a,b) = (b,a)的基础上省略了括号。当然,其他编程语言里面会有用下划线来表示匿名变量,不过python没有这个强制设定,习惯的话也可以用单个下划线来表示不需要的变量,比如[_,b,_] = [1,2,3]。

倒数第二个是del,虽然python自带垃圾回收,但有时候也需要自己删除不需要的东西,比如某个集合(set)里不需要的值。

最后是print,因为这个在python3里面被踢掉了,所以放到后面意为可选。所以如果要在这一点上兼容python2和python3,有个小技巧,就是在print和括号之间加一个空格,这样在python2里面会被理解为打印一个元组,python3会理解为一次函数调用。

操作之后来讲下结构相关的语法。首先是函数构造,用def就可以了(记得处理缩进)。

至于匿名函数,python有很多限制,不能像其他脚本语言那样写好几行。类定义的话用class,允许多重继承,不过通常来讲除了用mixin之外都不推荐这么弄。导入的话用import和from…import。声明全局变量用global,python2没办法声明局部变量,这个在python3里面用local可以搞定。

基本概念

这一节会有点长,想跳过的可以先跳过,不过还是尽量看完先。

说到概念,首先是package(包)。在c里面,代码是可以很方便的include的,这种概念很原始,也很实用。就是把一断代码插到另一个地方,而且为了方便,通常都是另一端代码的开头。js也有类似的概念,效果也很相似,不过现在大多数人写js都不喜欢直接那么干了,讲究个什么命名空间(namespace),这个也是有点用的,不过也有点多余。Python里面主要靠package来维护这么一个类似namespace的概念。其实就是学java的,然而学得很挫。建立package的方法很简单。新建个文件夹abc,在底下建一个叫__init__.py的文件,那么回到abc的上级目录,在这里打开cmd,输入python –c “import abc”你会发现没有任何问题,那就对了。Import一个package跟c里面include是比较像的,不过有点不同。比如import os之后,你可以用os.listdir去调用,这样保留了os这个前缀,省得跟当前代码内的函数名冲突。当然必要的时候也可以用from os import listdir这种方式来省去package name,具体怎么用,这个看应用场景。通常标准库和成熟的第三方库,如果名字不是很长,那么用import比较多。本质上来讲,import的机制和include的机制差很多,不过不必深究,用得习惯就好。有人说python或许比较适合女生学,因为有很多包包。

还有一个概念是模块(module),指的是可以被import的东西。这个概念包含了两个概念,一个是前面说的包,另一个是python源文件,还是比较好理解的。

然后是类(class)和函数(function)。Python的类比较简陋,没有java里面的interface(接口)。另外所有的类属性和方法(method)都存储在类的一个.__dict__属性里。其实在python里并不需要掌握太多使用类的技巧,只要记得不用太多继承就好。函数的话,python是区分有名函数和匿名函数的,而且python算是强制你很多时候都别去写匿名函数。这也就是python作者的一种强迫症而已,不用太在意,偶尔用用lambda还是很方便的。类和函数的定位不同,如果之前习惯c,那么用函数会比较多,即便写几个类也可能只用staticmethod而不是property这种。如果是之前用java的估计除了一堆类还有各种类装饰器吧。说到装饰器,这是个很方便的语法糖,用类和函数都可以构造,看具体复杂度和各自喜好了。我这里先举个不太复杂的例子就好:

图2:装饰器示例

关于对象,python和js的设定其实很多还是相似的。不过没必要在意太多,一般在python里就是class+method的组合,类似js里面用一个对象然后像这样{“main”:function(){}}这样框住一坨代码。现在普遍承认的面向对象编程实际上并没有什么太多意义,所以尽量忘掉这个概念对迎接未来的软件工程应该有一定的帮助。

对象之下,还有类型(type),这个很重要。不过按理说类型是比对象更基本的概念,但是一旦引入了OOP,那么不可避免会造成这样的混淆,比如class是type还是说type可以用class定义这种新手容易搞混的问题。老实说这点其实就是python3主要想改的一个地方,那就是把类和类型设计的更规范化。不过既然我说的是Python2,那么python3之后的东西,可以自己往后再补。就像在本期前面第十八节里提到的,学点旧东西并没有啥坏处,也方便对新事物有更深的认识。当然即便是python2,在这里我们不去深究class和type的关系,只要会用就好。

关于类型,首先你要知道,python是动态类型的,不像java那么死。这个有好有坏,此处不多做分析,只要习惯这种设定就好。然后,你需要知道就是几个基本的类型和扩充类型:数字分整数int和浮点float(一般不用在意长度的问题,而实际上python里的float是c里面的double);字符串在python2里面是str,也和c一样可以当不可变的字符列表来用,基于str的有unicode类型;然后数据集方面,最基本的有列表list,然后是字典map,还有元组tuple,这三个基本的之外,还有集合set,还有基于list+tuple的有序字典ordereddict等等。简单说是这个样子的,具体后面展开。不过在这篇指南里不会过多涉及ctypes,之前有c语言基础的可以自己去了解下(比如你想使用些c里面的专用类型),毕竟现在大多数人之所以还用Cpython和Cython主要就是性能考虑和c语言的扩展性了。

有了前面的铺垫,现在来具体讲下常用的(或者说真正意义上的)一些基本概念(以及基本类型)。首先要讲的是元组。元组这个类型比较特别,因为圆括号在python里面有很多种不同的用法,当然实际上是一个意思。比如:(1)实际上并不是构造了一个元组,而是给1加了个括号表面这是一个单元,也就是说(1)不等于(1,)。再一个,[i for i in range(2)]和(i for i in range(2))的结果也是不一样的,前者构造了一个列表,后者构造了一个生成器(generator)。元组和列表的主要区别在于元组不可变(immutable),这个比较符合常规的函数式编程(FP:Functional Programming)的思想,前面提到的return多个值和交换变量的用法都是基于此。

列表是很多编程语言的基本概念,比如lisp。Python的列表基本可以对应C里面的数组(Array),不过python不限定列表内数据的类型,存什么都可以。另外列表的索引方法比较多样,比如L[-1]可以表示列表的最后一个元素,L[:]可以表示列表内的所有元素,L[::-1]可以让一个列表反转等等(这里背后用到的也是对象的__getitem__方法加上slice,即切片)。关于列表有很多常用的技巧,而且里列表在FP里面用到比较多,感兴趣的自己去了解下。

再就是字典,这个在其他编程语言里面可能叫做map(映射)或hash之类的。简单说就是一个符合key-value的数据集。字典的key具有唯一性,且key必须immutable(官方说法叫hashable,其实意思差不多)。众所周知,现在比较常见的数据传输格式比如json,里面的object实际上和dict是类似的(不过严格的json不允许把匿名函数当作value)。对于dict,用法也很多。不过本质上一个dict实际上就是tuple+list的组合,这个如果你调用一个dict的.items()就会吐出来一个这样的结构。具体表现为你可以这样解压(unpack)一个字典的所有key:[k for k,v in D]。另外dict也可以用下标,不过python的dict默认是无序(或者说不符合存储顺序)的,所以不能用像list一样用下标索引。访问一个dict的value可以通过它的某个key来访问:D[K],如果找不到的话,就会报错(KeyError)。当然更多的情况我们不太想捕获这个异常,所以用D.get(K)就好(这个其实是默认返回了None,如果想返回一个指定值比如2,可以D.get(K,2))。

Python的集合同dict一样,比较符合数学规范(这个也是有好有坏)。现在的python对于集合都支持用大括号来创建了,比如:{1,2,3}。集合的操作也很多,不过个人通常用的一个技巧就是用集合去排除一个列表里的重复元素,比如:list(set([1,2,1]))的最后结果只会留下[1,2]。当然,对于这种偏数学运算的东西,比如矩阵什么的,还是用numpy之类的第三方库比较好。

当然,最基本的两个类型我好想还没展开,即数(int,float)和字(str,unicode)。Python进行数运算的坑不是很多,除了除法和精度可能有些问题,其他都还好。字符串的问题倒是一开始可以坑掉很多人,老实说到今天我都不能完全避免被unicode坑一下,不过真正被坑的机会其实没那么多的,只要用好decode和encode方法,能够避免python2里面多数的unicode坑。

类型讲完,接下来概念只要了解一下就好,比如前面提到过的生成器,这个可以用来实现惰性求值(lazy evaluation)和协程(coroutine),而迭代器(iterator)跟生成器是个很相近的东西,具体差别老实讲我自己都说不清楚,不过对于python来讲,如果一个类具有一个能用的__iter__方法的话,那么这个类的实例就可以拿来for in遍历了。装饰器(decorator)前面讲过了,还有一个在构造方法上类似的概念叫描述符(descriptor)。用class定义的装饰器主要需要提供__call__方法(通常来讲python的类定义大多需要提供一个__init__方法做初始化),描述符则需要实现__get__和__set__。这个和dict的__getitem__和__setitem__是有差别的。类似的还有切片(slice),道理跟前几个相似,感兴趣的可以看官方文档自己了解下。

还有些常见的概念我觉得有必要顺带提一下,比如:递归(recursive),循环(loop),尾递归(tail recursion),回调(callback),同步(synchronous),异步(asynchronous,简称async),协程,操作符(也叫运算子:operator),语法糖(syntax sugar),编程范式(paradigm),函数式编程,面向对象编程(OOP:object oriented programming),多态(Polymorphism),duck typing,模式匹配(pattern

matching),声明式编程(Declarative),命令式编程(Imperative),冯诺依曼式编程语言(von Neumann language),组合子(combinator),lambda calculus,π演算,消息传递(Message passing)。

以上这些概念我不会一个个解释以及演示如何在python里面去运用,因为很多东西是python不自带或者不支持的,比如尾递归优化就需要借助第三方库,模式匹配的话python语法原生不支持。还有一些用的比较少,比如运算符重载(override)。简单说,关于递归,在python里面(stackless除外)还是少用比较好(其他关键词都是打酱油的)。

读懂代码

OK,总算进入正题。看懂python代码,从本篇指南的例子开始。我相信有些人看不太懂前面图1的yield演示,于是现在我来解释一下。图片我就不重复插了,自己翻页就好(顺�便锻炼一下自己的记忆力or码字速度)。

首先这里有两个文件:fib.py和fib_test.py,放在同一个目录下。fib.py定义了四个不同版本的函数。fib(n)的话是原始斐波那契数列的递归版本(前两个数是0和1,第三个数是前两个数之和,第四个数是第二个和第三个之和以此类推),这个好懂,简单说逻辑是这样的:如果n小于2就直接返回n,n大于2就调用前两位的fib(n)。fibonacci(max)的话用了个yield,同时还用了个变量n来计数,算是标准的生成器版本。简单说逻辑是这样的,给定一个个数上限max,第一次调用的时候,yield a,即为0,后来a变成了1,b变成了2,也就是下次调用函数的时候yield的就是1,以此类推。后面的两个函数F1和F道理是类似的,只是没有用n来计数,F1也能生成数列,不过在个数控制上会存在问题(你会看到底下输出的时候只有第三行是输出了四个数)。fib_test.py是用来测试fib.py的,第一行是导入了所有fib里的函数所以在fib_test里可以直接调用。第三行就是一次list comprehension了,这个效率很低,因为n>3之后每次fib(o)都要递归一次。第4,5行也是构造一个列表,方法一致。第6,7行可能不太好理解,因为用到了匿名函数lambda。先从右往左看起,F()调用后生成了一个generator,然后传递给了lambda,匿名函数里就是调用三次__next__方法的意思。但你不能直接在lambda里面写F().__next__(),因为这样每次都会F()重新常见一个生成器。

接下来解释一下图2里的装饰器。文件结构和图1的例子是类似的,不再解释。这里有两个装饰器,一个是函数D1。另一个是类decorator。先看装饰器做了什么,第11行前面的一次echo(T)调用就是print出一句第4行说的文本,这里是给参数T做了强制类型转换的。第12行分号前面是用D1装饰后的函数e2(T),输出结果的变化在于原来echo(T)的后面多了一句By: D1。类似的,e3是用decorator类来装饰过的echo,区别在于e3是在调用echo前多输出了一行。简单说这两个装饰器的作用都是只是在给做原函数做类似打补丁的事情,当然装饰器的复杂用法也有,比如用来模仿模式匹配的效果。现在来讲基本原理。其实构造的原理是这样的,我们先看右边的deco_test.py里的第9行和左边deco.py第7行开始的class定义,这个是装饰器的本质。echo函数作为decorator实例构造的参数传到了__init__方法里,然后绑到了实例自己的fn属性上。然后在实例调用的过程即__call__方法中,先于self.fn调用了一句print。函数构造装饰器的方法也是类似的,D1里面的W函数(一般叫做wrapper)实际上就是个包装,最后用return的W来替代原函数。而@语法糖实际上就是做了个同名函数替换的过程,即右边第6、7行可以理解为:先定义好一个e2,然后让e2 = D1(e2)。

以上差不多是前面代码的讲解,如果搞不懂的话自己写一遍试试,或者Google一下。回顾前面我写的代码,如果你了解pep8的话,可能会替我的人身安全担忧。是的,我之所以这么不符合规范地写python代码的用意,是在于让大家了解python的语法其实没有那么死,至少没有传说中那么恶心。你可以用逗号,用分号,用反斜杠,或者写一堆lambda,甚至用type函数来定义类,只要不影响代码的组织结构和debug,我觉得都是可以的。

当然,就这点代码量不足以认为可以读懂大多数的python代码,所以这里我觉得有必要多加点示例。首先是python自己的标准库。首先举个比较简单的例子:

图3:datetime模块源码概览

图中上半部分的代码是一次调用标准库的示范,即调用datetime.datetime.now()方法。假设你不知道datetime这个模块怎么用,最简单的方法其实就是去查文档或者网上找资料。稍微原始一点的,可以在命令行里面调用help(datetime.datetime.now)或者dir(datetime.datetime)这种(如果用ipython qt console的话在键入过程中会带有提示的),更原始的就是上图这种查看源代码的方式了。

但是具体来说,怎么找源码呢?最土的方法,自己在python安装目录找(通常就在lib文件夹里),或者,借助操作系统或第三方软件来搜(我偶尔也会用everything来找python的模块文件),又或者,借助编辑器/IDE的功能,这个emacs / sublime / pycharm都有,不过个人还是习惯在pycharm里面翻源码:

图4:pycharm下查看第三方库的源代码

简言之,对于想快速上手python的人来说,anaconda+pycharm+zeal无疑是最佳组合。

上述所讲主要是读python代码的方式,没有讲到具体要点。其实要读懂python代码不难,通常(对于一个有规模的python项目来讲)情况下,首先,有文档的先看文档,因为文档一般都有api reference这一块,这样可以快速理清目标的代码结构,当然如果没有文档的话,就靠pycharm之类的。通常大部分project都会带有一部分测试代码,通过测试代码来反查也是一种思路。当然,以上思路对于某些具体的代码片段并不管用,尤其是某些算法题。通常看不懂python代码有两种情况,一是不知道整个代码是怎么工作的,二是看不懂这里面写的是什么意思。前者基本上方法和思路已经说了,现在来讲下后者。先举个简单的例子:

图5:单行代码示例

上图的单行代码如果看不懂,分解就可以了。str().strip()会去掉字符串两端的空格(因为空格是默认参数),split()会以空格分割字符串列表,最后那个[::-1]前面讲过了,一个简单的逆序方法,最后‘’.join把前面的列表合并成一个字符串。

上面这个例子还是很好懂的,因为涉及的冷门技巧不多。现在再换一个:

图6:leetcode代码讨论概览

老实说,对于上面这种代码,我不指望一下就能看懂,其实,对于多数情况,只要会用会改就可以了。即,读懂python代码的关键,还是要会用先,再是改写,读懂是其次。

本来关于读代码,我觉得讲这些就差不多了,剩下的可以多练习练习,找些简单的项目源码看起。本来有想过举些稍微有点代码量的实际项目做例子的,但是感觉单讲源码分析的话会写好长,也就不好详讲,最后一个例子我们来简单分析一下某socks工具的源码:

1. 首先我们要把源码下载下来,这里只需要git clone 一下就可以了:

2. 用pycharm打开目录,上来先看一眼setup.py以及文件结构:

这一步是为了弄清楚package的依赖关系(不过这个项目的install_requires是空的所以也就没什么依赖了),有些项目可能会把这部分抽离到一个requirements.txt里面。然后我们还可以看到entry_points里面有两行,对应生成两个可执行命令console_scripts。

3. 接下来就看项目的具体用途而定了。如果是一个工具型的库(比如SQLAlchemy)那么就从__init__.py入手,当然也有人不喜欢在__init__.py里放东西(比如django),那就对应的各找各咯,思路是一样的,找一个入口。而对于非工具类的(比如我们现在看的这个),也有对应的入口,那就是它的执行文件:

然后再一步步深入,比如具体上面的tcp_server要怎么实现。

4. 最后就是改动代码和反复调试了,这里截图演示不了,就略过了,其实是最关键的一步。不过没关系,大家可以当作联系。不过上面这个例子的代码量并不大,如果觉得这个代码量不够塞牙缝的,可以换一个:https://github.com/Pylons/pyramid

以上都是比较基础的分析方法,没有借助到pycharm之类的IDE独有特性。

最后补充一下。要读懂代码呢,基础是很必要的,而基础之中的基础就是规范了。说道规范,首先是注释。python的注释分两种,而且差别其实还挺大的。注释也有很多用法,可以方便调试,可以写文档,可以做文档测试。不过总的来说,规范只有一条,那就是文档注释用三个双引号(以及前面提到过的四空格缩进),不要用单引号,具体为什么,可以自己留到后面去思考,也可以参照pep8,这里不解释。

代码调试也是基础,新手上路,首先要习惯看trackback异常。单条异常日志要倒着看,进阶之后,可以自己试着用日志来替代调试过程中临时写的print。往后,用ide的debug功能或者各种debug工具(gdb、pdb、pudb等等),或者自己手动监视locals(),再往后,也可以引入inspect和自省(interrogation)。当然,个人目前还介于print和log之间的位置,感觉基本够用了…

再就是熟悉标准库,需要的时候做点笔记也是应该的。虽然对于大多数人来讲每星期写点技术总结很困难(包括我),但试着写写还是很有帮助的,无论内容的好与坏。关于读代码的部分就讲到这里。其实从注释开始,读代码和写代码之间的章节界限就已经模糊了。

写代码

这里我只说一条原则:若无必要,勿增实体。或者反其道行之。不过由于python的语法限制,通常还是精简比较好。如果是元编程吐出来的python例外。

我记得有些c语音或java书会教你先不要用IDE,用记事本之类的文本编辑器写起,这个其实是有一定道理的,然而,这个道理并不太适合java,因为java的大部分代码并不能在一行之内搞定。当然,很多时候单靠人来纠正代码里的错误还是比较费时间的,于是就有了pyflakes、pylint之类的第三方工具。另外,说到文本编辑器,windows自带的记事本并不是一个很好的选择,如果觉得sublime比较重量级(?),那么notepad2-mod / notepad++之类的或许比较适合你。

当然,我还是假定大家可以先试用一下sublime,因为这个文本编辑器的扩展性还可以,且不如emacs那么难上手。一开始写代码,对于完全没有编程经验的人来讲,难免会有语法错误(syntax error,indentation error等等),这个还是先适应一下比较好,不然如果一上来用pycharm,结果碰到一个只有vim还没有安装权限的linux虚拟机,那就准备哭吧。关于工具的选择,无论是软件(以上)还是硬件(ssd或机械键盘),到头来还是看个人需求。

除了语法错误,还可能碰到很多其他的错误,解法嘛,一般先自己思考,不行就网上找找。当然,养成良好的代码组织习惯之后可以避免一些错误的发生。比如有的时候一个分支逻辑判断写太长,那就最好拆开来,封装涉及的实体比较多,就不要用太多继承。

说写代码的话,差不多就这样了。毕竟编码(coding)在我看来是一件很枯燥的事情,建议有目的性的写或改,比如你喜欢或有意向搞数据分析,那就不要开多一个窗口去折腾web框架。

写代码的风格也是因人而异的,有人喜欢上来写大纲一样先把结构列出来,有人喜欢编写边调试。一般来说,对于较大的项目,后者比较实际点。这里说的写代码风格和前面提到过的编程范式不是一个意思,编程范式的话有很多种分类,OO还是FP,命令式还是声明式等等。个人偏向于声明式+函数式的组合。当然这里说到优劣,也还是见仁见智的。比如我虽然习惯函数式,但并不死磕纯函数无副作用这些,毕竟实用就好。总之,接触的编程语言越多,自己的编程范式会逐渐趋于稳定,这算是从我个人经历总结出来的吧。

最后再补充点相关知识。如果需要长期编写一个项目,无论是否团队协作,最好还是引入版本控制系统(VCS,version control system),方便做变更日志记录。比如今天做了哪些改动,还差哪些没实现等等。虽然这不是VCS的标准用法,但也不违反规范。一般推荐用git和hg。hg的话比较适合那种单人玩一玩性质的项目,因为配置很简单。如果一开始定位就比较高的话,还是用git吧,这个基本上已经成为业界标准了,省得以后还要迁移。

另外,不要懒得写文档写测试,哪怕只有一点点。虽然很多时候自己也不写测试…

好啦,回到本小节最开头那句话,其实就是控制复杂度的另一种表述形式吧,或许这样说会比较好懂一点。

还有,这里可以顺便留点简单的作业题:

1.写个标准的冒泡排序(可选:用递归实现)

2.用一行代码,把当前目录下文件名中的某段固定字符串批量删除掉,长度越短越好。比如:abc-xyz.mp3和bcd-xyz.txt中的xyz。

误区

这里主要讲些常见的关于python的误区。首当其冲是python2和python3的争执。其实现在python3都到3.5了,随着新特性越来越多,守旧的人也只会继续守下去,比如我,不过个人同样支持python3的发展。之所以不用python3是有原因的,如果你开发的环境需要用到很多历史悠久的第三方库,那么用Python2通常要保险一点。如果单纯是运维的话,一般没问题,因为多数第三方库存在的问题都出现在那些关键特性的变更上,比如字符串。当初碰到过BeautifulSoup4在3.4里面处理的结果和2.7完全不同情况,最后实在无解了只能把部分方法覆盖掉敷衍了事。现在python在web领域的地位已经受js和ruby冲击得所剩无几了,除了爬虫代理各种小工具各种成熟的库以外。而在科学计算和数据分析领域,python这几年倒是增幅比较大。换句话说,工具总是要适应场景的。

关于OOP,python虽然也号称一切是面向对象的,其实并没有那么纯粹。当然个人认为还是不纯粹的好。习惯java的人可能觉得python里面没有interface会有点奇怪,不过要说python没有interface也不完全对,只是没有严格的实现而已。有个第三方库叫zope.interface,可以满足大部分需求(虽然这个库的主要功能不局限于此)。一般的python项目需要用到它的机会不多,也只有在工程量比较大情况下才会用到,比如twisted这样的。有人可能之前看到zope就觉得卧槽这是什么鬼还能用吗,不过这又是另一个误区了。

续上。很多人觉得python的所谓的哲学就像《unix编程艺术》里面描述的那样,差不多可以用simple is better来描述。其实这是一种片面的认知。首先我觉得编程语言根本就没什么哲学概念一说,用比较形象的词来说,只是一种虚无缥缈的情怀罢了。具体到python的话,只要它存在着c扩展,那就不可能simple下去,只能一味的掩盖罢了。所以真正要用好python,必须要直面python的历史。而讲到历史,这里有必要概括性科普一下zope。

Python的早期发展和zope有千丝万缕的联系。Python的作者GVR在1994年发布的1.0版本,那时候还在CWI(Centrum Wiskunde & Informatica),后来去了CNRI(Corporation for National Research Initiatives)。2000年左右,在发布了2.0之后,pythonlabs的一席人加入了Digital Creations,也就是Zope公司的前身。2003年,在完成python2.3之前,GVR离开了zope,但当初那些python的核心开发人员不少还在这家公司。好吧,其实zope是一家公司,也是他们做的一套web框架体系的名字,自然也是最早的python web框架之一。

Zope的大致思路就是仿当时的J2EE,把python当java使。这个其实是可行的,而且效果还不错,但是社区的大多数人都不太接受这种又带接口又是xml的玩法。Zope2可能接受的人还有,毕竟很酷炫还实用,直接能在浏览器里面修改业务逻辑。但zope3反而更激进了,于是到最后zope3也只相当于是个半成品。Python社区里现存的和zope相关的,还有人记得的,估计就剩plone了,但这个相对还是太复杂了,现在的人一般搞cms基本都不会考虑它。说到Web框架,中期冒出来的Django现在的普及度就很高,它是仿ruby on rails的。后期的框架都是比较轻量级的,诸如flask,tornado这些。实际上zope这一支还没死,zope3之后有了repoze这个项目,把zope的遗产解耦了,到现在还有人用的主要就ZCA(对应zope.interface)、ZODB和traversal这三个了。Repoze里面有个web框架叫bfg,后来跟一个中后期web框架pylons合并了,成了今天的pyramid(我主要用的就是这个)。虽然pyramid相对django来说可能没那么方便快捷,不过熟悉的过程中倒是让我对python的发展有了更深刻的认识。

科普zope就到这里,我想说的其实只是希望做选择的时候还是尽量盲从(没看错,这样省时间),但还是要广开思路,不要局限了自己的视野。Pyramid是我觉得python里面最实用的web框架,但限于历史背景,很多人都对这个代码量巨大的框架有一种畏惧心理,这大可不必操心。经得起时间考验的开源项目就这个好处,实在不行了自己改一改就好。

关于python的语法,误区不多,缩进、分号都不是什么大问题。坑人比较多的还是逻辑判断,比如前面有提到过的is语句。if语句也是,有时候省略一些描述觉得像if a这样会省事,但需求改了之后可能限定a的条件可能就是另一个意思了,因为if语句默认None和False是归为一类的,还包括空列表等等。

关于python,我觉得最大的误区可能还是认为什么都可以用python来做。其实也不是不可以,但多数情况这是不科学的。我举个例子,VCS里面,现在主流的三个有SVN,Hg和git。豆瓣早年觉得hg是用python写的,应该好扩展吧,结果最后还是把代码库整体切换到了git上面。有时候就是这么现实。类似的还有个例子,现在自动编译代码或者部署之类的,多少会用到makefile,但是python历史上出现过buildout这样的东西,就是完全靠python实现项目的部署等一系列操作。我觉得这个没有流行起来是也有原因的,既然makefile用的人那么多也不难学,为何要多了解一个更复杂的体系呢?

还有,有的人觉得有了pip就可以不用easy_install了,实际上这么讲也不科学。而实际情况,easy_install要比pip好用的多。因为多数环境下你根本不需要用到uninstall这个功能,而且,现在的virtualenv都是一次性的,出问题了就重新建一个,也不费事。

效率问题可能也有很多人在意,但也有很多人不在意。而我觉得,不把效率当回事才是真正的陷入误区了。有些事情,能用一个for循环何必用两个呢?可以硬编码的,何必要放到数据库里面?所以说,环保节能,要从我做起。

设计模式也是常困惑新手的一个问题,python到底需不需要类似java里面那样的设计模式。其实是有的,但不多,一般只要搞懂adapter和factory就够了。认为需要完全照搬或者完全不需要的,那都是走极端。

另外,有些人觉得python在windows下开发会很痛苦,其实那只是一些没用过msbuild的人的臆想。当然,在windows系统上摸索编译c扩展是一件很累人的事情,这里给个参考,大致的流程就是:装好visual studio(2008以上的express或2015社区版都可以),还有系统对应的windows sdk(一般来说win7sdk比较通用);然后打开vs的命令行(分64位和32位,这里以64位为例),设置两个参数( set DISTUTILS_USER_SDK=1和setenv /x64 /release ),然后再用python setup.py就可以了。

而说到误区,我觉得最严重的,可能是关于python所谓的胶水语言的这个定位。很多人以为python作为胶水语言是为其他各工具集之间建立桥梁,实则不然。我觉得胶水语言的本质,是用来缝合历史遗留问题与当今环境之间裂隙的,说简单点,就是用来弥补一些类似c语言这样的旧工具的不足之处,以便让这些旧工具能适应新时代的需求。

最后,请不要忽略测试代码的重要性。再次强调。但,是不是说代码测试通过了就一定管用呢?这个还看你的测试覆盖率,但,即便是100%的覆盖率,也不等价于你的代码就没有任何问题了。这里没有绝对的因果关系,只有可能和不可能。以上内容主要是对新手而言的,如果你觉得这些误区你都了解,那么就该看一下沈崴当年留下的幻灯片《python编程艺术》里面关于误区部分的深入探讨了。

参考资料

本来想在这里留一些参考资料的,但是想想,除了那些文档链接以外,好像也没什么特别的。找东西,能用google就google吧,不能用就先翻过去。以下可以算作附录,也就列举写python相关的第三方库和工具的名字:

数据/计算:sqlite、bsddb、mysql、sqlalchemy、redis、mongodb、zodb、numpy、scikit、pandas、PIL、matplotlib、openxml、cython、pypy

实用/基础:anaconda(conda)|ipython(notebook,

kernel)、pywin32、setuptools、virtualenv、pip、buildout、mr.developer、nose、mock、uncompyle、pdb、pudb、fn、toolz、patterns、pyrsistent、pp、multipledispatch、gevent、pyqt、pygments、sphinx、you-get、sh、zope.interface

Web /网络:django、flask/jinja2、bottle、tornado、pyramid、zope2、webtest、beautifulsoup、requests、twisted、scrapy、httpie、oauth、lamson、shadowsocks、celery、rabbitmq、fabric、saltstack、sentry、planet、pelican

暂时就想到这些,我书读得少,见识不广,有些库也只是道听途说,和web开发不相干的就更不知道了,以后有好东西再慢慢填充吧。顺便科普一下pypi(python package index),这个相当于node.js里面的npm,用easy_install安装东西,默认都要先在这里面找一遍。当然,如果自己用东西打算开源,除了在github上放代码,也推荐在pypi上传自己的包。

新手路线

# 简书有字数限制,此章略去绝大部分

Ok,回到我自己的新手路线。除了文档,其他还比较有帮助的,就是一些陈旧的资料了,比如limodou(李迎辉)的博客。他是文本编辑器ulipad以及web框架uliweb的作者。记得他有用过好几个博客,donews的比较早,百度空间也有,后来百度空间停服了,那部分资料估计现在也找不到了。Stackoverflow上的问答资料也帮到过不少忙,即便像pyramid这样冷门的框架,上面依然能看到一些优质的问答,其中还包括一些web框架作者的解答,总之很多很多。然后还有其他一些国内的早期python人物,比如前面提到过的沈崴(邮件列表里人称沈游侠),他的网易博客也留下了不少有用的文章,当然最具代表性的还是他那个《python编程艺术》的幻灯片。一开始看的时候心里想这特么什么鬼,后来过了两年回过头来看才觉得这人当年是何等的牛逼。

同时期的我记得还有赖永浩和潘俊勇。老潘当年推zope几乎是不留余地,可惜我开始接触zodb的时候,已经是N年后的事情了,不过当年留下的一些翻译文档还是有些帮助(另外还有EryxLee写的一些pyramid教程),不知道现在还能否找到。科学计算方面,当年有个张若愚,还出了本书,虽然有些过时不过看着也挺不错的,貌似曾经说要出第二版,不知道情况如何。同时期相对年轻点的,还有清风,张沈鹏(人称教主),剩下的有影响力的我记着好像就没几个了,也许现在还活跃在知乎或类似的地方打打嘴炮,好像也没啥了,不少也早转方向了。

当然这些国内的python大牛,我记得好像都是从啄木鸟社区和python-cn的邮件列表找到的。而说到啄木鸟社区和python-cn的邮件列表,由不得不提一下国内python圈里面广为人知的大妈:zoom.quiet。此人对早期国内python社区的发展做出了很大的贡献,虽然有些方面的意见不敢苟同,但其付出是值得肯定的,包括好几次pycon的筹办工作,虽然pycon没几届办的特别好的,但也算是挺不容易的吧。国内的Pycon,老实讲我都没太明白它的定位,虽然不能跟国内的ruby conf比,但或许还是有些存在价值吧。

我记得前面开始水zope的时候有讲过:历史很重要。是的,我的新手路线离不开对python历史的各种花式挖坟,国外的也好、国内的也好,基本都被我扒过了。而挖python历史的过程对我个人也有不少帮助,因为你会意识到某种历史的局限性,例如你会渐渐地会明白python3的各种纷争以及未来python的发展趋势。

我觉得可以一句话概括Python的宿命:领导者是对的,然而并没有什么卵用。这个不仅体现在python的core team,比如当年做出py3k决定这件事情。我也觉得搞python3是对的,但是,不向下兼容的话,那也只能等历史来完成这个漫长的过渡过程了。同样的,在国内python社区也是这个问题,管事的那帮人想法也是对的,但是,现在这个年代坚持用着google邮件列表真的好吗?自己搞一个像erlang一样的独立邮件列表或者ruby-china一样的官方论坛会死啊?

谁知道呢,我也不是没跟人提过这个事情。而,整个学习python过程中我最不爽的问题就是这个,本来好好的一个python社区,随着09年天朝局域网体系的确立,变得分崩离析。如果不是因为大部分人上不了google,或者说非gmail后来根本收不了里面的群发邮件,v2ex后来也不会有那么多玩python的人在里面。我也知道,国内还有个水木清华,还有个python贴吧,但说真的,最早那一批玩python的死守google邮件列表的结果就是必将导致python社区的断层,而历史将无法得到延续,更别提文化的传承。

如果要我给他们提个建议,也很简单:去google化,接地气;面向大众,走向中立。今时今日的google早已不是曾经的google了,python在脚本语言中的地位也开始受到更多的挑战,做出些艰难的决定,有时也是必要的。当然,即便python在中国做不活社区,我也觉得没啥,毕竟相濡以沫,不如相忘于江湖。而我最初喜欢python的,也是这种感觉。

写这篇东西的用意,一方面是希望能帮助到新接触python的人,或者学习过程中遇到了跟我类似问题的人,能够有个参考指南,不至于犯太多同样的低级错误。虽然很多时候犯错是无可避免的,于是真正有点用处的,也只是让很多新人能够了解一部分python在国内发展的前世今生。虽然我所说很主观不完整也不一定对,但也是某种角度的参考吧,毕竟国内很少有人像我这样凭空扯淡这么多字数的吧,囧。

其实曾经也有人跟我有着类似的想法,或者说我之所以有写这个打算,完全是受前人的影响。在国内python社区发展的比较好的那个年代,那时候google还没被墙掉,有一本挺不错的书叫《可爱的python》。一开始我以为这是一本给新手看的书,然而我错了,可能当初大妈编辑的时候也觉得书的定位应该偏向新人,结果效果恰恰相反。这本书一开始我看的时候是云里雾里,因为我用的主力系统不是linux,有些东西没办法实操,加上章节安排有段混乱(比我现在写的这个还混乱),读起来也费劲。而且,我至今没搞懂那个CDays是什么意思。后来再看的时候我又觉得,里面很多东西都过时了,好像除了怀旧并没有什么其他用途。不过再后来我就发现读这本书是一个了解国内python历史的绝佳途径,而且里面的一些小贴士(书里写作作弊条,cheatsheet)也挺实用的。

当然,很多python书籍还是不错的。挑选一本好书要看很多方面,封面设计、排版、标题、厚度、作者经历、译者水平以及出版社也都包括在内,看多自然就会挑了,没有捷径。

真·新手路线

首先我想提一下图形界面这一块,先声明,个人不建议拿python搞GUI。你会发现,在前面的参考资料部分,我都没有提到wxpython。wx还是有不少人在用的,而我只是象征性的放了一个pyqt。这么做或者说不推荐GUI开发时有原因的,毕竟是python比较明显的一个鸡肋领域。如果真要弄,自带的tkinter基本就够了,pyqt我觉得学习成本不亚于twisted。而安卓方面,虽然现在有个叫kivy的项目,GVR也推了,然而(github上的关注了居然比pyramid还低)。所以,不要误入歧途。讲真,如果要搞,现在c++/java/.net甚至js都比python要实在。

然后是科学计算和数据分析领域,这个是目前python比较火的一个地方。如果你对这个感兴趣,那可能就会明白我推荐安装anaconda的用意。前面提到的有些库也是这个领域常用的,比如numpy / cython / matplotlib / pandas等等。但毕竟没接触过这个领域,所以其他有用的东西我可能还没来得及接触,仅仅是有耳闻的那种。不过ipython倒是比较常用,因为这个不分领域,qt console能爆官方命令行十几条街,用过之后就不愿换回来了。不过据我一些在公司里做DA(数据分析)的同学讲,其实真正用python的时候并不是很多。

然后是网络这一块,python还是有一定优势的,因为库比较成熟,比如twisted这种。虽然twisted也跟zope一样很多人见了就怕,实际上也没那么夸张啦,一旦习惯了ZCA这种设定,再多的python代码看上去都不会觉得太恶心。爬虫方面,python也是比较成熟的,抓站之流比较出名的有scrapy。网络安全方面我不是很了解,感兴趣的自己去google一下。

Web开发这块,水比较深,我接触的也最多,于是打算放到后面来讲。一般上来都会选个框架,主流的是django,选它不会错,就看习不习惯了。次一点的有flask和tornado,在国内都有些创业公司用在生产环境上了。Bottle/web.py也有人用,不过相对比较少。而且bottle其实往深了讲,适合入门但并不太适合新手作为主力长期使用。其他更冷门的框架也有人用,比如web2py,比如pyramid。

我这里可以简要概括一下几个框架的主要特点:首先是django。Django最开始是仿rails这个应该都明白了,但是概念上有些许不同。比较适合快速开发,用起来也是简单粗暴。现成的扩展很多,比如你想给自己的项目加个sentry的支持,一搜就能找到django-sentry。而且整个工具链都很齐全,数据库迁移(db migrate)什么的也已经很成熟了。但是,选择django意味着丧失了一定的可定制性。因为实际上你不肯能真正去改动django的源码,太多了,10M的大小啊。而且,即便你想给django修点bug或者加点新功能,也不是那么简单的事情。

相比之下,轻量级的框架就容易些,比如flask和bottle。用flask的人多主要原因可能是集成度比较高且扩展多。至少,flask记成的自家模板jinja2要甩bottle的原生模板几条街。而Bottle的买点无非是单文件import,这个其实也是最大的局限性。Flask的问题在于扩展多了,感觉和django也没啥区别,而且集成度可能还没django做的好。我就记得以前用flask的时候,加上flask-alchemy老出错,但是自己手动接入sqlalchemy一点问题都没有。

Tornado这个框架相对比较特别,因为说它是框架其实并不严谨。其实它应该是web.py的威力加强版。目标和django一样也是大而全,但是整体架构还算轻量级。因为我没试过这款,不太好对这个框架做过多的评价。优势可能是集成前端交互比较方便,还自带了server端的功能,应该来说是最适合新手的一款。缺点,也许是异步回调的一些写法不太符合python的风格(实际上也可以用同步逻辑写)。

高度集成的框架里有一个极端叫Web2py,被人吐槽的很多。然而做些小站点也没有传说的那么糟糕,你看前面提到过的张若愚,他不照样用的很舒坦。

我的选择是pyramid,当初选择的理由是我观察到python的web框架的发展呈现出一个整体发散的趋势,而pyramid在那个时候是由两个框架合并过来的(即repoze.bfg+pylons),这一点我觉得挺有意思。深入了解之后,我发repoze.bfg原来继承了zope一脉的traversal功能,这个我挺喜欢的,还有chameleon模板等等。我比较喜欢这种有实力的项目,即便它看上去不那么出众,但是感觉很适合自己。总之,每个人都有自己的喜好,但有时候适合自己的未必适合别人,所以放到工作上,总有些东西需要去适应和妥协的。

Web开发这块比较麻烦的,如果不是在大公司里,不可避免的要牵扯到一部分运维的工作。比如环境和代码部署啦,自动化测试啦,数据库维护等等,不过我觉得最要命的可能还是前端。现在部署的花样比以前多多了,docker是13年左右开始冒出来的,现在用的人比以前要多不少,这个相当于一个系统级别的virtualenv。我还没怎么正式用过,据说效果还可以。代码仓库基本上都一律用git了,除非公司用的svn之类的比较难迁移。CI(Continuous Integration)方面,我没怎么试过,只知道有那么些工具还不错,比如buildbot / Jenkins / travis等等。运维方面,用过的也就fabric,saltstack据说还不错,不过也没试过。

数据库方面我觉得可以分出来讲讲。很多人刚上手web开发比较头疼的可能不是前端二是sql。其实呢,sql没那么恶心,习惯就好了,而且现在也还有很多nosql的选择,也很成熟,比如mongodb和redis。不过关系型数据库还是广泛应用的,出来混,迟早要还。主流的还是mysql,小型的可以用sqlite,国内用oracle和sql server(t-sql)的也不少,不过个人比较喜欢postgresql,其实初阶水平来用的话,差别都不是很大。但具体到开发,sql还会涉及到数据库迁移的过程,如果用django你就轻松多了,其他的话,可能还得借助sqlalchemy+alembic的组合,或者,自己手动alter table吧。

前端之所以说头疼,是对于类似我这周单干的人来讲的。前端的工具和技术更新的快,搞后端的基本是跟不上节奏的。这倒不是重点,搞前端的知识储备和经验积累可能比大多数搞后端的人预估的还要多得多。而且,还需要一定的设计水平。很多搞后端的就是喜欢偷懒,以为用个bootstrap就可以省去前端设计的工作了,于是乎曾经好长一段时间,你都会看到很多网站的按钮都长这样:

图12:bootstrap2中文文档(局部)

所以有时候太偷懒也是不行的。不过还好现在boostrap效果比以前简洁了许多,没那么强烈的违和感。现在前端用到比较多的工具,我所知的有:node.js、gulp / grunt、coffeescript / typescript、angular.js / react.js

/ vue.js、jquery / lo-dash、d3.js / three.js。其他的没列出来的说明名气还不是很大。由于自己的前端水平也不是很好,这里就不细讲每个工具的个人喜好了。获取前端资讯的方法有很多,关注点新闻站点,水下知乎,刷下微博,搜些好文章,都可以的。当然最重要的还是参考与实践结合,这个道理无论前后端都是相通的。

Web开发方面差不多就这些,现在大部分都是后端提供些api,前端分离,手机应用也调api或者干脆用混合应用(html5 + native code)。等项目架构稍复杂点,不可避免的会引入消息队列、集群、冗余、周期性任务计划以及性能优化等等,有时候还不得不做点seo之类的杂活,总之是个深坑。而游戏的水更深,所以我就没太多能讲的了,只好一笔带过了。现在用python做游戏的还真不多,大多都转lua了。而听过且比较出名的可能是eve,不过用到的好像是c++结合stackless python。


本文由职坐标整理并发布,希望对同学们学习Python有所帮助,更多内容请关注职坐标编程语言Python频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程