这本书适合使用过python一段时间以后看,作为进阶。
整本书只涉及高级议题,所以并不是循序渐进的,思路上每章都是独立的,因此可以单独学习。
主要涉及到Python的一些高级特性和技巧,内容包括:
低于类级别下面的最佳实践(ch2)
这要涉及列表推导式、迭代器和生成器以及协程、装饰器,with和contextlib用法
从iterator到list comprehension,到generator以及coroutine,可以说是循序渐进把这几个概念和用法讲的很清楚。
装饰器(Decorator)
这本书的装饰器讲的很好,第一次看到有人把装饰器讲的这么好。
装饰器接受一个函数并且返回一个增强版本的函数。
大多数人接触到的第一个装饰器可能就是@classmethod和@staticmethod.
如何写装饰器?
主要提到了两种写法
第一种适合一般的装饰器
def mydecorator(function):
def _mydecorator(*args, **kwargs):
print 'before function [%s()] run.' % function.__name__
rst = function(*args, **kwargs)
print 'after function [%s()] run.' % function.__name__
return rst
return _mydecorator
第二种适合带参数的装饰器
在第一种写法外面再包装一层
def mydecorator(arg1,arg2):
def _mydecorator(function):
def _mydecorator(*args, **kwargs):
print 'before function [%s()] run.' % function.__name__
rst = function(*args, **kwargs)
print 'after function [%s()] run.' % function.__name__
return rst
return _mydecorator
return _mydecorator
装饰器讲到好几种模式:
参数检查
缓存
代理
上下文提供者
with语法
with语法改善了try...finally模式,值得一看,起码看到别人那么写不会感到奇怪。我们知道内建的很多类型,比如file什么的已经可以支持wth语法,但是如果要自定义一个呢?让我们学习contextlib
contextlib
这东西是专门为with语句量身定制的,可以很方便的让函数也支持with语句。不过with语句是Python3的新特性(Python2.6以后的版本可以通过__future__模块启用with语句)。with的好处就是在语句块内的代码执行完毕后可以保证最后执行一段代码,比如关闭资源等。这也是个高级技巧,用好了会方便很多,代码也很优雅。
类级别下面的最佳实践(ch3)
多重继承、mro、描述符和属性以及元编程等。
新式类和旧式类
注意不要混用两种类。这是历史遗留问题,下面一个帖子比较清楚说明了区别:
http://stackoverflow.com/questions/54867/old-style-and-new-style-classes-in-python
多重继承
关于多重继承,这里更多的是要注意MRO带来的陷阱。书中有详细的介绍与讨论,是Python程序员必须掌握的内容。
描述符和属性以及元编程这些内容都很好,也是python进阶必须掌握的内容。不懂得这些最佳实践,看框架源代码就是一句空话。
ch4讲解命名的最佳实践,给出设计良好的api的提示
大多数内容和java命名法类似,除了私有特性部分。python没有真正的私有特性,靠的是约定,基本上以_开头的就算私有特性,而以__开头的会被改名,在前面加上一个类名。
ch5 在这些基础内容之后还有关于包的编写,使用模板的方法,如何发行和分发代码
ch6 是ch5的扩展实例
ch12和ch13
直接跳到ch12和ch13,这两章讲解了优化策略和实践。
优化策略:
过早的性能优化是罪恶之源
优化的步骤:先完成所有功能,建立了足够的单元测试,发现bug解决bug然后建立回归测试,回归测试包括功能和性能的检查,性能的检查是比较有意思的部分,因为不同的机器不同的环境造成同一个程序运行的表现会参差不齐,如何建立性能的检查是一个值得思考的问题。作者建立了一个机器中立的性能基准-kstone。
这本书碰到的兼容性问题
因为这本书写的比较早(2008),看的时候碰到了问题老是会怀疑是不是过时了,看看有没有替代品。
总的来说还好,只是在guppy和pbp.script的时候比较棘手,但是后来也解决了。
一开始使用guppy出现app crash错误(windows7-x64,py2.7)
下面这个帖子讨论过这个话题
http://stackoverflow.com/questions/26060045/guppy-heapy-on-windows-with-python-2-7-6
我以为guppy已经outdated,所以找来一个替代品memory_profiler
后来看到ch13的时候,发现pbp.script也不能使用,因为这个是作者专门为这本书例子写的包,所以也找不到合适的替代品。
但是也不能弃之不用,因为使用pbp.scripts很方便,可以打印出某个函数运行使用的时间(kstones和s)和使用的内存。
guppy和pbp.scripts在linux下面可以使用,在windows7会出现app crash
安装步骤:
pip install guppy
安装pbp.scripts,下载源代码安装
https://bitbucket.org/tarek/atomisator
因为并发是python的难点,所以下面特别记录说明。
并发实例p277-278
使用了threading.Thread的多线程
t=Thread(target=functionName)
t.setDaemon(True)
t.start()
subprocess(linux下面使用subprocess32)用来运行一个命令行程序。
subprocess(shellcommand)
Queue.Queue用来做任务队列
put,get,task_done,join;依赖task_done和join来等待所有多线程的结束
并发实例p281-p282
使用processing.Process处理多进程
p.start,p.join
并发实例p283
使用processing.Pool作为进程池
pool=processing.Pool()
result=pool.apply_async(worker)#建立进程,并且立即返回
print result.get(timeout=1)#后面可以获取进程的结果,可以设置timeout
使用processing.Queue作为队列
q.get_nowait()
如果队列为空,raise Queue.Empty,所以在程序的某个地方需要处理这个exception,其实就是表示队列里面的任务全部完成了
提高性能的最佳实践
1. Keep Code Simple Not Data
减少代码,能减少生成的代码,因此能减少执行时间
python是解释执行的,代码量少对性能确实有好处,针对被调用次数高的代码,可以使用一些技巧减少代码行获得性能的提升。有些函数会被调用成千上万次,每次执行的时间从0.005优化到0.0025也是很了不起的。
2. 使用List Comprehensions构造List,快12倍
3. 使用enumerate来获取index,快20%
4. 使用Generator处理循环/序列,节省内存
List Comprehensions节省CPU, Generator节省内存
讲到Generator,我发现数据量比较大的时候,也会节省cpu时间
改写了p284实例的代码,p284实例是测试使用cache和不使用的性能。
我添加了一个使用cache并且使用Generator的函数。
测试的时候,小数据量看不出generator和listComprehension的区别,随着逐渐提高数据量,结果不出所料。
当数据量提高到100000的时候,Generator版本的cache耗时不到list comprehension版本的一半。
耗时kstones比例情况如下:
cached_genrator:cached_listComprehension:nocached
10:29:41
5. 使用multitask并发
使用multitask扩展模块和Generator可以实现简单的并发操作。
特别在涉及到io操作包括数据库操作的时候,python的并发可以提高性能。cpu密集的优化则是python的难点,因为全局锁的存在。
6. 使用itertools迭代
7. 使用defaultdict替代dict
P272实例运行结果,耗时kstones比例是 11:24
8. 使用deque替代list或者Queue.LifoQueue
我改写了p271实例代码,添加了Queue.LifoQueue的实现版本,发现deque是最快的,list其次,LifoQueue最慢了
他们的耗时kstones比例是84:342:790。
9.使用gevent/eventlet协程库优化io密集任务
这是比较底层的库,很多框架已经包装了这些协程库。
比如下面会讲到的Celery,在并发方面有很多种选择,Prefork, Eventlet, gevent, threads/single threaded.
10.基于事件处理的异步方式
著名的twisted是一个基于事件处理的web框架。twisted实现了reactor模式。
另一个著名的web框架tornado,低版本是依赖于twisted的,最近的版本已经重新写了一个库。
tornado其实没啥优势,可能被过度神话了。
建议使用框架sanic,经过比较测试,相对于tornado有10倍的提升。
还有一个框架japronto, 没有sanic成熟,据说每秒百万查询,测试过以后发现和sanic属于相同量级。
想到japronto来说,sanic的优点生态系统已经比较成熟,各种扩展都已经具备。
10.cpu密集型的优化建议看看processing
这是多进程库,书里面没有深入下去,后面有待继续研究。
11.使用成熟的分布式任务队列Celery
Celery - 分布式任务队列
Celery 是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具。
它是一个专注于实时处理的任务队列,同时也支持任务调度
消息中间件
Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis, MongoDB (experimental), Amazon SQS (experimental),CouchDB (experimental), SQLAlchemy (experimental),Django ORM (experimental), IronMQ
任务执行单元
Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。
任务结果存储
Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, Redis,memcached, MongoDB,SQLAlchemy, Django ORM,Apache Cassandra, IronCache
另外, Celery还支持不同的并发和序列化的手段
并发
Prefork, Eventlet, gevent, threads/single threaded
序列化
pickle, json, yaml, msgpack. zlib, bzip2 compression, Cryptographic message signing 等等
ch14 、简单讨论了几个在Python下常用的设计模式
GOF的设计模式深入人心。我以前学习设计模式使用了java语言实现。因为不同语言的场景不一样,有的已经内建,有的需要自己积累。所以值得一看。
想加入更多乐读创业社的活动,请访问网站→http://ledu.club
或关注微信公众号选取: