资源描述
python项目练习一:即时标记 60837°C
这是《python基本教程》背面实践,照着写写,一方面是来熟悉python代码方式,另一方面是练习使用python中基本以及非基本语法,做到熟能生巧。
这个项目一开始比较简朴,但是重构之后就有些复杂了,但是更灵活了。
按照书上所说,重构之后程序,分为四个模块:解决程序模块,过滤器模块,规则(其实应当是解决规则),语法分析器。
先来说解决程序模块,这个模块作用有两个,一种是提供那些固定html标记输出(每一种标记均有start和end),另一种是对这个标记输出开始和结束提供了一种和谐访问接口。来看下程序handlers.py:
class Handler:
'''
'''
def callback(self,prefix,name,*args):
method = getattr(self,prefix+name,None)
if callable(method):return method(*args)
def start(self,name):
self.callback('start_',name)
def end(self,name):
self.callback('end_',name)
def sub(self,name):
def substitution(match):
result = self.callback('sub_',name,match)
if result is None:match.group(0)
return result
return substitution
class HTMLRenderer(Handler):
'''
'''
def start_document(self):
print '<html><head><title>...</title></head><body>'
def end_document(self):
print '</body></html>'
def start_paragraph(self):
print '<p>'
def end_paragraph(self):
print '</p>'
def start_heading(self):
print '<h2>'
def end_heading(self):
print '</h2>'
def start_list(self):
print '<ul>'
def end_list(self):
print '</ul>'
def start_listitem(self):
print '<li>'
def end_listitem(self):
print '</li>'
def start_title(self):
print '<h1>'
def end_title(self):
print '</h1>'
def sub_emphasis(self,match):
return '<em>%s</em>' % match.group(1)
def sub_url(self, match):
return '<a href="%s">%s</a>' % (match.group(1),match.group(1))
def sub_mail(self, match):
return '<a href="mailto:%s">%s</a>' % (match.group(1),match.group(1))
def feed(self,data):
print data
这个程序堪称是整个“项目”基石所在:提供了标签输出,以及字符串替代。理解起来也比较简朴。
再来看第二个模块“过滤器”,这个模块更为简朴,其实就是一种正则表达式字符串。有关代码如下:
self.addFilter(r'\*(.+?)\*','emphasis')
self.addFilter(r'(http://[\.a-z0-9A-Z/]+)','url')
self.addFilter(r'([\.a-zA-Z]+@[\.a-zA-Z]+[a-zA-Z]+)','mail')
这就是三个过滤器了,分别是:强调牌过滤器(用×号标出),url牌过滤器,email牌过滤器。熟悉正则表达式同窗理解起来是没有压力。
再来看第三个模块“规则”,这个模块,抛开那祖父类不说,其她类应当有两个办法是condition和action,前者是用来判断读进来字符串是不是符合自家规则,后者是用来执行操作,所谓执行操作就是指调用“解决程序模块”,输出前标签、内容、后标签。 来看下这个模块代码,其实这个里面几种类关系,画到类图里面看会比较清晰。 rules.py:
class Rule:
def action(self,block,handler):
handler.start(self.type)
handler.feed(block)
handler.end(self.type)
return True
class HeadingRule(Rule):
type = 'heading'
def condition(self,block):
return not '\n' in block and len(block) <= 70 and not block[-1] == ':'
class TitleRule(HeadingRule):
type = 'title'
first = True
def condition(self,block):
if not self.first:return False
self.first = False
return HeadingRule.condition(self,block)
class ListItemRule(Rule):
type = 'listitem'
def condition(self,block):
return block[0] == '-'
def action(self,block,handler):
handler.start(self.type)
handler.feed(block[1:].strip())
handler.end(self.type)
return True
class ListRule(ListItemRule):
type = 'list'
inside = False
def condition(self,block):
return True
def action(self,block,handler):
if not self.inside and ListItemRule.condition(self,block):
handler.start(self.type)
self.inside = True
elif self.inside and not ListItemRule.condition(self,block):
handler.end(self.type)
self.inside = False
return False
class ParagraphRule(Rule):
type = 'paragraph'
def condition(self,block):
return True
补充utils.py:
def line(file):
for line in file:yield line
yield '\n'
def blocks(file):
block = []
for line in lines(file):
if line.strip():
block.append(line)
elif block:
yield ''.join(block).strip()
block = []
最后隆重来看下“语法分析器模块”,这个模块作用其实就是协调读入文本和其她模块关系。在往重点说就是,提供了两个存储“规则”和“过滤器”列表,这样做好处就是使得整个程序灵活性得到了极大提高,使得规则和过滤器变成热插拔方式,固然这个也归功于前面在写规则和过滤器时每一种类型规则(过滤器)都单独写成了一种类,而不是用if..else来区别。 看代码:
import sys,re
from handlers import *
from util import *
from rules import *
class Parser:
def __init__(self,handler):
self.handler = handler
self.rules = []
self.filters = []
def addRule(self,rule):
self.rules.append(rule)
def addFilter(self,pattern,name):
def filter(block,handler):
return re.sub(pattern,handler.sub(name),block)
self.filters.append(filter)
def parse(self,file):
self.handler.start('document')
for block in blocks(file):
for filter in self.filters:
block = filter(block,self.handler)
for rule in self.rules:
if rule.condition(block):
last = rule.action(block,self.handler)
if last:break
self.handler.end('document')
class BasicTextParser(Parser):
def __init__(self,handler):
Parser.__init__(self,handler)
self.addRule(ListRule())
self.addRule(ListItemRule())
self.addRule(TitleRule())
self.addRule(HeadingRule())
self.addRule(ParagraphRule())
self.addFilter(r'\*(.+?)\*','emphasis')
self.addFilter(r'(http://[\.a-z0-9A-Z/]+)','url')
self.addFilter(r'([\.a-zA-Z]+@[\.a-zA-Z]+[a-zA-Z]+)','mail')
handler = HTMLRenderer()
parser = BasicTextParser(handler)
parser.parse(sys.stdin)
这个模块里面解决思路是,遍历客户端(也就是程序执行入口)给插进去所有规则和过滤器,来解决读进来文本。
有一种细节地方也要说一下,其实是和前面写呼应一下,就是在遍历规则时候通过调用condition这个东西来判断与否符合当前规则。
我觉得这个程序很像是命令行模式,有空可以复习一下该模式,以保持记忆网节点牢固性。
最后说一下我觉得这个程序用途, 1、用来做代码高亮分析,如果改写成js版话,可以做一种在线代码编辑器。 2、可以用来学习,供我写博文用。
尚有其她思路,可以留下您真知灼见。
补充一种类图,很简陋,但是应当能阐明之间关系。此外我还是建议如果看代码捋不清关系最佳自己画图,自己画图才干熟悉整个构造。
python项目练习二:画幅好画 22982°C
作者:the5fire | 标签: pythonpdf python实战 | 发布:-12-18 3:35 p.m.
这是《python基本教程》中第二个项目,关于python操作PDF
涉及到知识点
· 1、urllib使用
· 2、reportlab库使用
这个例子着实很简朴,但是我发当前python里面可以直接在数组[]里面写for循环,真是越用越以便。
下面是代码:
from urllib import urlopen
from reportlab.graphics.shapes import *
from reportlab.graphics.charts.lineplots import LinePlot
from reportlab.graphics.charts.textlabels import Label
from reportlab.graphics import renderPDF
URL = ''
COMMENT_CHARS = '#:'
drawing = Drawing(400,200)
data = []
for line in urlopen(URL).readlines():
if not line.isspace() and not line[0] in COMMENT_CHARS:
data.append([float(n) for n in line.split()])
pred = [row[2] for row in data]
high = [row[3] for row in data]
low = [row[4] for row in data]
times = [row[0] + row[1]/12.0 for row in data]
lp = LinePlot()
lp.x = 50
lp.y = 50
lp.height = 125
lp.width = 300
lp.data = [zip(times,pred),zip(times,high),zip(times,low)]
lp.lines[0].strokeColor = colors.blue
lp.lines[1].strokeColor = colors.red
lp.lines[2].strokeColor = colors.green
drawing.add(lp)
drawing.add(String(250,150,'Sunspots',fontSize=14,fillColor=colors.red))
renderPDF.drawToFile(drawing,'report3.pdf','Sunspots')
python项目练习三:万能XML 13869°C
作者:the5fire | 标签: python实战 | 发布:-12-20 3:18 p.m.
这个项目名称与其叫做万能XML不如叫做自动构建网站,依照一份XML文献,生成相应目录构造网站,但是只有html还是太过于简朴了,如果要是可以连带生成css那就比较强大了。这个有待后续研发,先来研究下怎么html网站构造。 既然是通过XML构造生成网站,那所有事情都应当由这个XML文献来。先来看下这个XML文献,website.xml:
<website>
<page name="index" title="Home page">
<h1>Welcome to my Home page</h1>
<p>Hi,there. My name is Mr.gumby,and this is my home page,here are some of my int:</p>
<ul>
<li><a href="interests/shouting.html">Shouting</a></li>
<li><a href="interests/sleeping.html">Sleeping</a></li>
<li><a href="interests/eating.html">Eating</a></li>
</ul>
</page>
<directory name="interests">
<page name="shouting" title="Shouting">
<h1>shouting page</h1>
<p>....</p>
</page>
<page name="sleeping" title="Sleeping">
<h1>sleeping page</h1>
<p>...</p>
</page>
<page name="eating" title="Eating">
<h1>Eating page</h1>
<p>....</p>
</page>
</directory>
</website>
有了这个文献,下面应当来看怎么通过这个文献生成网站。
一方面咱们要解析这个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节点(如果存在话)。
下面来看这某些代码,书中实现比较复杂,比较灵活。先来看,然后在分析。
from xml.sax.handler import ContentHandler
from xml.sax import parse
import os
class Dispatcher:
def dispatch(self,prefix,name,attrs=None):
mname = prefix + name.capitalize()
dname = 'default' + prefix.capitalize()
method = getattr(self,mname,None)
if callable(method):args = ()
else:
method = getattr(self,dname,None)
args = name,
if prefix == 'start':args += attrs,
if callable(method):method(*args)
def startElement(self,name,attrs):
self.dispatch('start',name,attrs)
def endElement(self,name):
self.dispatch('end',name)
class WebsiteConstructor(Dispatcher,ContentHandler):
passthrough = False
def __init__(self,directory):
self.directory = [directory]
self.ensureDirectory()
def ensureDirectory(self):
path = os.path.join(*self.directory)
print path
print '----'
if not os.path.isdir(path):os.makedirs(path)
def characters(self,chars):
if self.passthrough:self.out.write(chars)
def defaultStart(self,name,attrs):
if self.passthrough:
self.out.write('<' + name)
for key,val in attrs.items():
self.out.write(' %s="%s"' %(key,val))
self.out.write('>')
def defaultEnd(self,name):
if self.passthrough:
self.out.write('</%s>' % name)
def startDirectory(self,attrs):
self.directory.append(attrs['name'])
self.ensureDirectory()
def endDirectory(self):
print 'endDirectory'
self.directory.pop()
def startPage(self,attrs):
print 'startPage'
filename = os.path.join(*self.directory + [attrs['name']+'.html'])
self.out = open(filename,'w')
self.writeHeader(attrs['title'])
self.passthrough = True
def endPage(self):
print 'endPage'
self.passthrough = False
self.writeFooter()
self.out.close()
def writeHeader(self,title):
self.out.write('<html>\n <head>\n <title>')
self.out.write(title)
self.out.write('</title>\n </head>\n <body>\n')
def writeFooter(self):
self.out.write('\n </body>\n</html>\n')
parse('website.xml',WebsiteConstructor('public_html'))
看起来这个程序上面分析复杂了某些,但是伟人毛毛说过,任何复杂程序都是纸老虎。那咱们再来分析一下这个程序。
一方面看到这个程序是有两个类,其实完全可以当作一种类,由于有了继承。
然后再来看它多了些什么,除了咱们分析出来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项目练习四:新闻聚合 13729°C
作者:the5fire | 标签: python实战 | 发布:-12-26 2:07 p.m.
书中第四个练习,新闻聚合。当前很少见一类应用,至少我从来没有用过,又叫做Usenet。这个程序重要功能是用来从指定来源(这里是Usenet新闻组)收集信息,然后讲这些信息保存到指定目文献中(这里使用了两种形式:纯文本和html文献)。这个程序用处有些类似于当前博客订阅工具或者叫RSS订阅器。
先上代码,然后再来逐个分析:
from nntplib import NNTP
from time import strftime,time,localtime
from email import message_from_string
from urllib import urlopen
import textwrap
import re
day = 24*60*60
def wrap(string,max=70):
'''
'''
return '\n'.join(textwrap.wrap(string)) + '\n'
class NewsAgent:
'''
'''
def __init__(self):
self.sources = []
self.destinations = []
def addSource(self,source):
self.sources.append(source)
def addDestination(self,dest):
self.destinations.append(dest)
def distribute(self):
items = []
for source in self.sources:
items.extend(source.getItems())
for dest in self.destinations:
dest.receiveItems(items)
class NewsItem:
def __init__(self,title,body):
self.title = title
self.body = body
class NNTPSource:
def __init__(self,servername,group,window):
self.servername = servername
self.group = group
self.window = window
def getItems(self):
start = localtime(time() - self.window*day)
date = strftime('%y%m%d',start)
hour = strftime('%H%M%S',start)
server = NNTP(self.servername)
ids = server.newnews(self.group,date,hour)[1]
for id in ids:
lines = server.article(id)[3]
message = message_from_string('\n'.join(lines))
title = message['subject']
body = message.get_payload()
if message.is_multipart():
body = body[0]
yield NewsItem(title,body)
server.quit()
class SimpleWebSource:
def __init__(self,url,titlePattern,bodyPattern):
self.url = url
self.titlePattern = pile(titlePattern)
self.bodyPattern = pile(bodyPattern)
def getItems(self):
text = urlopen(self.url).read()
titles = self.titlePattern.findall(te
展开阅读全文