python 初探

最近在公司做了一些python的技术分享,都是比较基础的东西,用到的一些题材还挺有意思的,和大家分享。

###python 初探 ###Python web api ###用Python做文本摘要

本文是系列的第一篇。

##起源 ###作者

Guido Van Rossum (GvR)

“仁慈的终身独裁者”

###得名

“1989年12月,我在寻找一门“课余”编程项目来打发圣诞节前后的时间。我的办公室会关门,但我有一台家用电脑,而且没有太多其它东西。我决定为当时我正构思的一个新的脚本语言写一个解释器,它是 ABC 语言的后代,对 UNIX / C 程序员会有吸引力。作为一个略微有些无关想法的人,和一个蒙提·派森(Monty Python)的飞行马戏团的狂热爱好者,我选择了 Python 作为项目的标题。”

###每个人都会 1999年,Guido向DARPA阐述Python语言的特性:

  • 简单、直观、强大
  • 开源,以便任何人都可以为它做贡献
  • 代码像纯英语那样容易理解
  • 适用于短期开发的日常任务

这些想法中的一些已经成为现实。Python 已经成为一门流行的 编程语言,尤其是在互联网环境下。

##特性 ###交互式命令行(Interactive console) Python可以单步直译运行。运行Python解释器进入交互式。

命令行的环境,你可以在提示符号»>旁输入代码,按Enter键输出结果:

>>>print("Hello, Python!") 
Hello, Python!

有点像Shell 脚本的执行方式。 ### 不只是脚本 “脚本语言”如Linux shell script、windows batch file等,只能处理简单的任务。

而Python是面向对象编程(OOP)的,支持异常处理和类型检查。Python的支持者较喜欢称它为一种高阶动态编程语言

###强大易用的标准库 核心库不超过10Mb

Html、Xml解析:BeautifulSoup, Expat

字符串处理:字典、数组切片、正则表达式 re

单元测试: PyUnit

代码版本控制: PySVN

网络访问: urllib2

图形模块: Tkinter、PyTCL、WxPython

串行化、多线程等

扩展标准库十分容易 ###胶水语言(glue language) Python经常用作将不同语言编写的程序“粘”在一起的胶水语言。 Google内部的很多项目使用C++编写性能要求极高的部分,然后用Python调用相应的模块。

  • C/C++:

    Boost.Python使得 Python 和 C++ 的类库能互相调用(.pyc)

  • Java:

    Jython 是用Java实现的Python,可同时使用二者的类库

  • .NET:

    IronPython是Python在.NET平台上的版本。

###收放自如(scalability) Python内建的数据结构(variable, list 和 dict)以及对多线程 分布式操作的支持,使得程序可以用相同的代码处理不同规模 的数据,以及并发的用户需求。

###不要括号 Python使用缩进而不是括号来进行代码段标识,减少了视觉上 的混乱,并且使程序变短,从而提高了程序的可读性。

###发行版本

  • CPython: www.python.org

    主流:2.5-2.7

    最新:3.0 不向下兼容

  • ActivePython:

    Windows 下的Python,文档和库较全

  • IronPython: http://ironpython.codeplex.com/

    与.NET集成较好

    可使用CPython的类库

  • NumPy,Python(x,y):

    对科学计算进行了优化的Python版本

###vs. Perl Perl是另一种广泛使用(滥用)的动态高级语言, 经常被用来与Python 比较。

  • 正则表达式的典范
  • 催生了CGI、PHP
  • 黑客最喜爱的语言

作者:

Larry Wall

Perl语言之父,语言学家;两届国际C语言混乱代码大赛(IOCCC) 的冠军;第一届自由软件奖得主。

程序员的三大美德:

  • 懒惰:能让人尽量减少总能量支出的美德。它使你写出节省脑力、可以重用的代码;也督促你为程序写注释和文档,那样你就不用回答各种问题。
  • 不耐烦:你会对试图偷懒的计算机代码大发雷霆。 你写出的代码能预测并适应、而非被动满足用户的需求,或者至少看上去是这样。
  • 傲慢:自傲到人神共愤的程度,让你编写(维护)的程序拥有无可挑剔的品质。

###vs. Ruby

Ruby:比Python更年轻的动态语言

  • 完全面向对象
  • 支持正则表达式
  • 整合了多种语言的优势

作者:松本行弘 @yukihiro_matz

Ruby on Rails (RoR) 网站快速开发工具

###观点 Perl之父Larry Wall:

“做一件事有很多种方法” TIMTOWTDI

Python之父Guido Van Rossum :

“做一件事,应该有一种最直观的方法,而且最好只有一种。”

Ruby之父松本行弘 (“Matz”)

“不要重复自己” DRY原则

###国籍? | 语言 | 作者 | 国籍 | 风格 | | — | — | — | — | | Perl | Larry Wall | 美国 | 随性自由 | | Python | Guido van Rossum | 荷兰 | 优雅统一 | | Ruby | 松本行弘 (“Matz”) | 日本 | 兼容并包 |

##用途

  • 脚本程序
  • 大型程序的原型开发
  • 科学计算
  • 网络应用
  • 计算机图形编程

###知名的Python应用

  • Zope:www.zope.com

    一个应用程序服务器,具有内容管理、团队开发、XML、面向对象、SOAP接口等一系先进特性,开源。

  • Gadfly:http://www.chordate.com/gadfly.html

    一个用Python写的面向对象关系型数据库,具有小巧、快速、可移植性好的 特点,具有大部分SQL语言特性。开源。

  • Wallbase: http://wallbase.net

    Python编写的图片站点。

  • uTorrent : http://www.utorrent.com

    BitTorrent下载软件,主程序仅2Mb,支持ipv6地址解析。开源。

  • Torchlight: torchlight.perfectworld.com

    Python编写的大型3D游戏,原Blizzard公司人员制作发行,开源。

###Google Apps Engine Google App Engine,GAE

“Google App Engine 可让您在 Google 的基础架构上运行您的网络 应用程序。App Engine 应用程序易于构建和维护,并可根据您的访 问量和数据存储需要的增长轻松扩展。使用 Google App Engine, 将不再需要维护服务器:您只需上传您的应用程序,它便可立即为您的用户提供服务。”

Python 为GAE的数据存储区、Google 帐户、网址抓取和电子邮件服务提供了丰富的 Python API。GAE还提供了一个称为 webapp 的简单 Python 网络应用程序框架,从而可以轻松开始构建应用程序。 ###GAE的主要服务

  • 动态网络服务,提供对常用网络技术的完全支持
  • 持久存储空间,支持查询、分类和事务
  • 自动扩展和负载平衡
  • 用户身份验证和使用 Google 帐户发送电子邮件的 API
  • 一套在本地模拟 GAE的开发环境
  • 用于在指定时间和定期触发事件的计划任务

##硬币的另一面 限制Python发展的因素有:

  • 数据库访问层的局限性

相比现有的成熟技术,比如ODBC和JDBC,Python的数据库访问层看起来就过于原始了。虽然这一方面也在发生变化,但是,开发部门需要平滑地接合现有的复杂遗留数据,同时需要快速的SQL数据库访问,所有这一些使其在短时期内难以对Python表现出什么太大的兴趣。

  • 文档差距

相比其对手语言,比如Perl、Java,在某种程度上再算上PHP,Python确实深受文档缺乏之苦,Python没有广泛、易于获得的文档和图书。市面上冠以PHP标题的图书数量几乎是Python的两倍多;而Perl就更多了,有400多种。

Python的在线文档倒还组织得比较好,但是这些文档几乎全是些参考资料。幸而Python相当容易的学习曲线减轻了对图书资料的过多需要。

  • 缺乏GUI和团队协作工具

给Python应用程序创建图形用户界面未必复杂。Python分发版本随带的Tk就是Python开发人员最常用的工具。但是Tk缺乏可访问、易用的GUI工具。 相比GUI工具的缺乏更要命的是Python几乎没有支持团队开发的协议工具。 Java在这些工具领域可谓相当丰富。在企业软件开发市场上,这一缺陷简直可视为致命的要害。没有这类工具要让很多程序员共同开发同一项目几乎是不可能的。Python利用其模块化和命名空间分析等特性减轻了这一方面的需求,这些特性可以让多个程序员开发项目时不可能发生代码冲突的情况。但是,这同样改变不了其协同性能缺乏的严重性。

##如何学习

“Don’t learn. Just use it.”

##工具 SublimeText

IDLE:CPython自带

PythonWin:ActivePython自带

Notepad++:查找/替换 tab和空格 语法高亮

Ulipad: 转到函数定义 Code Snippets

Eclipse:Java

Komodo Editor/IDE

Vim/Emacs: Linux下流行的IDE

##资料 集体智慧编程

简明Python教程

Python Cookbook

IronPython In Action

Or just Google it.

##代码与注释

请大家改变传统的编程态度,“向计算机发出指令”不再是我们的主要工作任务,我们应该把精力集中在“如何向其他的人类解释,我们想让计算机做什么”这件事上。

码农应该像散文家一样,掌握化繁为简的阐述技巧,保持漂亮一致的风格。他(她)应该字典在手,仔细斟酌变量的名字,并解释其含义。他(她)会以一种由浅入深的次序介绍各种概念,交叉地使用形式化和非形式化的手段,互为解释和补充,不遗余力地让程序更加被人类所理解。

