python入门学习总结

开篇吐槽

        大学的专业是通信工程,学的东西大都是电路或电磁波之类的,此时本该盘踞于电线杆上进行通信抢修的。然而,不巧的是,在大一的时候初次接触到了编程,被代码的魅力所深深吸引。另外,由于本人来自农村,上大学之前连电脑开机都得费半天劲,面对神奇的代码,更是无法自拔。可毕竟自身局限性太强以及对自身发展的迷茫,大学期间,多是用C针对各种开发板写些简单的程序,以致毕业时只掌握了C语言基础和一点点对JAVA和C++的了解。幸运的是,工作了半年,偶然接触到了python,对它的简明优雅,尤其是函数式编程,喜爱不已,遂辞去工作,加入python大军。

走在入门的路上

       在学习python之前,我只有C语言基础,对面向对象的概念只有耳闻,不曾实践。而python的艺术确是一切皆对象,简直是对我这个技术渣男的无情嘲讽啊。像所有人一样,我开始在网上搜索python入门的教程。到目前为止,我的入门之旅可以分为3部分。

入门之一————廖雪峰的python教程

在网上搜索一番,发现廖雪峰老师的pyhton教程很适合小白入门,另外他的官方网站还有git入门教程,能学到不少东西。另外,慕课网也有对应此教程的练习,还是很不错的。非常感谢廖雪峰老师的无私奉献,中国需要多一些这样乐于分享的前辈。在这个教程中,学习了python的基本的string、list、tuple、dict、set等基本的数据类型以及它们的对应的内置方法,了解了切片、迭代、生成器等高大上的特性,同时,也对函数式编程以及面向对象编程有了一定的了解。教程的后面提到了一些常用内建和第三方模块,甚至还讲到了网络编程和web开发,非常全面。教程最后的大作业——写一个WEB APP,一个BLOG,数据库模块、ORM、web框架等全部自己写的,很是厉害,不过很多地方我没太看懂。

入门之二————learning python

在快速学习了廖雪峰老师的教程之后,虽然收获颇丰,但感觉不够系统,对于我这种注重大局观的人来说,必然是要拜读一些经典教程。我选择了1000+页的《python学习手册》,对于初学者来说,这足够系统了。由于有前面的基础,学起来还算快,但是,作者实在过于苦口婆心了,一些细枝末节的东西blablabla讲一大堆,生怕你哪里没听懂,学到后面就有些走马观花了。这本教程据说已经有第五版了,可见其受欢迎的程度,但可能已经不那么适合我了。于是便有了我的入门之三。

入门之三————python基础教程

在强行把python学习手册学了个七八成之后,我又开始迷茫了。虽然学了很多,针对相应的知识点也练习了不少,但还是觉得无法融会贯通,实战起来很多问题。《python基础教程》内容详实,仅仅有条,部分章节鞭辟入里,同时很多地方点到为止,恰到好处,而且后面配备了对应的实战项目,32个赞。这里小小的总结一下练习过的几个实战项目。 

1.即时标记

目标:将纯文本转换网页

原型设计:原型其实很简单,把纯文本文件分块,判断每块是head或者para,添加相应标签,并为每块进行过滤,直接上代码。

#分块函数,util.py

