基本信息
- 原书名:Python in Practice: Create Better Programs Using Concurrency, Libraries, and Patterns
- 原出版社: Addison-Wesley Professional

【插图】

编辑推荐
全球资深PVthon专家Doug Hellmann作序鼎力推荐,Amazon全五星评价,Python领域最有影响力的著作之一
从设计模式、并发技术和程序库角度,围绕Python编程的核心问题,系统而详细地讲解各种实用Python编程技术和技巧,并以3个完整的案例展示“设计—实现—优化”的全过程,带你领略Python语言之美,提升Python编程水平
内容简介
计算机书籍
《Python编程实战:运用设计模式、并发和程序库创建高质量程序》由Python开发者社区知名技术专家Mark Summerfield亲笔撰写,全球资深Python专家Doug Hellmann作序鼎力推荐,是Python领域最有影响力的著作之一。书中通过大量实用的范例代码和三个完整的案例研究,全面而系统地讲解了如何运用设计模式来规划代码结构,如何通过并发与Cython等技术提升代码执行速度,以及如何利用各种Python程序库来快速开发具体的应用程序和游戏。
《Python编程实战:运用设计模式、并发和程序库创建高质量程序》共8章:第1~3章分别介绍了Python的几种设计模式(创建型设计模式、结构型设计模式和行为型设计模式);第4章和第5章详细讲解了Python的高级并发技术以及Cython的用法;第6章具体介绍了Python的高级网络编程;第7章阐释了如何用Tkinter开发图形用户界面;第8章讲解了如何用OpenGL绘制3D图形。
作译者
爱飞翔,资深软件开发工程师,擅长Web开发、移动开发和游戏开发,有lo佘年开发经验,曾主导和参与了多个手机游戏和手机软件项目的开发,经验十分丰富。业余爱好文学和历史,有一定的文学造诣。翻译并出版了《Android游戏开发实践指南》、《测试驱动的iOS开发》、《HTML5 Canvas核心技术:图形、动画与游戏开发》、《NoSQL樯粹》和《JavaScfipt应用开发实践指南》等书。
目录
译者序
序
前言
第1章 Python的创建型设计模式 1
1.1 抽象工厂模式 1
1.1.1 经典的抽象工厂模式 2
1.1.2 Python风格的抽象工厂模式 4
1.2 建造者模式 6
1.3 工厂方法模式 12
1.4 原型模式 18
1.5 单例模式 19
第2章 Python的结构型设计模式 21
2.1 适配器模式 21
2.2 桥接模式 26
2.3 组合模式 31
2.3.1 常规的“组合体/非组合体”式层级 32
2.3.2 只用一个类来表示组合体与非组合体 35
2.4 修饰器模式 37
2.4.1 函数修饰器与方法修饰器 38
译者序
第一是如何运用设计模式来规划代码结构,使之既易于修改,又易于维护;第二是如何通过并发及Cython等技术提升代码执行速度;第三是如何利用各种Python程序库来快速开发具体的应用程序和游戏。
针对这三大问题,本书都做了非常精彩的解答。作者把设计模式分为“创建型”、“结构型”与“行为型”三类,并分别比较了每种设计模式的传统用法与它在Python中的用法究竟有何异同。读者通过这部分讲解,可以学会如何在Python中简化或扩充传统的设计模式,也能明白为何有些模式在Python中无须使用。
许多开发者都想通过并发来提升程序性能,但由于要处理“资源竞争”、“加锁”等复杂的问题,所以并发式应用程序很容易出错,而本书作者则会告诉我们怎样利用queue及future等高级数据结构来避免这些错误,此外,他还辨析了多进程技术与多线程技术的适用场合。其后,作者又讲解了如何用Python来调用C或C++,并通过实例证明了Python并不是一门效率低下的语言——只要合理运用并发及Cython技术,照样可以写出速度很快的程序。
在具体的应用领域中,作者着重讲解了如何利用Python程序库来简化网络及图形编程,并把图形编程又细分为用户界面编程和三维图形编程。由于Python的程序库非常丰富,所以读者只要把学到的解题思路灵活地运用到自己的工作领域,并辅以适当的程序库,就能快速开发出符合需求的程序。
本书不仅提供了大量实用的范例代码,而且还有三个完整的案例研究。这三个案例再现了“设计—实现—优化”的全过程,并使我们领略到Python语言之美。
尽管本书作者认为读者应该有一定的Python基础,但Python其实是一门亲和力很高的语言,即便你对Python知之甚少,但只要用其他语言编过程序,也依然可以从for x in range(1,10): print(x)、(2, 3, 4) * 2、[9,8,7,6][1:3]等浅显易懂的写法中轻松得知循环、元组及列表等功能的用法。如果你想快速掌握Python语言,那不妨在开发文档的帮助下,试着直接读这本书。
总之,无论你是老手还是新手,本书都是学习Python的良好伴侣。相信大家在读完本书之后,应该能用其中的技术和思路把Python程序写得更加优秀。
翻译过程中,我得到了机械工业出版社华章公司诸位编辑与工作人员的帮助,在此深表感谢。
本书附有“中英文词汇对照表”,其中列出了相关词汇的各种译法,供大家参考。有兴趣的朋友可至华章公司网站www.hzbook.com下载。由于时间仓促,译者水平有限,错误与疏漏之处在所难免,敬请读者批评指正。大家可发邮件至eastarstormlee@gmail.com与我联系,也可访问网页http://agilemobidev.com/eastarlee/book/python-in-practice留言。
爱飞翔
前言
本书有四大主题:用设计模式编写出优雅的代码、用并发和“编译过的Python”(也就是Cython)提升处理速度、高级网络编程,以及图形。
《Design Patterns: Elements of Reusable Object-Oriented Software》(详情参见附录B)一书虽然早在1995年就出版了,然而时至今日,依然深刻地影响着面向对象编程这一领域。本书从Python语言的角度重新审视前书所提到的每种设计模式,给出实用的Python范例,并解释为何Python程序员用不到某些模式。这些模式在第1章、第2章及第3章中讲解。
Python的GIL(Global Interpreter Lock,全局解释器锁)会阻止Python代码同时在多个处理器核心上运行。于是有人就误以为Python不支持多线程,或无法发挥多核硬件的优势。对于“计算密集型”(CPU-bound)程序来说,可以用multiprocessing模块实现并发,该模块不受GIL限制,可以完全利用每个核心。这样一来,处理速度就很容易提高了(大致同CPU的核心数成正比)。对于“I/O密集型”程序来说,我们既可以用multiprocessing模块来做,也可以用threading模块或concurrent.futures模块来做。实际上,使用threading模块来编写I/O密集型程序时,并不用担心由GIL所带来的开销,因为网络延迟的影响更大。
遗憾的是,在编写并发程序时,如果采用低级与中级方式,那么非常容易出错,任何编程语言都有这种问题。要想少出错,就不要使用“显式锁”(explicit lock),而是改用Python的queue及multiprocessing模块,这些模块提供了封装程度较高的“队列”(queue),此外,也可以改用concurrent.futures模块来做。第4章会告诉大家如何用封装程度较高的并发技术来大幅提高程序性能。
某些程序员之所以使用C、C++或其他“编译型语言”(compiled language)来编程,是因为他们还有另外一个错误的想法,那就是Python程序运行得很慢。一般来说,Python确实要比编译型语言慢,但在目前的硬件上面,用Python语言所编写的绝大部分应用程序的运行速度都足够快。即便有时Python程序真的不够快,我们也可以一边享受用Python编程所带来的好处,一边想办法提升其运行速度。
如果要给某些长期运行的程序提速,那么可以使用PyPy这款Python解释器(网址是pypy.org)。这是一种“即时编译器”(just-in-time compiler),可以极大提升程序执行速度。另外一种优化执行效率的方式是调用运行速度与编译后的C程序相仿的代码,对于“计算密集型”程序来说,用这种代码改写后,其执行速度很容易变成原来的100倍。要想使Python程序运行得和C程序一样快,最简单的办法就是调用那种底层以C语言来实现的Python模块。比方说,标准库里的array模块或第三方numpy模块都能飞快地处理数组,并且很省内存(多维数组可以用numpy来处理)。除此之外,还可以使用标准库的cProfile模块来探查程序的瓶颈,并用Cython来写对速度要求很高的那部分代码。这种写法实际上就是一套“增强版Python语言”(enhanced Python):写好的程序可以编译成纯C,从而使运行速度提升到极致。
当然,有时候我们所需的功能已经由现成的C或C++库实现好了,或者由采用“C语言调用约定”(C calling convention)的其他语言程序库实现好了。在大多数情况下,都能找到第三方Python模块来访问我们所需的那些程序库,这些模块可以在Python Package Index(简称PyPI,网址是pypi.python.org)里找到。不过在个别情况下可能找不到这种模块,此时可以用标准库的ctypes模块或第三方的Cython包来调用C程序库里的功能。采用已经实现好的C程序库来编写代码能够极大减少开发时间,而且C代码的运行速度也相当快。第5章讲解ctypes与Cython。
Python标准库提供了许多用于网络编程的模块,比如底层的socket模块、中层的socketserver模块,以及高层的xmlrpclib模块。把用其他语言所写的代码移植到Python时,可能会用到底层与中层网络模块,然而直接用Python编程时,通常不需要理会那些底层的细节,只需要用高层模块来实现所需的网络功能即可。第6章讲解如何使用标准库中的xmlrpclib模块以及功能强大且易用的第三方RPyC模块。
每个程序差不多都要提供某种用户界面,使用户可通过它来向程序下达指令。可以用argparse模块来编写Python程序,使其支持命令行界面;也可以用其他模块来编写,使其支持完整的终端用户界面(例如,在Unix系统上,可用第三方urwid包实现这种界面,此包的网址为excess.org/urwid)。此外,有许多Web框架能够实现出Web界面,比如轻量级的bottle框架(网址是bottlepy.org)、重量级的Django框架(网址是www.djangoproject.com)与Pyramid框架(网址是www.pylonsproject.org)。当然,除了上面说的这几种界面外,还可以创建具有“图形用户界面”(Graphical User Interface,GUI)的Python应用程序。
经常听到“Web程序将取代GUI程序”这种说法,不过现在还没发展到那一步。实际上,用户可能更喜欢GUI程序,而不是Web程序。比方说,在21世纪初智能手机刚开始流行时,用户总是爱用专门制作好的“app”而不是浏览器中的网页来处理日常事务。有许多第三方Python包都可用来编写GUI程序。本书第7章要介绍的Tkinter包位于Python标准库里,该章会告诉大家如何用它创建样式新潮的GUI程序。
目前大多数计算机(包括笔记本电脑及部分智能手机)都配有功能强大的图形渲染硬件,这种硬件通常是独立的GPU(Graphics Processing Unit,图形处理单元),能够绘制出绚丽的二维及三维图形。而大多数GPU都支持OpenGL API,所以Python程序员可以通过第三方包来调用这套API。第8章将会讲解怎样用OpenGL绘制三维图形。
本书旨在演示如何编写更好的Python程序,如何写出效率高、易维护且易于使用的Python代码。阅读之前,需要有Python编程基础,因为此书是写给已经学会Python语言用法的读者看的,大家应该已经读过Python的开发文档或是类似教程了,比如《Programming in Python 3, Second Edition》(详情参见附录B)等书。而这本书将提供一些有助于提升Python编程水平的思路、灵感与实用技巧。
本书全部范例代码都在Linux系统的Python 3.3版本下测试通过(笔者也尽量在Python 3.2及Python 3.1版本下测试过了),绝大部分代码还能在OS X与Windows操作系统中运行。可从本书网站www.qtrac.eu/pipbook.html下载范例代码,这些代码也应该能在后续的Python 3.x版本下运行。
致谢
与写其他技术书籍时一样,笔者写这本书时也得到了大家的诸多建议、帮助及鼓励,在此深表谢意。
Nick Coghlan从2005年起成为Python的核心开发者,他提供了大量建设性的批评意见,并展示了许多想法及代码片段,以此表明书中所讲的某些内容还有更好的实现方式。Nick对笔者改进本书内容帮助极大,尤其是前面几章。
Doug Hellmann是资深Python开发者与技术作者,他给笔者写了许多条非常有用的评论,从成书之前的出版提案到成书之后正文里的每一章都是如此。Doug还给笔者提供了许多思路,并为本书撰写了序。
两位友人Jasmin Blanchette与Trenton Schulz都是有经验的Python程序员,他们各自的研究方向迥然不同,但都位于本书所讲的范围之内。Jasmin与Trenton反馈了许多意见,使笔者能够据此改写正文及范例代码中的许多不够明晰之处。
感谢策划编辑Debra Williams Cauley,在成书过程中,他再次向我提供了支持和帮助。
序言
这15年来,我用Python编程语言开发过各种应用程序,在此过程中,Python开发者社区也逐渐成熟与壮大起来。从前,我们必须向管理人员“推销”Python语言,以便其允许开发者在相关工作项目中使用它。而现在则不同了,懂Python语言的程序员在就业市场中备受青睐,而参加各种Python技术会议的人也络绎不绝,有些是区域性的会议,有些是大型的国内或国际会议。如OpenStack这样的项目既能拓宽Python语言的应用领域,又能吸引开发好手投入Python阵营。社区壮大之后,优秀的Python书籍也比原来多了。
Mark Summerfield是Python开发者社区里的知名技术作家,写有Qt及Python等方面的著作。我是乔治亚州亚特兰大市Python开发者聚会的组织人,经常有开发者问我:学Python语言看什么书好?在我列出的推荐书目中,Mark所著的《Programming in Python 3》名列榜首。Mark的这本新作当然也在书单里,只是目标读者有些不同。
大部分编程书籍都位于两个极端:要么是向某门语言初学者(或刚开始学习编程之人)做一些简单介绍,要么就是专门讲解Web开发、图形用户界面应用程序开发、生物信息学等特定的高端话题。在写作《The Python Standard Library by Example》一书时,我想填补两极之间的空白,也就是想写给那些有一定基础的程序员或计算机通才,这部分读者既想提升知识水平,又不愿局限在某个狭小的应用范围内。编辑请我审阅本书的出版提案时,我发现这本书的目标读者恰与我自己的书一致,于是颇感欣慰。
我始终在寻找这样一本书:它里面的内容不针对某个特定的框架或程序库,读者在阅读过程中一旦产生某个想法,就立刻能将其运用于目前正在做的项目中。过去几年里我一直在开发一套系统,用于计量OpenStack云服务。在这个过程中,开发团队发现:计费系统所收集到的数据也可以有其他用途,比如,报表系统和监视系统也能用到。于是,在设计系统时,我们通过一条管线来传递样本数据,以便将其转换并发布为各种格式,这样一来,就能把数据传给多个数据消费端了。当这条管线的代码快要写好时,我开始参与这本书的技术评审工作了。读完草稿第3章前面几节之后,我清楚地意识到,当初把管线实现得太过复杂了。Mark在书中演示的“协程链”技术非常优雅,而且易于理解,所以,我立刻在项目的“路线图”里加了个任务,计划在下个发行周期里用该技术来修改管线设计。
本书有很多实用的建议及范例代码,大家可以像上面所说的那样,用它们来改进自己的项目。此外,书中还介绍了许多有趣的编程技法,即便大家像我一样读过很多代码,也依然有可能发现一些原来不知道的技巧。无论是很有经验的老程序员,还是正在寻求自我提升的新手,本书都会引领大家从不同的角度来观察问题,使你能用学到的技术创建出更为高效的解决方案。
Doug Hellmann
DreamHost公司资深开发者
2013年5月
媒体评论
——Doug Hellmann,DreamHost公司资深开发者
书摘
Python的创建型设计模式
关乎对象创建方式的设计模式就是“创建型设计模式”(creational design pattern)。一般我们都是通过调用构造器(也就是用参数来调用类对象)来创建对象的,但有时候需要以更为灵活的方式来创建对象,而这正是创建型设计模式的用途。
对于Python程序员来说,其中某些设计模式彼此之间非常相似,而另外一些则根本用不到(稍后就要讲到)。有些设计模式主要是为C++这种语言设计的,目的是绕开这些编程语言中的某些限制。而Python语言没有这些限制,所以就用不到它们了。
1.1抽象工厂模式
“抽象工厂模式”(Abstract Factory Pattern)用来创建复杂的对象,这种对象由许多小对象组成,而这些小对象都属于某个特定的“系列”(family)。
比方说,在GUI系统里可以设计“抽象控件工厂”(abstract widget factory),并设计三个“具体子类工厂”(concrete subclass factory):MacWidgetFactory、XfceWidgetFactory、WindowsWidgetFactor,它们都提供创建同一种对象的方法(例如都提供创建按钮的make_button()方法,都提供创建数值调整框的make_spinbox()方法),而具体创建出来的对象的风格则与操作系统平台相符。我们可以编写create_dialog()函数,令其以“工厂实例”(factory instance)为参数来创建OS X、Xfce及Windows风格的对话框,对话框的具体风格取决于传进来的工厂参数。
1.1.1经典的抽象工厂模式
为了演示抽象工厂模式,我们来写一段程序,用以生成简单的“示意图”(diagram)。这段程序会用到两个“工厂”(factory):一个用来生成纯文本格式的示意图,另一个用来生成SVG(Scalable Vector Graphics,可缩放的矢量图)格式的示意图。图1.1列出了这两种格式。此程序有两种写法,diagram1.py文件按照传统方式来运用抽象工厂模式,而diagram2.py则借助了Python的某些特性,这样写出来的程序比原来更短小、更清晰。这两个版本所生成的示意图都一样。
图1.1纯文本格式与SVG格式的示意图
有一些代码是这两个版本都要用的,首先我们来看main()函数。
首先创建两个文件(上述范例代码中没有列出相关语句)。接下来,用默认的纯文本工厂()创建示意图,并将其保存。然后,用SVG工厂()来创建同样的示意图,也将其保存。
create_diagram函数只有一个参数,就是绘图所用的工厂,该函数用这个工厂创建出所需的示意图。此函数并不知道工厂的具体类型,也无须关心这一点,它只需要知道工厂对象具备创建示意图所需的接口即可。以make开头的那些方法我们放在后面讲。
说完工厂的用法之后,我们来看工厂本身的写法。下面这个工厂类用来绘制纯文本示意图(该工厂也是其他工厂的基类):
虽说“抽象工厂模式”的名字里有“抽象”这个词,但实际上我们可以用一个类来身兼二职:这个类既像基类那样定义抽象接口,又像具体类那样提供实现代码。DiagramFactory类就是按照这个思路写出来的。
创建SVG示意图所用的工厂叫做SvgDiagramFactory,该类的前几行代码是:
这两个make_diagram方法之间的唯一区别在于:DiagramFactory.make_diagram()方法返回的是Diagram对象,而SvgDiagramFactory.make_diagram()方法返回的是SvgDiagram对象。SvgDiagramFactory里的另外两个方法也是如此(这两个方法没有列在上述范例代码中)。
稍后我们会看到,虽然对应类的接口都一样(比如Diagram与SvgDiagram类的方法名都相同),但是绘制纯文本示意图所用的Diagram、Rectangle、Text等类的实现方式却与SVG示意图所用的SvgDiagram、SvgRectangle、SvgText等类截然不同。这意味着不同系列的类之间不可混搭(比如Rectangle和SvgText就不能放在一张示意图里),相关的工厂类会自行保证这一点。
纯文本Diagram对象用“二维列表”(list of lists)来保存示意图里的数据,这些数据就是空格、+、