—— 高德纳 (Donald Knuth, Literal Programming)

###为什么?

  • 易开发:对自己好一点 (6个月法则)
  • 易维护:对同事好一点 (spm
  • 易使用:对开发者社区好一点 ( nih )

##编程示例1:唇形科

Scarborough Fair是1968年奥斯卡获奖影片《毕业生》的主题曲, 歌词里反复吟唱提到的植物,Parsley欧洲香芹,sage鼠尾草,rosemary迷迭香,thyme百里香,这里的四种植物,就有三种出自香草植物辈出的帝国:唇形科

“唇形科”这个名词对于普通人也许会略感陌生,但接下来开始列举的这些名字,你一定很早以前就曾听过,或者品尝过:薄荷、留兰、黄芩、紫苏、香薷、藿香、薰衣草、牛至、香蜂草、迷迭香、百里香、罗勒、香青兰、鼠尾草、丹参、风轮菜、益母草、夏枯草……是的,这些弥漫着梦幻小清新香味和草药味道的植物,它们都来自于唇形科。

###问题描述 唇形科的部分香料所属的分类树如下:

唇形科 Lamiaceae
	迷迭香属 Rosmarinus
		迷迭香 Rosmarinus officinalis
	紫苏属 Perilla
		紫苏 Perilla frutescens
	薰衣草属 Lavandula
		狭叶薰衣草 Lavandula angustifolia
		西班牙薰衣草 Lavandula stoechas
		宽叶薰衣草 Lavandula latifolia
	薄荷属 Mentha
		薄荷 Mentha haplocalyx
		胡椒薄荷 Mentha piperita
	刺蕊草属 Pogostemon
		广藿香 Pogostemon cablin		

现有一个扁平化的记录文件

a _ 唇形科 Lamiaceae
b a 迷迭香属 Rosmarinus
c b 迷迭香 Rosmarinus officinalis
d a 紫苏属 Perilla
e d 紫苏 Perilla frutescens
f a 薰衣草属 Lavandula
g f 狭叶薰衣草 Lavandula angustifolia
h f 宽叶薰衣草 Lavandula latifolia
i f 西班牙薰衣草 Lavandula stoechas
j a 薄荷属 Mentha
k j 薄荷 Mentha haplocalyx
l j 胡椒薄荷 Mentha piperita
m a 刺蕊草属 Pogostemon
n m 广藿香 Pogostemon cablin

每一行是一个植物学上的分类实体(科、属、种)

每行按空格分隔,第一个域是实体id,第二个是父级实体的id(_表示没有父),第三个是中文名,剩下的是拉丁文名。

请根据扁平化的文件中的实体id和父级id,重建并显示分类树。

###问题分析

其实是从行列储存的数据文件中构造树的问题。

涉及到的python知识点:

  • 文件读写
  • 类的写法
  • 基本数据结构(list、dict、sequence)
  • 树的构建与遍历
  • 迭代器的写法(yield关键字)
  • 字符串的格式化(print)

###文件读写

#输入文件的名称	
input_file_name='spices.txt'	
#写文件,w	
#如果是在文件后附加(例如log)则为a	
file(input_file_name,"w").write(flat)	
#读文件, r
flat=file(input_file_name,'r').read()

###类的写法

class Plant(object):
	#类的说明,在help(Plant)时显示
	"""docstring for Plant"""
	#构造函数
	def __init__(self,plant_id,parent_id,chinese_name,latin_name):
		super(Plant, self).__init__()
		self.plant_id=plant_id #实体id
		self.chinese_name=chinese_name #中文名
		self.latin_name=latin_name #拉丁名
		self.parent=None #父实体
		self.parent_id=parent_id #父id
		self.children=[] #孩子实体列表
		self.depth=0 #实体的深度(级别),根节点为0,每一级+1
	#类方法,所有类方法的第一个参数都是self,表示类的实例本身 self.foo是实例的foo
	#显示实体信息,返回字符串
	def display(self)
		return str(self.plant_id)

###基本数据结构:list、dict、sequence http://sebug.net/paper/python/ch09s02.html

http://sebug.net/paper/python/ch09s04.html

http://sebug.net/paper/python/ch09s05.html ###树的构建与遍历 见代码 ###迭代器的写法(yield)

def walk_tree(current,root=None):
	yield  current
	for child in current.children:
		for x in walk_tree(child,current):
			yield x

简单地讲,yield 的作用就是把一个函数变成一个迭代器,在 for 循环执行时,每次循环都会执行 walk_tree 函数内部的代码,执行到 yield 时,就返回一个迭代值,下次迭代时,代码从 yield 的下一条语句继续执行,而函数的内部变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。 ###字符串的格式化 看这里 ###完整代码

#encoding=utf-8
"""
从平面化的文件中恢复对象树的结构,并打印出来,保存
"""
flat="""
a _ 唇形科 Lamiaceae
b a 迷迭香属 Rosmarinus
c b 迷迭香 Rosmarinus officinalis
d a 紫苏属 Perilla
e d 紫苏 Perilla frutescens
f a 薰衣草属 Lavandula
g f 狭叶薰衣草 Lavandula angustifolia
h f 宽叶薰衣草 Lavandula latifolia
i f 西班牙薰衣草 Lavandula stoechas
j a 薄荷属 Mentha
k j 薄荷 Mentha haplocalyx
l j 胡椒薄荷 Mentha piperita
m a 刺蕊草属 Pogostemon
n m 广藿香 Pogostemon cablin
"""
tree="""
唇形科 Lamiaceae
	迷迭香属 Rosmarinus
		迷迭香 Rosmarinus officinalis
	紫苏属 Perilla
		紫苏 Perilla frutescens
	薰衣草属
		狭叶薰衣草 Lavandula angustifolia
		宽叶薰衣草 Lavandula latifolia
		西班牙薰衣草(Lavandula stoechas)
	薄荷属 Mentha
		薄荷 Mentha haplocalyx
		胡椒薄荷 Mentha piperita
	刺蕊草属 Pogostemon
		广藿香 Pogostemon cablin
"""
#输入文件的名称
input_file_name='spices.txt'
#写文件,w
#如果是在文件后附加(例如log)则为a
file(input_file_name,"w").write(flat)
#读文件, r
flat=file(input_file_name,'r').read()

class Plant(object):
	#类的说明,在help(Plant)时显示
	"""docstring for Plant"""
	#构造函数
	def __init__(self,plant_id,parent_id,chinese_name,latin_name):
		super(Plant, self).__init__()
		self.plant_id=plant_id #实体id
		self.parent_id=parent_id #实体id
		self.chinese_name=chinese_name #实体id
		self.latin_name=latin_name #实体id

	#类方法,所有类方法的第一个参数都是self,表示类的实例本身 self.foo是实例的foo
	#显示实体信息,返回

	def display(self):
		return "{}{} {}".format ("\t"*x.depth, x.chinese_name, x.latin_name)
def get_tree_from_flat_file(flat):
	dic={} #字典,key为plant_id, value为Plant对象
	root=None #记录树的根实体
	#逐行读取并生成实体,然后装入dic中
	for line in flat.split("\n"):
		#line为string,split函数将sring分割成list,也就是words
		words=line.split(" ")
		#空行不做处理
		if len(words)<=1: 
			continue
		#获取各种属性
		plant_id, parent_id, chinese_name = words[0], words[1], words[2]
		latin_name=" ".join(words[3:]) #从list的第3个元素到最后,用空格连接成string
		#Plant类的实例化
		plant=Plant(plant_id,parent_id,chinese_name,latin_name)
		#dict的赋值方法
		dic[plant_id]=plant
	#补充实体的parent_id、parent和children属性
	for x in dic.values(): #dict的遍历,可根据需要遍历.keys() .values() 和 .items()
		if x.parent_id=="_":
			root=x
		elif x.parent_id in dic:
			x.parent=dic[x.parent_id]		
		if x.parent: #也可写作x.parent!=None True False
			x.parent.children.append(x)
	return root
root=get_tree_from_flat_file(flat)
#介绍递归函数和迭代器的写法
#walk_tree是一个递归函数,返回的是一个迭代器
#可用在for x in walk_tree中
def walk_tree(current,root=None,depth=0):
	current.depth=depth
	yield  current
	for child in current.children:
		for x in walk_tree(child,current,depth+1):
			yield x
output=[]
for x in walk_tree(root):
	s= x.display()
	print s
	output.append(s)
file("tree.txt","w").write("\n".join(output))
	output=[]
	for x in walk_tree(root):
		s= x.display()
		print s
		output.append(s)
	file("tree.txt","w").write("\n".join(output))

###思考题 输入为上面的示例1中输出的分类树文件,请生成扁平化的数据文件,也就是示例1的输入文件。plant_id可随意取,不重复即可。parent_id要等于父节点的id。

  • 提示1: 如何生成唯一id google “python 唯一id”
  • 提示2: 获取一行中前缀空格数的方法:

设行字符串存在变量line中,

len(line)为line的长度

line1=line.lstrip()为去掉所有的前缀空格后的line

len(line)-len(line1)为前缀空格数。

也可用正则表达式s/^\s+//

分享