def lines(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 = []


#不过我自己实践的时候去掉了lines函数,直接用file.readlines()生成器不就可以么?
#simple_markup.py
import sys, re
from util import *

print '...'

title = True
for block in blocks(sys.stdin):
    block = re.sub(r'\*(.+?)\*', r'\1', block)
    if title:
        print '

' print block print '

' title = False else: print '

' print block print '

' print ''


扩展 :为什么要扩展?在进行原型设计的过程中,发现这个程序不止是可以处理html标签,其他标签如XML一样可以处理啊。另外,程序没有分模块,所有的逻辑判断和处 理工作,甚至包括过滤器都写在一个文件中完全没有灵活性和可扩展性可言。于是,程序可以分为四个模块来做。

老大—-Parser模块,负责读取文本和管理其他的类,在其子类中可以进行各个rule和filter的插拔。
class Parser:
    """
    A Parser reads a text file, applying rules and controlling a
    handler.
    """
    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')



老二--handler模块,“掌握核心技术”的模块,掌握了生成标签的方法,在其子类HtmlRender中还掌握了过滤器的方法。
class Handler:
    """
    An object that handles method calls from the Parser.

    The Parser will call the start() and end() methods at the
    beginning of each block, with the proper block name as a
    parameter. The sub() method will be used in regular expression
    substitution. When called with a name such as 'emphasis', it will
    return a proper substitution function.
    """
    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

第三个模块rules.py---这个模块就是负责判断block属于哪种block,每种block都有自己的action,没啥特别的。
class Rule:
    """
    Base class for all rules.
    """
    def action(self, block, handler):
        handler.start(self.type)
        handler.feed(block)
        handler.end(self.type)
        return True
第四个filter模块,比较简单。

self.addFilter(r'\*(.+?)\*', 'emphasis')
self.addFilter(r'(http://[\.a-zA-Z/]+)', 'url')
self.addFilter(r'([\.a-zA-Z]+@[\.a-zA-Z]+[a-zA-Z]+)', 'mail')

这个程序到这里基本算结束了,其中parser类中管理其他类的方法可以参考一下,很容易实现了其他模块的插拔。教程中后面还有一些其他的扩展建议,可以使程序更加丰满。




2.画幅好画

目标:从internet中下载文件,并分析数据,在pdf中用图形表示出来。

原型设计:原型中假设数据已经从网上下载好了,并放在data列表中,然后利用reportlab根据数据把图形画出来。

from reportlab.lib import colors
from reportlab.graphics.shapes import *
from reportlab.graphics import renderPDF

data = [
#    Year  Month  Predicted  High  Low
    (2007,  8,    113.2,     114.2, 112.2),
    (2007,  9,    112.8,     115.8, 109.8),
    (2007, 10,    111.0,     116.0, 106.0),
    (2007, 11,    109.8,     116.8, 102.8),
    (2007, 12,    107.3,     115.3,  99.3),
    (2008,  1,    105.2,     114.2,  96.2),
    (2008,  2,    104.1,     114.1,  94.1),
    (2008,  3,     99.9,     110.9,  88.9),
    (2008,  4,     94.8,     106.8,  82.8),
    (2008,  5,     91.2,     104.2,  78.2),
    ]

drawing = Drawing(2000, 1500)

pred = [row[2]-40 for row in data]
high = [row[3]-40 for row in data]
low = [row[4]-40 for row in data]
times = [200*((row[0] + row[1]/12.0) - 2007)-110 for row in data]

drawing.add(PolyLine(zip(times, pred), strokeColor=colors.blue))
drawing.add(PolyLine(zip(times, high), strokeColor=colors.red))
drawing.add(PolyLine(zip(times, low),  strokeColor=colors.green))

drawing.add(String(65, 115, 'Sunspots', fontSize=18, fillColor=colors.red))

renderPDF.drawToFile(drawing, 'report1.pdf', 'Sunspots')
扩展:扩展实现了data从网上下载并分析,其他的和原型差别不大。解析data的关键代码如下(实践中float(n)有报错!)


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()])
这个实战项目其实比较简单的,主要能从中了解reportlab和urllib两个模块的一些用法。



3.万能的XML

目标:通过XML生成一个网站内容,包括目录结构和每个网页的内容。说白了就是解析XML文件。

原型设计:原型比较简单粗暴,直接继承sax的ContentHandler的类,然后复写startElement和endElement方法,其中忽略了directory。

class PageMaker(ContentHandler):
    passthrough = False
    def startElement(self, name, attrs):
        if name == 'page':
            self.passthrough = True
            self.out = open(attrs['name'] + '.html', 'w')
            self.out.write('\n')
            self.out.write('%s\n' % attrs['title'])
            self.out.write('\n')
        elif self.passthrough:
            self.out.write('<' + name)
            for key, val in attrs.items():
                self.out.write(' %s="%s"' % (key, val))
            self.out.write('>')


    def endElement(self, name):
        if name == 'page':
            self.passthrough = False
            self.out.write('\n\n')
            self.out.close()
        elif self.passthrough:
            self.out.write('' % name)
    def characters(self, chars):
        if self.passthrough: self.out.write(chars)
扩展:参考即时标记项目中的思想,搞了一个混入类(Min-in)Dispatcher类来负责自动调度start_xxx和end_xxx,然后WebsiteConstructor继承Dispatcher和ContentHandler。
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)
上面是Mix-in类,class WebsiteConstructor(Dispatcher, ContentHandler)类继承括号中两个,代码和原型差不多。这个项目通过sax实现XML文件的解析,功能虽然比较简单,写写代码多少算是有点收获吧。


教程后面其他项目都挺好的,简单的看了下项目4和项目10,分别是有关socket网络编程和游戏编程的东东,项目4虚拟茶话会在我电脑上运行没成功,小游戏也没有很好的运行起来,具体原因目前还没有搞明白。

最后,同是天涯代码农,共勉!


你可能感兴趣的:(python,python)