作者:燕大侠v
Python 是一种极具可读性和通用性的编程语言。Python 这个名字的灵感来自于英国喜剧团体 Monty Python,它的开发团队有一个重要的基础目标,就是使语言使用起来很有趣。Python 易于设置,并且是用相对直接的风格来编写,对错误会提供即时反馈,对初学者而言是个很好的选择。
Python 是一种多范式语言,也就是说,它支持多种编程风格,包括脚本和面向对象,这使得它适用于通用目的。随着越来越多地在工业中,被诸如联合太空联盟(NASA 的主要飞机支持承包商)和工业光魔(VFX 和卢卡斯影业的动画工作室)等组织使用,Python 为那些寻求额外编程语言的人提供了巨大的潜力 。
当一个重要的被称为 comp.lang.python 的 Python 新闻组在 1994 年形成时,Python 的用户基础不断增长,这为 Python 成为开源开发中最受欢迎的编程语言之一铺平了道路。
Python当下真的很火。Python实战项目,也一直尤为关注,接下来,和大家介绍下十个Python练手的实战项目
python项目练习一:即时标记
这是《python基础教程》后面的实践,照着写写,一方面是来熟悉python的代码方式,另一方面是练习使用python中的基本的以及非基本的语法,做到熟能生巧。
这个项目一开始比较简单,不过重构之后就有些复杂了,但是更灵活了。
按照书上所说,重构之后的程序,分为四个模块:处理程序模块,过滤器模块,规则(其实应该是处理规则),语法分析器。
先来说处理程序模块,这个模块的作用有两个,一个是提供那些固定的html标记的输出(每一个标记都有start和end),另一个是对这个标记输出的开始和结束提供了一个友好的访问接口。来看下程序handlers.py:
这个程序堪称是整个“项目”的基石所在:提供了标签的输出,以及字符串的替换。理解起来也比较简单。
再来看第二个模块“过滤器”,这个模块更为简单,其实就是一个正则表达式的字符串。相关代码如下:
这就是三个过滤器了,分别是:强调牌过滤器(用×号标出的),url牌过滤器,email牌过滤器。熟悉正则表达式的同学理解起来是没有压力的。
再来看第三个模块“规则”,这个模块,抛开那祖父类不说,其他类应该有的两个方法是condition和action,前者是用来判断读进来的字符串是不是符合自家规则,后者是用来执行操作的,所谓的执行操作就是指调用“处理程序模块”,输出前标签、内容、后标签。来看下这个模块的代码,其实这个里面几个类的关系,画到类图里面看会比较清晰。rules.py:
补充utils.py:
最后隆重的来看下“语法分析器模块”,这个模块的作用其实就是协调读入的文本和其他模块的关系。在往重点说就是,提供了两个存放“规则”和“过滤器”的列表,这么做的好处就是使得整个程序的灵活性得到了极大的提高,使得规则和过滤器变成的热插拔的方式,当然这个也归功于前面在写规则和过滤器时每一种类型的规则(过滤器)都单独的写成了一个类,而不是用if..else来区分。看代码:
这个模块里面的处理思路是,遍历客户端(也就是程序执行的入口)给插进去的所有的规则和过滤器,来处理读进来的文本。
有一个细节的地方也要说一下,其实是和前面写的呼应一下,就是在遍历规则的时候通过调用condition这个东西来判断是否符合当前规则。
我觉得这个程序很像是命令行模式,有空可以复习一下该模式,以保持记忆网节点的牢固性。
最后说一下我以为的这个程序的用途:
1、用来做代码高亮分析,如果改写成js版的话,可以做一个在线代码编辑器。
2、可以用来学习,供我写博文用。
还有其他的思路,可以留下您的真知灼见。
补充一个类图,很简陋,但是应该能说明之间的关系。另外我还是建议如果看代码捋不清关系最好自己画图,自己画图才能熟悉整个结构。
python项目练习二:画幅好画
这是《python基础教程》中的第二个项目,关于python操作PDF
涉及到的知识点
1、urllib的使用
2、reportlab库的使用
这个例子着实很简单,不过我发现在python里面可以直接在数组[]里面写for循环,真是越用越方便。
下面是代码:
python项目练习三:万能的XML
这个项目的名称与其叫做万能的XML不如叫做自动构建网站,根据一份XML文件,生成对应目录结构的网站,不过只有html还是太过于简单了,如果要是可以连带生成css那就比较强大了。这个有待后续研发,先来研究下怎么html网站结构。既然是通过XML结构生成网站,那所有的事情都应该由这个XML文件来。先来看下这个XML文件,website.xml:
有了这个文件,下面应该来看怎么通过这个文件生成网站。
首先我们要解析这个xml文件,python解析xml和在java中一样,有两种方式,SAX和DOM,两种处理方式不同点在于速度和范围,前者讲究的是效率,每次只处理文档的一小部分,快速而能有效的利用内存,后者是相反的处理方式,先把所有的文档载入到内存,然后再进行处理,速度比较慢,也比较消耗内存,唯一的好处就是可以操作整个文档。
在python中使用sax方式处理xml要先引入xml.sax中的parse函数,还有xml.sax.handler中的ContentHandler,后面的这个类是要和parse函数来配合使用的。使用方式如下:parse('xxx.xml',xxxHandler),这里面的xxxHandler要继承上面的ContentHandler,不过只要继承就行,不需要有所作为。然后这个parse函数在处理xml文件的时候,会调用xxxHandler中的startElement函数和endElement函数来一个xml中的标签的开始和结束,中间的过程使用一个名为characters的函数来处理标签内部的所有字符串。
有了上面的这些认识,我们已经知道如何处理xml文件了,然后再来看那个罪恶的源头website.xml文件,分析其结构,只有两个节点:page和directory,很明显page表示一个页面,directory表示一个目录。
所以处理这个xml文件的思路就变的清晰了。读取xml文件的每一个节点,然后判断是page还是directory如果是page则创建html页面,然后把节点中的内容写到文件里。如果遇到directory就创建一个文件夹,然后再处理其内部的page节点(如果存在的话)。
下面来看这部分代码,书中的实现比较复杂,比较灵活。先来看,然后在分析。
看起来这个程序上面分析的复杂了一些,不过伟人毛毛说过,任何复杂的程序都是纸老虎。那我们再来分析一下这个程序。
首先看到这个程序是有两个类,其实完全可以当作一个类,因为有了继承。
然后再来看它多了些什么,除了我们分析出来的startElement和endElement以及characters,多出来了startPage,endPage;startDirectory,endDirectory;defaultStart,defaultEnd;ensureDirectory;writeHeader,writeFooter;和dispatch,这些个函数。除了dispatch,前面的函数都很好理解,每一对函数都是单纯的处理对应的html标签以及xml节点。而dispatch比较复杂,复杂之处在于他是用来动态拼合函数并且进行执行的。
dispatch的处理思路是,首先根据传递的参数(就是操作名称以及节点名称)判断是否存在对应的函数如startPage,如果不存在则执行default+操作名称:如defaultStart。
一个函数一个函数搞清楚之后,就知道整个处理流程是什么样了。首先创建一个public_html的文件,存放整个网站,然后读xml的节点,通过startElement和endElement调用dispatch进行处理。然后就是dispatch怎么调用具体的处理函数了。到此为止,这个项目算是分析完了。
主要掌握的内容一个是python中使用SAX处理XML,另一个就是python中的函数的使用,比如getattr,传参数时的星号……
python项目练习四:新闻聚合
书中的第四个练习,新闻聚合。现在很少见的一类应用,至少我从来没有用过,又叫做Usenet。这个程序的主要功能是用来从指定的来源(这里是Usenet新闻组)收集信息,然后讲这些信息保存到指定的目的文件中(这里使用了两种形式:纯文本和html文件)。这个程序的用处有些类似于现在的博客订阅工具或者叫RSS订阅器。
先上代码,然后再来逐一分析:
这个程序,首先从整体上进行分析,重点部分在于NewsAgent,它的作用是存储新闻来源,存储目标地址,然后在分别调用来源服务器(NNTPSource以及SimpleWebSource)以及写新闻的类(PlainDestination和HTMLDestination)。所以从这里也看的出,NNTPSource是专门用来获取新闻服务器上的信息的,SimpleWebSource是获取一个url上的数据的。而PlainDestination和HTMLDestination的作用很明显,前者是用来输出获取到的内容到终端的,后者是写数据到html文件中的。
有了这些分析,然后在来看主程序中的内容,主程序就是来给NewsAgent添加信息源和输出目的地址的。
这确实是个简单的程序,不过这个程序可是用到了分层了。
python项目练习五:虚拟茶话会
几乎在学习、使用任何一种编程语言的时候,关于socket的练习从来都不会少,尤其是会写一些局域网的通信的东西。所以书上的这个项目刚好可以练习一下socket编程。 这个练习的整体思路首先有一个聊天的服务器,这个服务器的功能主要是提供客户端socket的连接、存储每个客户端的连接session,处理每个连接发送的消息、解析客户端发送的数据。就这些,至于客户端方面不需要写代码,用系统的telnet工具即可。 我觉得有了上面的分析,剩下的这个程序就没有什么说的了,当然,除了那两个把socket封装的类之外。 自己使用python中的socket类尝试这个编写了一个简单的通信程序,不过不知为什么,通信中总是出现意外。这段简单的代码如下:
server.py
clinet.py
这个程序出错的原因没有去细揪,因为python中提供了两个封装好的类来完成socket通信过程:asynchat中的async_chat和asyncore中的dispatcher以及asyncore本身。前面的类是用来处理客户端同服务器的每一次会话,后面的类主要是用来提供socket连接服务。并且将每一个socket连接都托管给前者(async_chat)来处理。
来看代码:
整个程序分为我一开始说的三个部分:
🔹 提供客户端的socket连接:ChatServer类。
🔹 存储每个客户端的连接session,处理每个连接发送的消息:ChatSession类,这个类的作用很简单,接受数据,判断是否有终结符,如果有调用found_terminator这个方法。
🔹 解析客户端发送的数据:就是剩下的room相关的类,这些类分别用来处理客户端发送的字符串和命令,都是继承自CommandHandler。
最终截图:
python项目练习六:使用CGI进行远程编辑
记得一开始接触web开发的时候,看视频,视频里面的老师一般都会语重心长的说:想当年我们一开始学习编程那会儿,都是用cgi编程,复杂的很,现在你们学习web编程,直接有现成的框架来用,十分简单。记得当然听完这句话之后就会觉得这个老师好有经验,技术很高。
不过后来慢慢的接触web编程时间长了,觉得cgi编程并不是像传说中的那么难,只不过是比较麻烦,在后台使用html硬编码来完成(也就是在后台使用类似print的语句输出html)。通过浏览器直接访问cgi文件,由web服务器执行cgi脚本,输出内容到浏览器。
关于cgi的更多内容可以参考这里:http://www.jdon.com/idea/cgi.htm
再来看这个python中的cgi,确实很简单。但是有一点我不确定,就是如果我是初学web编程的话,会不会觉得这个简单,这个角度的思考确实不好操作。
下面直接上代码吧,和书上的不太一样,因为书上的代码在我的电脑上不能正常运行。首先是index.html:
edit.cgi,用来接受index页面的名字,然后根据名字查找文件,并且输出。
最后一个文件save.cgi:
代码理解上比较简单,唯一麻烦的地方是web服务器的配置。我这里使用的是tomcat来做web服务器。需要修改tomcat配置,首先是配置cgi,我引用一段从网上搜来的文字:
要为Tomcat配置CGI服务主要有下面几个步骤:
1、把servlets-cgi.renametojar (在%CATALINA_HOME%/server/lib/目录下)改名为servlets-cgi.jar。
2、在Tomcat的%CATALINA_BASE%/conf/web.xml 文件中,把关于<servlet-name> CGI的那段的注释去掉。内容样式如下:
其中参数executable需要自已添加进去,它的值就是我们用来解释CGI脚本的程序。一般情况下这里会配置为Perl。"C:/Perl/bin/"为Perl的安装目录。
3、在Tomcat的%CATALINA_BASE%/conf/web.xml文件中,把关于对CGI进行映射的那段的注释去掉。内容样式如下:
其中url-pattern就是将来我们访问CGI脚本的url地址模式。
完成上面三个步骤后,我们的Tomcat服务器就具有了运行CGI脚本的能力了。
摘自:http://www.blogjava.net/Tauruser/archive/2007/09/06/143097.html
使用hello.cgi测试一下:
然后测试能运行的话,就要把代码放到tomcat的webapp下的某一个app下的WEB-INF中的cgi下。,比如我这里的cgi文件是在tomcat/webapps/test/WEB-INF/cgi/下。另外在cgi目录下要建立一个data文件夹,里面放一个test.txt文件。
最后执行效果如图:
python项目练习七:自定义公告板
这依然是一个cgi的项目,有了前面的一个项目作为基础,这个里面没有什么难点。不过,和书上不同的是,我这里使用的数据库是mysql,所以有兴趣的童鞋,可以参考一下。
首先建立一张mysql的数据表:
然后你要确定你的系统中已经安装了连接mysql的python模块,怎么确定呢。命令行下,进入python,然后输入import MySQLdb,注意大小写,如果没有报错,说明安装了,如果报错,从网上找python连mysql的方法,很多。
准备就绪,开始分析整个程序吧。
一个很简单的电子公告版,主要功能有,展示所有公告,查看单个公告,编辑公告,保存公告。所以根据功能建立四个文件:main.py,view.py,edit.py,save.py,每个文件,负责一个模块。
下面就上代码吧,太简单了。main.py:
view.py
edit.py
save.py
python项目练习八:使用XML-RPC进行远程文件共享
这是个不错的练习,使用python开发P2P程序,或许通过这个我们可以自己搞出来一个P2P下载工具,类似于迅雷。说到迅雷,关于其原理不知道大家是否了解,如果你不了解,我想看完这篇文章,你一定会了解的。啥,你已经了解了?那就过来指点一番。
以前在java中也接触过类似的概念。一个是RMI( Remote Method Invocation)的概念,另外一个就是XML-RPC的概念。
那么什么是XML-RPC呢?它和P2P有什么关系?下面谈谈我的个人理解。
XML-RPC是一个远程过程调用(remote procedure call,RPC)的分布式计算协议,通过XML将调用函数封装,并使用HTTP协议作为传送机制[摘自维基百科]。所以这个XML-RPC可以帮助我们完成远程调用的工作,即调用相邻电脑中的方法,当然前提是在相邻电脑中已经有我们编写的供远程调用的程序在运行(不管是在前台还是后台,就像迅雷一样,总是悄悄运行)。
这里还要提出来一个概念:Node,即节点。每一个电脑被为一个节点,这个只是针对每个电脑只运行一个我们通过XML-RPC编写的程序,如果电脑中同时运行了多个程序,其实每一个程序都是一个节点。有了节点这样的一个概念之后,我想大家可以想象的出来了,不同节点之间相连,形成各种复杂的网状结构。
这时每个节点可以和其他多个节点进行相连,但是我们没必要让一个节点通其他所有的节点都相连,链接太多会很乱,就像人际关系一样。那什么时候连哪些节点呢?这时就要说到P2P了,所谓P2P即指peer to peer,也就是点到点。说是点到点,你可千万别认为只是从一点到一点,因为他可能是从多点到一点,或者一点到多点。而没有固定的从哪个点到哪个点,所有的点都可以相连。
因此在下载东西方面,这样的协议就比传统的只是从某一点下载数据要快很多,资源也会多很多。
其运作流程是这样的,我打一个比方:比如小A在迅雷里下载B片,迅雷上面可以没有这个资源,但是他可以帮你从节点中找,看谁又这个资源,刚好小C电脑里有,并且在迅雷共享目录下,然后迅雷就会把小C电脑中把资源通过自己的节点传回到小A的电脑上,当然更可能的情况是直接让小A和小C相连。
大家在使用迅雷下载东西的时候肯定注意过里面有一项资源:x/xx这样的东西,我觉得,前面的那个x的意思表示当为你提供资源的节点数量,后面的那个xx表示,所有拥有该资源的节点数目,这些节点可能并不在线。
理解了基本的概念之后,再来看python中如何来实现。
可以先做一个小小的尝试:首先进入命令行,输入python,然后输入一下代码:
然后在启动一个命令行,进入pyhon。输入:
from xmlrpclib import ServerProxy s = ServerProxy('http://localhost:4242') s.twice(2) #通过ServerProxy调用远程的方法,
然后你就会看到通过远程方法的计算完成。
是不是很轻松,这个还是比较简陋,不过足以让你理解python的远程调用,再来看看完整的吧。
先上代码,然后再详解。首先是Server.py:
首先来看上面的几个常量设置:SimpleXMLRPCServer.allow_reuse_address表示,其所占用的端口可以重用,即如果你强制关闭node server之后再次重启,不会出现端口被占用的情况。
MAX_HISTORY_LENGTH = 6 这个是设置最大的节点长度,因为不能让让节点无休止的搜索下去。
UNHANDLED = 100 ACCESS_DENIED = 200 这俩就是返回码。
然后再来看个node节点的具体流程。这个段代码的流程这这样的,首先,启动供远程调用的服务器,调用的接口就是Node类。在Node类中有三个方法供远程调用的,一个是hello,一个是fetch还有一个query。hello 这个方法就是添加邻节点信息到当前节点中。而fetch则是用来获取数据的方法,query是节点之间用来交互的。
在fetch方法中,首先判断密码是否正确,然后通过调用自己的query方法查找数据。我们来看query方法,这个方法中,先是调用私有方法_handle本地查找,如果没找到,那么在通过_broadcast接口在所有已知节点中发送广播,这里要注意histroy,每次广播都会传递history这个参数,这个参数的作用有二:一是、防止往重复的节点中发送广播;二是、限制当前所有链接节点的长度。
理解了一个node server的基础功能之后,再来看对server进行管理的控制类代码。
client.py:
来分析一下这段代码,前面的参数就不看了,很好理解,一开始有一个随机生成密码的函数,做什么用的呢?主要是用来防止别人非法调用该控制所控制的node server的。这密码 我们也不用记,因为我们有client的合法使用权。呵呵。
这段代码的总体作用就是为你提供一个可视的命令行的界面,通过继承cmd这个类,来解析你输入的命令,比如程序运行之后,出现命令提示符,你输入fetch,那么它会调用到do_fetch这个方法中来,并把参数传递进来。
do_fetch这个方法的所用就是调用node server中的fetch方法,获取资源。
另外的一个do_exit很好理解,就是接受exit命令退出程序。
在程序初始化的时候,还有一点需要注意,就是它会读取你urlfile参数传递的文件中的数据,这个里面放的是节点的url地址。读取之后程序会把这些地址加到相邻节点中,供以后访问。不过这个程序还有些不完善的地方就是在程序运行时,如果你修改了url配置的文件,他不会读取你新添加的节点url。不过这个修改很简单,把获取url的代码放到do_fetch中就行了。
在运行程序之前还有一些工作要做。首先需要建立两个文件夹,A和C,C文件夹里面创建一个文件,B.txt,在A和C所在文件夹中建立urlsA.txt和urlsC.txt文件。
里面在urlsA.txt中写入:http://localhost:4243,然后开启两个命令行,第一个输入:python client.py urlsA.txt A http://localhost:4242 回车,是不是出来提示符了。输入fetch B.txt回车,看到提示Couldn't find the file B.txt。
然后在第二个命令行中输入python client.py urlsC.txt C http://localhost:4243回车。同样输入fetch B.txt回车,是不是没反应。说明该文件存在。接在在第一个命令行中再次输入fetch B.txt看,是否还是提示没找到文件,如果你对代码根据我上面的建议进行了修改的话,就不会出现错误了,如果没有修改,此时你需要把输入exit退出程序,再次重启,然后在fetch B.txt,然后到A文件夹下查看一下,看是不是把B.txt下载到你的文件夹中了。
PS:上面的程序只能传输文本文件,大文件或者其他格式的文件无法传输,刚才研究了一下,使用xmlrpclib这个库中的Binary函数即可,具体使用访问为:先引入xmlrpclib,import xmlrpclib 在server类的的_handle方法中最后返回的那句代码return open(name).read() 修改为 return xmlrpclib.Binary(open(name,'rb').read()) 再把fetch方法中的f.write(result)修改为f.write(result.data) 另外这句话前面的那个写文件的方式要改为wb。
python项目练习九:文件共享2-GUI版本
有了前面的P2P基础,这一个练习就是给程序加一个可视化的界面,俗称GUI。
python里面的界面库有很多,如wxPython、wgGTK、tkinter,还有QT,按照书中的实例,我也使用wxPython来做界面。话说有了这个界面之后,我发现迅雷的网邻也不过如此(稍有夸张的成份),不过这个项目的练习之上再继续扩展的话,基本效果可以达到网邻的那种,如果有时间的话我可以继续扩展这个项目。下面就开始编写GUI。
这个里面的主要的问题应该都集中在界面上,远程共享的代码已经不需要修改了,只需要把现在的界面接上前面的代码就ok。这个wxPython库的使用,我觉得和以前使用java的awt编写界面没啥区别,没有什么难点,只是需要理解里面的几个概念,像是按钮、文本框、绑定事件,仅此而已。
还是来看代码吧:
这个相比于前面关于xml-rpc的实现就简单的多了。
关于扩展的思路,目前我的想法是这样的,现在的程序监听的端口是通过命令行参数决定的。我觉得可以直接写到窗口上输入或者写死在程序里,毕竟是要使用固定的端口通信的,还有共享的文件夹以及urls里面的节点,都可以是固定的。
另外可以添局域网查询功能,就像是现在迅雷网邻的换一换,就是查找当前局域网内正在使用我们软件的所有用户,然后把他们的资源情况列到我们的列表上。
python项目练习十:DIY街机游戏
终于来到了最后一个项目,看看前面的那些练习,也算是熟悉了python的基本操作,也知道python能干哪些事情,最后一个项目相比于以前的稍微复杂些,但是任何一个程序只要他是可以正常执行的,花点时间总会搞明白的。
这个练习是一个小游戏程序,如果要是给它起个名字的话,应该叫:快躲,香蕉。主要的游戏内容就是,游戏开始会从屏幕上方不断随便的掉一些铁块,在屏幕下方有一个小香蕉是受你控制的,你需要不断的左右移动来躲避铁块。在你躲避完一定数量的铁块之后,就会进入下一关。下一关依然是让你躲铁块,不过铁块下降的速度就快了很多。在游戏中你可以按下任意键暂停,再次按则继续,按下ESC键退出。这就是全部的功能了,下面我们来看游戏的实现。
无论是在实现功能时还是在代码分析的时候,分类归纳总是一个好习惯,这里自然也不例外。
首先对所有代码分类:
1、整体上代码有一个配置模块,来对游戏的速度、屏幕的宽度、香蕉移动速度、字体大小、各个物体的图片等进行配置。
2、然后是有一个元素模块,即游戏中的两个元素落下来的铁块以及被砸的香蕉,其中还要包含他们具有的行为。
3、然后还有游戏中的各种状态模块,状态模块中的类继承关系稍微多一些,处于家谱最上方的就是state类,由它来衍生其他的所有状态,它的直接子类是Level和Pause,其中Pause有衍生出子类Info、levelCleared、GameOver、StartUp。4、最后就是游戏的主模块,用来让其他模块协调工作的。
然后再来看一个整体图:
有了上面整体的认识,下面就要细揪一下了。我自己看代码的方法是这样的,首先整体分析,然后在从程序的入口点开始分析。我估计大多数人也是这么做的。
首先是squish.py文件中的game类:
忽略掉init中的设置代码,在run中,该管理类首先调用pygame初始化并启动游戏界面,然后在一个while True的死循环中不断的进行状态判断,事件处理,然后根据事件更新当前状态,并且绘制界面。
让我们把焦点放在那个死循环中,因为他就是整个程序的流程所在。其中状态和事件的关系就是,当发生某一事件之后,状态就会发生变化,比如点击事件、过关事件、死亡事件。这些事件的来源分别是:用户操作、系统判断、系统判断。要继续深入分析就需要再拿一部分代码出来。
依然是来自squish.py文件中剩余的所有代码:
其中用户判断部分就是Paused类中的update方法和handle方法,而系统判断就是Level类中的update方法。还有一个要注意的地方就是Level类中update方法中的第一行代码:self.sprites.update(),这是让铁块不断下落的关键代码。用户判断部分的代码已经有了,下面需要贴上系统判断时用到的代码.
objects.py中的代码:
在类Banana和Weight中的update和touches方法,用于进行系统判断。
好了,到这主要的东西都分析完了,剩下的只需要稍看一下就能够懂得了。
最后还有一个配置模块的代码config.py: