当前位置: 首页 > 新闻 > 信息荟萃
编号:4485
Python项目开发实战.pdf
http://www.100md.com 2020年4月11日
第1页
第6页
第11页
第25页
第47页
第180页

    参见附件(7922KB,706页)。

     Python项目开发实战是关于python开发的书籍,主要讲述了python开发入门,开发Web应用,Python项目的结构与包的创建,面向团队开发的工具等专业知识,对你一定有帮助,

    内容介绍

    本书来自真正的开发现场,是BePROUD公司众多极客在真实项目中的经验总结和智慧结晶。作者从Python的环境搭建开始讲起,介绍了Web应用的开发方法、项目管理及审查、测试与高效部署、服务器调试等内容,尽可能网罗了Python项目开发流程中的方方面面,有助于开发者建立有序生产环境,提高开发效率,让编程事半功倍。此外,在本书中Python仅仅是一个载体,很多知识点在非Python下也适用。

    书籍作者简介

    日本BeProud股份有限公司,BeProud是一家专注于Python开发的公司,因云集了众多杰出的Python工程师而闻名于日本国内。多年来在Python开发上硕果累累,以其精湛的技术水平,得到了客户及业界人士的认可和好评。

    引言

    迄今为止,BePROUD公司已使用Python开发了诸多项目。我们之所以撰写本书,是为了与各位读者分享我们在实践中总结出的一些技巧。

    同时,鉴于最近公司员工数量增长,我们把在BePROUD工作所需的知识也写入了本书,以便新的公司成员能尽快熟悉工作。

    因此本书从搭建工作环境开始讲起,逐步涉及Web应用的开发、项目管理及审查、测试代码的编写与高效部署、服务器调试等方面,网罗了Python项目开发工作中的一系列流程。书名中的“实战”一词就包含了“工作”的意思。

    书中所写的技巧主要源于我们的Python2开发经验。也正因为如此,本书将以Python2为例进行讲解。如今新的开发项目已经在使用Python3,这些技巧转移到Python3上理应同样适用。

    进入正题之前,先来聊聊我们的日常思路。

    主目录

    第 1 部分 Python 开发入门阅读

    第 1 章 Python 入门阅读

    第 2 章 开发 Web 应用阅读

    第 3 章 Python 项目的结构与包的创建阅读

    第 2 部分 团队开发的周期

    第 4 章 面向团队开发的工具

    第 5 章 项目管理与审查

    第 6 章 用 Mercurial 管理源码

    第 7 章 完备文档的基础

    第 8 章 模块分割设计与单元测试

    第 9 章 Python 封装及其运用

    第 10 章 用 Jenkins 持续集成

    第 3 部分 服务公开

    第 11 章 环境搭建与部署的自动化

    第 12 章 应用的性能改善

    第 4 部分 加速开发的技巧

    第 13 章 让测试为我们服务

    第 14 章 轻松使用 Django

    第 15 章 方便好用的 Python 模块

    Python项目开发实战截图

    书名:Python项目开发实战(第2版)

    作者:[日] 日本BePROUD股份有限公司

    译者:支鹏浩

    ISBN:978-7-115-43856-0

    本书由北京图灵文化发展有限公司发行数字版。版权所有,侵权必究。

    您购买的图灵电子书仅供您个人使用,未经授权,不得以任何方式复制和传播

    本书内容。

    我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

    如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维

    权措施,并可能追究法律责任。

    图灵社区会员 lot(tensionjayzl@qq.com) 专享 尊重版权

    版权声明

    引言

    极客 书虫常伴身边的公司

    希望能不做不想做的事

    希望学会好的方法并付诸实践

    希望工作时有个好心情

    谢辞

    前言

    本书涉及的内容

    阅读本书前的准备

    第 1 部分 Python 开发入门

    第 1 章 Python 入门

    1.1 安装 Python

    1.1.1 安装 deb 包

    1.1.2 安装第三方包

    1.1.3 virtualenv 的使用方法

    1.1.4 多版本 Python 的使用

    1.2 安装 Mercurial

    1.2.1 Mercurial 概述1.2.2 安装 Mercurial

    1.2.3 创建版本库

    1.2.4 文件操作

    1.3 编辑器与辅助开发工具

    1.3.1 编辑器

    1.3.2 开发辅助工具

    1.4 小结

    第 2 章 开发 Web 应用

    2.1 了解Web 应用

    2.1.1 Web 应用是什么

    2.1.2 Web 应用与桌面应用的区别

    2.1.3 Web 应用的机制

    2.2 前置准备

    2.2.1 关于 Flask

    2.2.2 安装Flask

    2.3 Web 应用的开发流程

    2.4 明确要开发什么应用

    2.4.1 留言板应用的需求

    2.4.2 明确必备的功能2.4.3 明确必备的页面

    2.5 页面设计

    2.5.1 确定成品页面的形式

    2.5.2 编写 HTML 和 CSS

    2.6 实现功能

    2.6.1 保存留言数据

    2.6.2 获取已保存的留言列表

    2.6.3 用模板引擎显示页面

    2.6.4 准备评论接收方的 URL

    2.6.5 调整模板的输出

    2.7 查看运行情况

    第 3 章 Python 项目的结构与包的创建

    3.1 Python 项目

    3.2 环境与工具

    3.2.1 用 virtualenv 搭建独立环境

    3.2.2 用 pip 安装程序包

    3.2.3 小结

    3.3 文件结构与发布程序包

    3.3.1 编写 setup.py3.3.2 留言板的项目结构

    3.3.3 setup.py 与 MANIFEST.in——设置程序包信息与捆绑的文件

    3.3.4 setup.py——创建执行命令

    3.3.5 python setup.py sdist——创建源码发布程序包

    3.3.6 提交至版本库

    3.3.7 README.rst——开发环境设置流程

    3.3.8 变更依赖包

    3.3.9 通过 requirements.txt 固定开发版本

    3.3.10 python setup.py bdist_wheel——制作用于 wheel 发布的程序

    包

    3.3.11 上传到 PyPI 并公开

    3.3.12 小结

    3.4 小结

    第 2 部分 团队开发的周期

    第 4 章 面向团队开发的工具

    4.1 问题跟踪系统

    4.1.1 Redmine

    4.1.2 安装Redmine

    4.1.3 Redmine 的设置

    4.1.4 插件4.2 版本控制系统

    4.2.1 Mercurial 与 Redmine 的联动

    4.2.2 用于生成版本库的插件

    4.3 聊天系统

    4.3.1 Slack

    4.3.2 Slack 的特点

    4.3.3 Slack 做不到的事

    4.3.4 Slack 的注册

    4.4 对团队开发有帮助的工具

    4.4.1 Dropbox

    4.4.2 Google Drive

    4.5 小结

    第 5 章 项目管理与审查

    5.1 项目管理与问题的区分使用

    5.1.1 项目管理的前置准备工作

    5.1.2 创建问题

    5.1.3 整理问题

    5.1.4 分割问题

    5.2 问题模板5.2.1 安装插件

    5.2.2 问题模板的使用方法

    5.2.3 Global Issue Templates

    5.2.4 问题模板示例

    5.3 问题驱动开发

    5.3.1 别急着敲代码,先建问题

    5.3.2 创建与问题编号同名的分支

    5.3.3 让发布与分支相对应

    5.3.4 分支的合并

    5.4 审查

    5.4.1 为什么需要审查

    5.4.2 审查委托:代码审查篇

    把希望审查员确认的事项整理出来

    5.4.3 审查委托:作业审查篇

    5.4.4 实施审查:代码审查篇

    5.4.5 实施审查:作业审查篇

    5.5 小结

    第 6 章 用 Mercurial 管理源码

    6.1 Mercurial 版本库的管理与设置6.1.1 服务器上的 Uinx 用户群设置

    6.1.2 创建版本库

    6.1.3 hgrc 的设置

    6.1.4 使用设置好的版本库

    6.1.5 使用 hgweb 建立简易中央版本库

    6.2 灵活使用“钩子”

    6.2.1 钩子功能的设置方法

    6.2.2 尝试钩子脚本

    6.2.3 钩子事件

    6.2.4 钩子功能的执行时机

    6.2.5 编写钩子脚本

    6.3 分支的操作

    6.4 关于合并

    6.4.1 未发生冲突的合并

    6.4.2 合并时发生冲突以及用文本编辑器解决冲突的方法

    6.4.3 合并的类型与冲突

    6.4.4 用 GUI 的合并工具进行合并

    6.5 GUI 客户端

    6.5.1 GUI 客户端的介绍6.5.2 GUI 客户端的优点

    6.5.3 GUI 客户端的缺点

    6.6 考虑实际运用的 BePROUD Mercurial Workflow

    6.6.1 概述

    6.6.2 背景

    6.6.3 版本库的结构

    6.6.4 提交源码

    6.6.5 提交设计

    6.6.6 分支的合并

    6.6.7 集成分支

    6.7 小结

    第 7 章 完备文档的基础

    7.1 要记得给项目写文档

    7.1.1 写文档时不想做的事

    7.1.2 什么样的状态让人想写文档

    7.2 Sphinx 的基础与安装

    7.2.1 Sphinx 的安装

    7.2.2 reStructuredText 入门

    7.2.3 用 Sphinx 写结构化文档的流程7.2.4 Sphinx 扩展

    7.3 导入 Sphinx 可解决的问题与新出现的问题

    7.3.1 由于是纯文本,所以能在平时用的编辑器上写文档

    7.3.2 信息与视图相分离,所以能集中精神编辑内容,不用顾虑装饰等外观

    问题

    7.3.3 可根据一个源码输出 PDF 等多种格式

    7.3.4 通过结构化,文档可分成几个文件来写

    7.3.5 能用 Mercurial 等轻松实现版本管理

    7.3.6 API 参考手册与程序的管理一体化

    7.3.7 通过 Web 浏览器共享

    7.3.8 导入 Sphinx 后仍存在的问题

    7.4 文档集的创建与使用

    7.4.1 什么是文档集

    7.4.2 项目所需文档的一览表

    7.4.3 面向项目组长、经理

    7.4.4 面向设计者

    7.4.5 面向开发者

    7.4.6 面向客户

    7.5 小结

    第 8 章 模块分割设计与单元测试8.1 模块分割设计

    8.1.1 功能设计

    8.1.2 构成 Web 应用的组件

    8.1.3 组件设计

    8.1.4 模块与程序包

    8.2 测试

    8.2.1 测试的种类

    8.2.2 编写单元测试

    8.2.3 从单元测试中剔除环境依赖

    8.2.4 用 WebTest 做功能测试

    8.3 通过测试改良设计

    便于测试的设计

    8.4 推进测试自动化

    8.4.1 用 tox 自动生成执行测试的环境

    8.4.2 可重复使用的测试环境

    8.5 小结

    第 9 章 Python 封装及其运用

    9.1 使用程序包

    9.1.1 程序包的版本指定9.1.2 从非 PyPI 服务器安装程序包

    9.1.3 程序包的发布格式

    9.1.4 生成wheelhouse 的方法

    9.1.5 从 wheelhouse 安装

    9.2 巧用程序包

    9.2.1 私密发布

    9.2.2 巧用 requirements.txt

    9.2.3 requirements.txt 层级化

    9.2.4 为部署和 CI+tox 准备的 requiremests

    9.2.5 通过 requirements.txt 指定库的版本

    9.3 小结

    第 10 章 用 Jenkins 持续集成

    10.1 什么是持续集成

    10.1.1 持续集成的简介

    10.1.2 Jenkins 简介

    10.2 Jenkins 的安装

    10.2.1 安装 Jenkins 主体程序

    10.2.2 本章将用到的 Jenkins 插件

    10.3 执行测试代码10.3.1 让 Jenkins 运行简单的测试代码

    10.3.2 添加 Job

    10.3.3 Job 的成功与失败

    10.4 测试结果输出到报告

    10.4.1 安装 pytest

    10.4.2 调用 pytest 命令

    10.4.3 根据 pytest 更改 Jenkins 的设置

    10.5 显示覆盖率报告

    10.5.1 安装 pytest-cov

    10.5.2 从 pytest 获取覆盖率

    10.5.3 读取覆盖率报告

    10.6 执行 Django 的测试

    10.6.1 安装 Python 模块

    10.6.2 Django 的调整

    10.6.3 示例代码

    10.6.4 Jenkins 的调整

    10.6.5 “构建后操作”选项卡的设置

    10.7 通过 Jenkins 构建文档

    10.7.1 安装 Sphinx10.7.2 在 Jenkins 添加 Job

    10.7.3 Sphinx 构建发出警告时令 Job 失败

    10.7.4 查看成果

    10.7.5 通过 Task Scanner Plugin 管理 TODO

    10.7.6 Task Scanner Plugin 的设置示例

    10.8 Jenkins 进阶技巧

    10.8.1 好用的功能

    10.8.2 进一步改善

    10.9 小结

    第 3 部分 服务公开

    第 11 章 环境搭建与部署的自动化

    11.1 确定所需环境的内容

    11.1.1 网络结构

    11.1.2 服务器搭建内容的结构化

    11.1.3 用户的设置

    11.1.4 选定程序包

    11.1.5 中间件的设置

    11.1.6 部署

    11.2 用 Ansible 实现自动化作业11.2.1 Ansible 简介

    11.2.2 文件结构

    11.2.3 执行 Ansible

    11.2.4 与最初确定的结构相对应

    11.2.5 将各步骤 Ansible 化

    11.2.6 整理Ansible 的执行环境

    11.3 小结

    第 12 章 应用的性能改善

    12.1 Web 应用的性能

    12.1.1 Web 应用面对大量集中请求时会产生哪些问题

    12.1.2 针对高负荷的对策

    12.2 评估留言板应用的性能

    12.2.1 什么是应用的性能

    12.2.2 安装 ApacheBench

    12.2.3 用 ApachBench 评估性能

    12.3 gunicorn 简介

    12.3.1 安装 gunicorn

    12.3.2 在 gunicorn 上运行应用

    12.4 nginx 简介12.4.1 安装 nginx

    12.4.2 检测nginx 的性能

    12.5 在 nginx 和 gunicorn 上运行应用

    12.5.1 gunicorn 的设置

    12.5.2 nginx 的设置

    12.5.3 评估 nginx+gunicorn 的性能

    12.5.4 性能比较

    12.6 小结

    第 4 部分 加速开发的技巧

    第 13 章 让测试为我们服务

    13.1 认识现状:测试的客观环境

    13.2 将测试导入开发各个阶段

    13.2.1 文档的测试(审查)

    13.2.2 测试设计的编写方法(输入与输出)

    13.2.3 测试的实施与测试阶段的轮换(做什么,做多少)

    13.3 小结:测试并不可怕

    第 14 章 轻松使用 Django

    14.1 Django 简介

    14.1.1 Django 的安装14.1.2 Django 的架构

    14.1.3 Django 的文档

    14.2 数据库的迁移

    14.2.1 什么是数据库的迁移

    14.2.2 Django 的迁移功能

    14.3 fixture replacement

    14.3.1 什么是测试配置器

    14.3.2 几种不便使用默认配置器的情况

    14.3.3 如何使用 factory_boy

    14.3.4 消除“不便使用默认配置器的情况”

    14.4 Django Debug Toolbar

    Django Debug Toolbar 的简介

    14.5 小结

    第 15 章 方便好用的 Python 模块

    15.1 轻松计算日期

    15.1.1 日期计算的复杂性

    15.1.2 导入 dateutil

    15.2 简化模型的映射

    15.2.1 模型映射的必要性15.2.2 映射规则的结构化与重复利用

    15.2.3 导入bpmappers

    15.2.4 与 Django 联动

    15.2.5 编写JSON API

    15.3 图像处理

    15.3.1 安装Pillow

    15.3.2 图像格式转换

    15.3.3 改变图像尺寸

    15.3.4 剪裁图像

    15.3.5 对图像进行滤镜处理

    15.4 数据加密

    15.4.1 安装 PyCrypto

    15.4.2 通用加密系统的加密及解密

    15.4.3 公钥加密系统(RSA)的加密与解密

    15.5 使用 Twitter 的 API

    15.5.1 导入 tweepy

    15.5.2 添加应用与获取用户密钥

    15.5.3 获取访问令牌

    15.5.4 调用 Twitter API15.5.5 编写用 Twitter 认证的系统

    15.6 使用REST API

    15.6.1 REST 简介

    15.6.2 导入 Requests

    15.6.3 导入测试服务器

    15.6.4 发送GET 请求

    15.6.5 发送 POST 请求

    15.6.6 发送 JSON 格式的 POST 请求

    15.6.7 使用 GETPOST 之外的 HTTP 方法

    15.7 小结

    附录

    附录 A VirtualBox 的设置

    A.1 安装VirtualBox

    A.2 新建虚拟机

    A.3 备份虚拟机

    附录 B OS(Ubuntu)的设置

    B.1 安装Ubuntu

    B.2 SSH 的设置

    B.3 中文的设置B.4 添加用户

    版权声明

    Python Professional Programming Dai 2 Han

    Copyright ? BeProud Inc. 2015

    All rights reserved.

    First original Japanese edition published by SHUWA SYSTEM CO.,LTD., Japan.

    Chinese (in simplified character only) translation rights

    arranged with SHUWA SYSTEM CO., LTD., Japan.

    through CREEK RIVER Co., Ltd. and CREEK RIVER SHANGHAI Co.,Ltd.

    本书中文简体字版由SHUWA SYSTEM CO., LTD., Japan. 授权人民邮电出版

    社独家出版。未经出版者书面许可,不得以任何方式复制或抄袭本书内容。

    版权所有,侵权必究。

    引言

    迄今为止,BePROUD 公司已使用 Python 开发了诸多项目。我们之所以撰写本

    书,是为了与各位读者分享我们在实践中总结出的一些技巧。

    同时,鉴于最近公司员工数量增长,我们把在 BePROUD 工作所需的知识也写

    入了本书,以便新的公司成员能尽快熟悉工作。

    因此本书从搭建工作环境开始讲起,逐步涉及 Web 应用的开发、项目管理及审

    查、测试代码的编写与高效部署、服务器调试等方面,网罗了 Python 项目开发工

    作中的一系列流程。书名中的“实战”一词就包含了“工作”的意思。

    书中所写的技巧主要源于我们的 Python2 开发经验。也正因为如此,本书将

    以 Python2 为例进行讲解。如今新的开发项目已经在使用 Python3,这些技巧转

    移到 Python3 上理应同样适用。

    进入正题之前,先来聊聊我们的日常思路。极客 书虫常伴身边的公司

    BePROUD 里不乏极客和书虫们。在这里,很多人对特定领域的了解程度能吓掉

    你的下巴。

    在这里,人们一旦发现感兴趣的事,就会拿出私人时间来学习、实践。要知

    道,极客和书虫们不会为这种事情吝啬时间。

    正如人们印象中的那样,极客和书虫们大多有些怪癖,但 BePROUD 的员工都

    具备下列共识。

    希望能不做不想做的事

    希望学会好的方法并付诸实践

    希望工作时有个好心情希望能不做不想做的事

    在工作中,重复单调的作业是一种极其无趣的事,因此能一次办完的事谁都不

    想去办两次。另外,大家也都讨厌工序复杂、容易出错的工作。所以要开动脑筋,把复杂的工序简单化,同时尽量减少出错的机会。希望学会好的方法并付诸实践

    世界上有许多公认的好方法、新思路和新技巧,我们要勇于尝试,学习它们并

    付诸实践。

    使用好的方法必然能帮助我们削减不想做的工作。不过,方法的好坏不能人云

    亦云,我们必须选出对自己真正有帮助的方法,然后再将所学方法应用到实际业务

    当中。希望工作时有个好心情

    现在,我们学会了优秀的方法、削减了繁杂的工作,之后自然希望带着好心情

    去工作。此时不妨给 Skype 做个好玩的 bot,或者在下班后找个会议室搞一场妙

    趣横生的快速演讲。我们希望大家能在保质保量完成工作的同时有个好心情,而不

    是只把公司当作工作的场所。这是我们的理念。

    本书的内容全部基于事实,都是 BePROUD 员工实际尝试、实践过的。我们希

    望给各位提供一些能实际应用且行之有效的知识,而不是让各位去死记硬背一大堆

    晦涩难懂的概念。我们很愿意看到本书的知识能对各位有所帮助,愿各位能在工作

    中有个好心情。谢辞

    本书在编撰过程中承蒙多名 IT 业界高人指点:寺田学(@terapyon)、金子

    望、关根裕纪(@checkpoint)、畠弥峰(@flag_boy)、小坂健二朗

    (@inoshiro)、筒井隆次(@ryu22e)、永井孝(@ngi644)、中西直树

    (@nk24)、尾曾越雅文、柴田正明(@_mshibata)、真幡康德(@mahata)、中

    石宜亨(@eiryplus)。各位在百忙之中仍担起审校工作,慷慨赐教,我们在此表

    示由衷的感谢。此外还有 BePROUD 公司的 haru、altnight、masaya、crohaco、nakagami、yyyk,感谢几位一边处理着公司内繁忙的开发工作,一边见

    缝插针地为本书进行审校。

    最后感谢各位未能在著者处署名的 BePROUD 员工。如果没有各位员工长期以

    来的切磋琢磨,这本书永远不会问世。

    至此,希望这本集诸人之力编撰出来的书,能为 IT 业界出一份绵薄之力。

    全体执笔者

    2015 年 1 月

    本书网址

    http:www.ituring.com.cnbook1719

    本书介绍的软件版本和 URL 均为截止到 2015 年 1 月底的最新信

    息,当前可能已发生变更。

    前言

    本书涉及的内容

    本书分为 4 个部分,共 15 章。

    第 1 部分“Python 开发入门”的重点将放在个人开发。内容涵盖 Python

    开发过程中必不可少的工具的安装(第 1 章),简单的 Web 应用开发(第 2

    章)以及 Python 项目的结构与包的创建(第 3 章)。

    第 2 部分“团队开发的周期”将为各位说明多人团队开发的相关问题。这部分

    将重点介绍团队高效开发过程中不可或缺的技术和技巧,内容涵盖团队开发前的环

    境调整(第 4 章)、项目管理与审查(第 5 章)、源码管理(第 6 章)、文档

    (第 7 章)、模块设计与单元测试(第 8 章)、封装及其运用(第 9 章)、持

    续集成(第 10 章)等。

    第 3 部分“服务公开”将向各位讲解如何搭建与运用正式环境公开 Web 服务

    (第 11 章),此外就是有关性能调节的一些方法(第 12 章)。

    第 4 部分“加速开发的技巧”可以说是加速开发的一些小贴士。例如将测试的

    概念导入整个开发流程以加快项目进度(第 13 章),Django 的基础及其进阶

    性、实践性的用法(第 14 章),Python 的辅助模块(第 15 章)等。阅读本书前的准备

    环境及版本

    OS: Ubuntu-14.04

    Python: 2.7.6

    Bash: 4.3

    从第 2 章起,如无特别说明,则运行环境皆由 virtualenv 搭建 。

    关于 OS

    实体机使用 WindowsOS XLinux,服务器的测试环境使用虚拟机上的

    Ubuntu。

    Python 的官方手册

    https:docs.python.org2.7

    我们仅对 Python 官方手册中的内容做最低限度的介绍,部分说明会被省略。

    因此建议各位手边时常准备一份参考手册以便阅读。

    Python 的官方教程非常适用于学习 Python 的基本安装流程、语法、术语、类以及模块。本书将以各位看过这份教程为前提进行讲解。

    UnixLinux 的一般命令操作

    本书虽以 Ubuntu Linux 为前提讲解,但书中不对 Ubuntu Linux 的基本命

    令操作进行说明。

    关于 PyPI(Python Package Index)

    PyPI 是一个集中管理包的网站,pip 等自动包安装工具会用到它。本书使用 1的包也来自 PyPI。

    https:pypi.python.orgpypi

    关于敏捷过程与极限编程

    本书并不对敏捷过程(Agile Process)和极限编程

    (ExtremeProgramming)做单独的说明。如今在许多书籍和网站上都能找到这二

    者的介绍,感兴趣的读者可以去读一读。

    本书面向的人群

    希望改善个人开发环境的人

    希望改善团队开发的人

    想学习工作中可使用的 Python 技巧的人

    新加入 BePROUD 公司项目的成员

    注意

    本书基于作者本人的调查结果而成。

    我们在加工本书时力求完美。不过若您发现本书存在不足和错

    误、漏记等问题,请书面联系出版方。

    对于因本书内容运用不当而导致的结果及其影响,无论是否因上

    述两项内容引起,我们均不负责,请知悉。

    未获得出版方书面许可不得全部或部分复制本书。

    商标等

    本书已省略 ? ? ? 等符号。

    1Python 徽标是 the Python Software Foundation的商标。

    Django 和 Django 徽标是 Django Software Foundation的

    商标。

    Google App Engine 是 Google Inc. 的商标。

    Jenkins 是 SOFTWARE IN PUBLIC INTEREST, INC. 的商标。

    nginx 是 Nginx Software Inc. 的商标。

    VirtualBox 是 ORACLE AMERICA, INC. 的商标。

    Ubuntu 是 Canonical Limited 的商标。

    此外,公司名和商品名、系统名一般为各开发者的注册商标。

    本书注册商标中还使用了普遍使用的通用名。

    第 1 部分 Python 开发入门

    在第 1 部分中,我们将搭建 Python 的基本环境,并进行简单的 Web 应用开

    发。然后根据已开发出的 Web 应用进一步优化环境,继续开发流程,直至其可以公

    开给一般用户使用。

    第 1 章 Python 入门

    第 2 章 开发 Web 应用

    第 3 章 Python 项目的结构与包的创建

    第 1 章 Python 入门

    各位在学习新技术或新编程语言时,是否对准备工作发过愁呢?往往学习还没

    有正式开始,就先在准备工作上迷失了方向。好不容易硬着头皮开始准备,却发现

    安装完一个软件之后又不知道该干什么了。最后自以为准备完毕兴冲冲地要开工

    时,才注意到应该装好的东西并没有正确安装。到头来,大把的时间花在了准备阶

    段上,再无心情去学习了。类似这种情况不知道各位遇到过没有。

    搭建 Python 开发环境时要考虑 OS 与版本等诸多组合,所以这个过程很难保

    证一帆风顺。独立开发者,尤其是自学成才的开发者们,大多是以网页或书籍上的

    信息作为参考,然后用自己独有的方法进行搭建。但即便如此,其中有些共通点还

    是需要了解的。

    第 1 章中,我们将按部就班地了解对个人开发者来说共通的环境搭建顺序,让

    初学者也能顺利搭建环境。

    因此,我们将在第 1 章中对下列项目进行重点学习。其中有部分内容涉及虚拟

    机,所以我们将学习时使用的本地实体机的 OS 称为“主 OS”,虚拟机的 OS 称

    为“客 OS”。已经自己搭建好 Python 开发环境的读者可以跳过本章。

    安装 Python

    安装 Mercurial

    关于编辑器以及开发辅助工具1.1 安装 Python

    本节将带领各位安装一些便于在 Ubuntu 上使用 Python 进行开发的工具和

    包。

    NOTE

    本书以 Ubuntu 14.04(Server 版)作为 Python 开发环境的OS。另

    外,我们使用 OracleVMVirtualBox 承载客 OS。搭建环境的相关内容收录在

    附录 A 以及附录 B 中,初学者请先参考附录再阅读以下内容。

    1.1.1 安装 deb 包

    Ubuntu 可以用 apt-get 命令管理包。我们先来更新所有包,同时安装一些

    Python 开发所需的包。

    LIST 1.1 deb 包的更新、升级

    sudo apt-get -y update

    sudo apt-get -y upgrade

    sudo apt-get -y install build-essential

    sudo apt-get -y install libsqlite3-dev

    sudo apt-get -y install libreadline6-dev

    sudo apt-get -y install libgdbm-dev

    sudo apt-get -y install zlib1g-dev

    sudo apt-get -y install libbz2-dev

    sudo apt-get -y install sqlite3

    sudo apt-get -y install tk-dev

    sudo apt-get -y install zip

    sudo apt-get -y install libssl-dev如 LIST 1.1 所示,我们在执行命令时添加了 -y 选项。这样一来,在安装过

    程中被询问 Yes 或 No 时,计算机会自动帮我们选择 Yes。如果各位想亲自逐个

    确认,可以将 -y 选项删去。

    build-essential 包可以批量安装 Python 在 Ubuntu 上进行构建时所需的

    全部工具(gcc、make 等)。Python 本身在涉及某些包和模块时也必须有这些基

    本工具才能进行安装,因此建议各位先装好它们。

    接下来安装 Python 相关的包(LIST 1.2)。

    LIST 1.2 安装 Python 相关的包

    安装python-dev

    sudo apt-get -y install python-dev

    安装pip

    wget https:bootstrap.pypa.ioget-pip.py

    sudo python get-pip.py

    pip 是管理 Python 第三方库的工具。虽然它也能通过 apt 命令进行安装,但那样安装的版本较低,因此我们使用 get-pip.py 来安装最新版。

    至此 Python 相关的包已经安装完毕。最后我们来查看一下 Ubuntu 默认自带

    的 Python 的版本。

    LIST 1.3 查看 Python 的版本

    python -V

    Python 2.7.6输入 LIST 1.3 中的命令,我们便能够查看到当前安装的 Python 版本。

    Ubuntu 默认安装的是 Python 2.7.6。

    专栏 ensurepip

    Python 3.4 具有 ensurepip 模块,可在安装 Python 的同时捆绑安装

    pip。这个模块是在 Python 2.7.9 之后加入的。支持 ensurepip 的

    Python 可以直接使用 pip,不需要执行 get-pip.py 来进行安装。另外,执

    行 python -m ensurepip -U 可以将 pip 更新到当前最新版本。

    ensurepip

    https:docs.python.org2.7libraryensurepip.html

    PEP 477: Backport ensurepip(PEP 453) to Python 2.7

    https:www.python.orgdevpepspep-0477

    1.1.2 安装第三方包

    用 pip install 命令可以安装第三方开发的包。

    第三方包注册在 PyPI 上。这是一个用来共享 Python 包的版本库

    (Repository),任何人都可以将 Python 包上传到上面,同时也可以从上面自

    由下载想用的包。用 Python 开发软件时,常常要从 PyPI 安装所需的包。

    NOTEPyPI 的读音是 'pa?pi: ai。

    PyPI 的构造类似 Perl 中的 CPAN 、Ruby 中的 RubyGems 、PHP 中

    的 PEAR 等。

    http:www.cpan.org

    http:rubygems.org

    http:pear.php.net

    从 PyPI 安装包时需要用到 pip 命令。

    NOTE

    有关 pip 的详细内容我们将在第 3 章中详细了解。

    这里简单了解一下 pip 的使用方法。首先我们来查看当前安装的 pip 的版本

    (LIST 1.4)。

    LIST 1.4 查看 pip 的版本

    pip --version

    pip 1.5.6 from usrlocallibpython2.7dist-packages (python 2.7)

    可以看到当前版本为 1.5.6(2014 年 12 月 9 日时)。

    NOTE

    上面例子中的 pip 安装在 dist-packages 目录下,只有通过 debian

    和 ubuntu 包安装 Python 时才会安装到这个特有的位置。如果是通过

    Linux 发行版、OS X、源码安装,则会安装在 site-packages 目录下。

    1 2

    3

    1

    2

    3通过 pip 安装第三方包的方法如下。首先我们来安装常用的 virtualenv 包

    (LIST 1.5)。

    LIST 1.5 通过 pip 安装包

    sudo pip install virtualenv

    -(中间省略)-

    Successfully installed virtualenv

    Cleaning up...

    此后,包的安装基本都要用 pip 命令来完成。另外,上面例子中的

    virtualenv 包安装在 usrlocallibpython2.7 目录下。

    NOTE

    pip 在安装一些需要构建的包时,会用 gcc 等编译器进行构建。在本书

    所用的 Ubuntu 下,我们已经通过 build-essential 安装了 gcc。Windows

    下需要用 Microsoft Visual C++ Compiler for Python 2.7 或者 MinGW

    等进行安装。这些都是免费的。

    1.1.3 virtualenv 的使用方法

    前面安装的 virtualenv 是用来搭建虚拟 Python 执行环境的。我们将其称

    为 virtualenv 环境。使用这个环境时,包不会安装到

    usrlocallibpython2.7 下,而是安装到虚拟 virtualenv 环境中。

    由于我们在前面已经完成了安装,所以这里可以直接查看版本(LIST 1.6)。

    LIST 1.6 查看 virtualenv 的版本 virtualenv --version

    1.11.6

    NOTE

    有关 virtualenv 的详细内容我们将在第 3 章中详细了解。

    我们在未使用 virtualenv 的状态下查看当前版本(LIST 1.7)。

    LIST 1.7 用 pip freeze 查看当前安装版本

    pip freeze

    PAM==0.4.2

    Twisted-Core==13.2.0

    apt-xapian-index==0.45

    argparse==1.2.1

    configobj==4.7.2

    :

    :

    输入 pip freeze 命令后,我们便能看到所有安装在

    usrlocallibpython2.7 目录下的包。

    接下来新建 virtualenv 环境。我们在主目录(HOME 目录)下创建工作目

    录,然后在这个工作目录下搭建 virtualenv 环境(LIST 1.8)。LIST 1.8 搭建 virtualenv 环境

    mkdir ~work

    cd ~work

    virtualenv venv

    执行 LIST 1.8 中的命令后,work 目录下会自动生成 venv 目录。这就是

    virtualenv 环境的目录。

    接下来我们启动 virtualenv 环境。

    LIST 1.9 启动 virtualenv 环境

    source venvbinactivate

    (venv)

    如 LIST 1.9 所示,通过 source 命令执行 activate ,启动 virtualenv

    环境。如果终端的开头显示了“(venv) ”(图 1.1),就证明 virtualenv 环境

    已经启动。

    图 1.1 activate 后的 virtualenv 的状态我们在启动了 virtualenv 的状态下再次执行 pip freeze ,查看当前已安

    装的包(LIST 1.10)。

    LIST 1.10 在虚拟环境下查看版本

    (venv) pip freeze

    argparse==1.2.1

    wsgiref==0.1.2

    可以看到,在 virtualenv 环境刚刚搭建完成时,这个 Python 执行环境中

    没有添加安装任何包(argparse、wsgiref 是与 Python 本体捆绑的标准库)。

    想关闭 virtualenv 环境时,输入 LIST 1.11 中的命令即可。

    LIST 1.11 关闭 virtualenv 环境

    (venv) deactivate

    如果我们不再需要某个 virtualenv 环境(本例中是 venv 目录),则可以

    直接用 rm -R venv 等命令将其连同所在目录一起删除。

    1.1.4 多版本 Python 的使用目前,Python 3.X 系列和 2.X 系列的开发是并行的,因此我们会遇到不同项

    目使用不同版本的 Python 的情况。本小节中,我们将学习如何在一个客 OS 环境

    下准备多个版本的 Python,以满足不同应用的需要。

    Ubuntu 14.04 默认安装了 Python 2.7.6 和 Python 3.4.0。

    LIST 1.12 查看 Python 的版本

    python3 -V

    Python 3.4.0

    python -V

    Python 2.7.6

    现在我们将 Python 2.7 系列的最新版本 Python 2.7.9 安装到客

    OS(Ubuntu 14.04)上。

    http:www.python.orgdownloadsreleasepython-279

    Ubuntu 14.04 上安装 Python 的方法有下列几种。

    通过 Ubuntu 官方 deb 包安装

    通过源文件构建安装

    通过 PPA(Personal Package Archives,个人软件包档案)以 deb 包

    的形式安装

    通过 deb 包的安装十分简便,但包中封装的不一定是最新版的 Python。某些

    版本的 Python 含有重要更新,这时候就需要我们通过源文件进行构建了。鉴于这

    类情况,我们将在这里介绍“通过源文件构建”这一安装方式(LIST 1.13)。

    4

    4LIST 1.13 通过源文件构建并安装

    wget https:www.python.orgftppython2.7.9Python-2.7.9.tgz

    tar xvzf Python-2.7.9.tgz

    cd Python-2.7.9

    LDFLAGS=-Lusrlibx86_64-linux-gnu .configure --prefix=optpython2.7.9

    make

    sudo make install

    该 Python 将被安装到 optpython2.7.9bin 下,我们可以通过文件名中

    的版本号找到它。现在执行 Python 命令查看是否安装成功(LIST 1.14)。

    LIST 1.14 查看 Python 2.7.9

    optpython2.7.9binpython -V

    Python 2.7.9

    到这里,Python 的安装就结束了。接下来我们看看如何在开发应用时区分使

    用各个版本的 Python。

    NOTE

    像 Python 2.6 这种官方 apt 版本库早已不支持的旧版本,我们可以通

    过PPA,即分享个人软件包的 apt 版本库进行安装(LIST 1.15)。但要注意,PPA 中的软件包全都是个人上传的,一切使用后果要由自己负责。

    LIST 1.15 通过 PPA 以 deb 包的形式安装

    sudo add-apt-repository ppa:fkrulldeadsnakes

    sudo apt-get -y update

    sudo apt-get -y install python2.6

    python2.6 -V

    Python 2.6.9

    NOTE

    Python 的部分模块依赖于一些必须通过 apt 命令进行安装的包。对于这

    类 Python 模块,如果不事先用 apt 命令安装好包,则会发生

    ImportError。

    这种时候我们需要先用 apt 命令安装所需的包,然后再通过源文件进行构

    建。因此如果各位遇到 Python 模块无法使用的情况,可以考虑重新通过源文

    件构建一遍。有些 Python 的标准模块需要先安装 deb 包才能使用,具体内

    容如下所示。

    Python 模块 deb 包

    zlib zlib1g-dev

    sqlite3 libsqlite3-devreadline libreadline6-dev

    gdbm libgdbm-dev

    bz2 libbz2-dev

    Tkinter tk-dev

    借助 virtualenv 分别使用不同版本的 Python

    当 OS 中安装了多个 Python 时,我们可以通过完整路径指定 Python 命

    令,或者使用带版本号的 Python 命令(如 python2.7 和 python3.4 )来区分

    使用各版本。

    不过,如果在搭建 virtualenv 环境时指定了该环境下的默认 Python,那么

    在启动该环境时,我们就不需要顾虑版本问题了。

    LIST 1.16 指定 virtualenv 下执行的 Python

    virtualenv --python=optpython2.7.9binpython venv2

    source venv2binactivate

    (venv2)

    Python 2.7.9

    根据 LIST 1.16 进行指定之后,以 optpython2.7.9binpython 为基

    础的 virtualenv 环境——venv2 就搭建完成了。1.2 安装 Mercurial

    版本控制系统在如今的开发过程中已经十分普及,Python 自然也不例外。人

    们使用版本控制系统通常是为了多人一起管理源码,不过,将它引入到个人开发中

    也能带来不少好处。比如在开发过程中应用突然不工作了,我们就可以将其回溯成

    能正常工作的版本。另外,对版本进行管理之后,一旦哪里发现了问题,我们可以

    立刻沿时间线查找之前的版本,快速找出问题发生的时间点。

    版本控制系统大致可分为两类,一类是 CVS 和 Subversion 这种单一版本库

    的版本控制系统,另一种则是 Mercurial 和 Git 这种分布式版本控制系统

    (Distributed Version Control System,DVCS),如今越来越多人倾向于使

    用后者。Mercurial 这种分布式版本控制系统最大的优势在于各个版本库独立,因

    此在创建分支、提交、取消更改时不会对周围人造成影响。而且分布式的版本库可

    以各自看作是彼此的备份。

    接下来我们来了解一下 Mercurial。

    1.2.1 Mercurial 概述

    Mercurial 是 Linux 内核的开发者 Matt Mackall 于 2005 年开始开发的

    分布式版本控制系统。Linux 内核之父 Linus Torvalds 也于同期开始开发

    Git。如今这二者已经成为分布式版本控制系统的代表,被人们广泛使用。

    由于 Mercurial 本身就是由 Python 编写而成的,因此我们可以轻松地通过

    pip 进行安装,也可以将其视为 Python 程序进行自定义设置。

    对熟悉 Python 的用户而言易于上手,与使用 Python 进行开发的团队亲和力

    高,这些都是 Mercurial 的优势所在。

    此外,Mercurial 的魅力还在于内置了基于 Web 的管理工具,支持

    Bitbucket 等著名源码托管服务,TortoiseHg 等 GUI 客户端丰富,等等。

    http:bitbucket.org

    5 6

    5

    6 http:tortoisehg.bitbucket.org

    不仅如此,Mercurial 的命令体系与广为人知的 Subversion 很类似,对于

    长期使用 Subversion 的用户而言,要比 Git 更容易上手。

    1.2.2 安装 Mercurial

    单看前面的说明很难对分布式版本控制系统的优势有一个明确理解,所以现在

    我们通过实际的安装和操作来体会一下。另外,高级的 Mercurial 运用技巧我们

    将在第 6 章中进行学习,熟悉 Mercurial 的读者可以直接跳过本部分。

    Mercurial 与其他程序包一样具有多种安装方法,用户可以通过 apt-get

    、pip 、源文件构建等不同途径进行安装。这里我们为保证 Mercurial 尽量是最

    新版,决定选用 pip 进行安装(LIST 1.17)。

    LIST 1.17 安装 Mercurial

    sudo pip install mercurial

    Mercurial 安装完成后我们就可以使用 hg 命令了。现在输入 hg --

    version 来查看版本(LIST 1.18)。

    LIST 1.18 查看 Mercurial 的安装情况

    hg --version

    Mercurial Distributed SCM (version 3.1.2)

    (see http:mercurial.selenic.com for more information)

    Copyright (C) 2005-2014 Matt Mackall and others

    This is free software; see the source for copying conditions. There is NO

    6warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    1.2.3 创建版本库

    在创建版本库之前,我们先准备好 Mercurial 的环境设置文件。在主目录下

    创建名为 .hgrc 的文件,然后进行如下描述。其中括号内的部分称为节

    (Section),比如 [ui] 节就是用来设置 username 属性的。

    username 中的账户信息会在用户向版本库进行提交时记录在日志中。各位请

    将自己的账户名和邮箱地址写在这里(LIST 1.19)。

    LIST 1.19 设置 .hgrc 的用户名与邮箱地址

    [ui]

    username=bpbook

    [extensions]

    color=

    pager=

    [pager]

    pager=LESS='FSRX' less

    [extensions] 节用来激活 Mercurial 附属的扩展工具。只要将扩展工具名写入 [extensions] 节的项目中,我们就可以使用该工具了。此外,某些扩展工具

    不仅要在 [extensions] 中设置激活,还需要在 [pager] 节中设置 pager 属

    性。

    完成环境设置文件之后就该创建版本库了。如 LIST 1.20 所示,我们为版本

    库创建一个目录并移动至该目录下,执行 hg init 命令创建版本库。

    LIST 1.20 hg init(初始化版本库)

    mkdir ~hgtest

    cd ~hgtest

    hg init

    1.2.4 文件操作

    创建好版本库之后让我们给它实际添加文件。现在创建一个测试用的文件,查

    看当前版本库的状态。

    查看版本库状态用 hg status 命令(LIST 1.21)。如果觉得每次输入

    status 太麻烦,可以将这个命令缩写为 hg st 。hg 命令为用户准备了部分缩写

    形式,感兴趣的读者可以参考帮助或其他资料。

    LIST 1.21 hg status(查看状态)

    touch test.txt

    hg status

    test.txt文件名左侧显示了该文件在版本库内的状态。各位可以看到 text.txt 文件的

    左侧显示了状态“? ”,这代表该文件现在并不在版本管理的范围内。因此我们执

    行 hg add 命令将其添加为版本管理的对象,如 LIST 1.22 所示。

    LIST 1.22 hg add(添加文件)

    hg add test.txt

    hg status

    A test.txt

    执行 hg add 之后我们再进行一次查看,会发现之前的“? ”已经变成了“A”。这代表该文件是新添加到版本管理里的。

    要想让添加文件反映到版本库,我们需要进行提交。提交时请按照 LIST 1.23

    所示,输入 hg commit 命令。如果不执行 hg commit ,那么我们创建的文件就

    只能停留在当前工作的机器里,不会反映到版本库中。

    LIST 1.23 hg commit(提交)

    hg commit

    test commit

    HG: Enter commit message. Lines beginning with 'HG:' are removed.HG: Leave message empty to abort commit.

    HG: --

    HG: user: bpbook

    HG: branch 'default'

    HG: added test.txt

    执行 hg commit 后编辑器就会启动,用来记录提交时的相关信息与注释。我

    们在这里输入 test commit 。

    注释输入栏下方显示着 branch 'default' ,这表示 default 分支(版本

    库创建时就存在的分支)为我们当前进行修正 添加操作的对象。

    NOTE

    提交时打开的编辑器是可以更改的。更改时需要如下例所示,在 .hgrc

    的 [ui] 节里添加 editor 属性。

    [ui]

    editor = vim

    这表示我们要使用vim 编辑器。默认启动的编辑器取决于环境变量

    EDITOR,环境变量可以用下述命令查看。

    echo EDITORvim

    提交文件之后用 hg status 查看,结果应该如 LIST 1.24 所示,什么都没

    有。

    LIST 1.24 提交后的查看

    hg status

    接下来我们看看如何在 Mercurial 中操作编辑过的文件。

    先用编辑器打开 test.txt 进行修改,然后保存文件。在当前状态下执行 hg

    status 后,会发现该文件的状态变成了 M 。状态 M 表示该文件在最后一次提交

    之后又进行了“变更”(Modify)。使用 hg diff 命令可以查看变更前的状态

    (已提交的文件)与当前状态的差别(LIST 1.25)。

    LIST 1.25 hg diff(查看差别)

    hg status

    M test.txt

    hg diff

    diff -r 74471564b074 test.txt--- atest.txt Mon Oct 31 18:07:15 2014 +0900

    +++ btest.txt Mon Oct 31 18:10:45 2014 +0900

    @@ -0,0 +1,1 @@

    +modify this file

    在尚未提交的状态下,我们可以使用 hg revert 命令撤销编辑(LIST

    1.26)。

    LIST 1.26 hg revert(撤销编辑)

    hg revert test.txt

    NOTE

    hg revent 可以撤销尚未提交的内容,但对已提交的内容无效。这种情况

    需要使用 hg commit --amend 命令对已提交的变更集进行修改或撤销。

    Mercurial 的基本操作方法就解说到这里,但下列几项我们并未提及。

    分支的操作

    远程版本库的使用

    以团队开发为前提的 Mercurial 的使用方法上述几点我们将在第 4 章和第 6 章中详细了解。1.3 编辑器与辅助开发工具

    本节将介绍编写 Python 代码时可用的编辑器,以及一些有助于开发的小贴士

    和 Python 模块。

    1.3.1 编辑器

    编写 Python 代码自然少不了编辑器。当今世上的编辑器种类繁多,但编写

    Python 代码的编辑器必须具备下列几项功能。

    语法高亮

    将语法设置高亮是一项十分重要的功能。用特殊字色或字体表示关键词可

    以让编程人员快速发现拼写类错误。这样一来,我们便能够在编写代码的过程

    中注意并修正此类错误。

    智能缩进

    自动根据语法添加缩进的功能。特别是对于Python这类缩进具有重要意义

    的语言,编辑器适时地自动缩进要比手动插入空格时的编程效率高得多。

    执行 DEBUG

    在编辑器上执行DEBUG的功能。比如在编程过程中遇到某些问题时,如果能

    直接使用编辑器进行DEBUG,那么将能更快地找出原因,提高解决问题的效率。

    可以使用静态解析类插件

    能在编辑器上执行静态解析类插件的功能。如果能直接在编辑器内执行语

    法高亮无法查出的键入错误、语法错误、编码格式检查等,将能省去每次开关

    编辑器的麻烦,大幅削减修改时消耗的时间。

    这里将按照上述 4 点,给各位介绍 3 个编辑器(Vim、Emacs、PyCharm)的

    使用方法和功能。各位可以以此为参考来寻找自己用着顺手的编辑器。

    Vim

    Vim 是一款功能强大的文本编辑器,默认搭载在许多 OS 上,普及度很高。

    Vim 可以通过内置的 Vim script 脚本语言进行功能扩展,因此存在许多插

    件。

    语法高亮

    默认捆绑Python的语法高亮设置文件(python.vim)。

    智能缩进

    有自动缩进的设置选项。缩进时插入的空格数也可以调节。

    执行 DEBUG

    Vim可以在编辑器上调出外部命令,因此可以执行pdb (后述)。比如执

    行:!pathtovirtualenvpython -m pdb % 之后,编辑器便会对编辑中

    的脚本启动调试工具。

    可以使用静态解析类插件

    vim-flake8插件可以检查当前打开的文件并发出问题警告。

    Vim 的设置在主目录“.vimrc ”文件中进行,我们写在该文件中的设置将反

    映在 Vim 上。

    现在我们来设置语法高亮和自动缩进(LIST 1.27)。

    LIST 1.27 用于 Python 的设置

    语法高亮的设置

    syntax on

    自动缩进的设置

    filetype plugin indent on另外,设置文件本身也可以根据对象文件类型进行分割。下面,我们专门为

    Python 脚本准备一个设置文件(LIST 1.28)。

    LIST 1.28 准备 Python 专用的设置文件

    mkdir ~.vim

    mkdir ~.vimftplugin

    touch ~.vimftpluginpython.vim

    我们在这个 python.vim 中进行针对 Python 的设置,以方便编写 Python

    代码。

    LIST 1.29 将 Tab 改为 4 个空格

    将“Tab”替换为“空格”

    setl expandtab

    将“Tab”的“缩进幅度”改为4

    setl tabstop=4

    自动缩进时的“缩进幅度”改为4

    setl shiftwidth=4

    按下键盘“Tab”键时插入的空格数

    这里设置为0 就可以插入“tabstop”中设置的空格数了

    setl softtabstop=0

    保存时删除行尾的空格autocmd BufWritePre :%s\s\+ge

    80 个字符换行

    setlocal textwidth=80

    像 LIST 1.29 这样设置是为了迎合 Python 社区推荐的 PEP 8 编码格式

    (后述)。

    https:www.python.orgdevpepspep-0008

    vim-flake8 是 Vim 的插件,需要进行安装。neobundle.vim 是一个专门

    用来管理 Vim 插件的插件,用它可以轻松安装其他 Vim 插件。

    https:github.comShougoneobundle.vim

    安装 neobundle.vim 后,我们在“.vimrc”里这样设置 vim-flake8。

    NeoBundle 'nvievim-flake8'

    现在只要重启 Vim 就会开始安装插件。安装结束后,用 Vim 打开 Python

    脚本,按下 Ctrl + F7 就可以看到 flake8 的警告信息了。

    NOTE

    python.org 官方 Wiki 上也记载着 Vim 的一些设置资料,各位不妨去

    7

    7

    8

    8看一看。

    · Vi Improved

    此外,在Vim 官方网站和许多民间社区中都能找到大量关于Vim 的信息。

    · Vim online

    · vim-jp

    https:wiki.python.orgmoinVim

    http:www.vim.org

    http:vim-jp.org

    Emacs

    Emacs 是 Unix 系列 OS 长期沿用的编辑器。该编辑器可以用 Emacs Lisp

    语言进行扩展,因此拥有大量插件。如今的 Emacs 已经捆绑了 python.el,安装

    Emacs 之后可以直接编写 Python 代码,不必特意去设置。

    人们常说 Emacs 是一个环境,不过我们在这里主要是看它作为 Python 编辑

    器的特征。

    语法高亮

    内置python.el。当global-font-lock-mode 不为nil 时(默认)进行

    语法高亮。

    智能缩进

    python.el会按照PEP 8的要求缩进到指定位置。

    执行 DEBUG

    Emacs上可以执行pdb 。

    先键入M-x pdb ,然后直接在minibuffer里运行类

    9

    10

    11

    9

    10

    11似pathtovirtualenv python -m pdb pathtoapp.py 的pdb命令

    行。此时会启动pdb专用的缓冲,我们可以在里面查看源码或进行调试。

    可以使用静态解析类插件

    flymake-python-pyflakes 可以在编码过程中高亮警告。

    安装完成之后我们在设置文件HOME.emacs.dinit.el 中设置 Tab 和空格

    的执行动作。另外,Emacs 可以让空格和 Tab 文字可视化。在 Python 中,缩进

    是语法的一部分,所以建议各位先将这些设置好(LIST 1.30)。

    LIST 1.30 空格和 Tab 的设置

    (require 'whitespace)

    (setq whitespace-style '(face tabs tab-mark spaces lines-tail empty))

    (global-whitespace-mode 1)

    (setq-default tab-width 4 indent-tabs-mode nil)

    (setq indent-tabs-mode nil)

    flymake-python-pyflakes 等插件并没有捆绑在 Emacs 中,所以我们需要

    通过 Emacs 的版本控制系统 elpa 进行安装。首先在 HOME.emacs.dinit.el

    文件中进行如 LIST 1.31 所示的设置。

    LIST 1.31 elpa 的程序包版本库设置

    (require 'package)

    (add-to-list 'package-archives

    '(melpa . http:melpa.milkbox.netpackages))

    (add-to-list 'package-archives

    '(marmalade . http:marmalade-repo.orgpackages))

    (package-initialize)通过 elpa 安装好 flymake 和 flymake-python-pyflakes 之后,我们再

    进行 LIST 1.32 所示的设置。

    LIST 1.32 flymake 的设置

    (require 'flymake)

    (require 'flymake-python-pyflakes)

    (add-hook 'python-mode-hook 'flymake-python-pyflakes-load)

    (setq flymake-python-pyflakes-executable flake8)

    设置好 flymake,我们编写源码时就能在 Emacs 上看到 flake8 的警告了。

    NOTE

    python.org 上有设置Emacs 的相关资料。

    · Emacs Editor

    另外,我们在其官方网站和许多Wiki 上也能找到大量Emacs 的信息。

    · GNU Emacs · EmacsWiki · Python Programming In Emacs

    https:wiki.python.orgmoinEmacsEditor

    12

    13 14 15

    12

    13 http:www.gnu.orgsoftwareemacsemacs.html

    http:www.emacswiki.org

    http:www.emacswiki.orgemacsPythonProgrammingInEmacs

    PyCharm

    对长期以来使用 Eclipse 等 IDE(Integrated Development

    Environment,集成开发环境)进行开发的人来说,IDE 用起来要比编辑器顺手得

    多。在当今众多的 IDE 中,普及率较高的当属 PyCharm 了。

    http:www.jetbrains.compycharm

    PyCharm 是一款 2010 年左右问世的 IDE,为 Windows、OS X、Linux 等

    OS 提供了相应的安装程序,同时还支持 Python 的 Web 框架 Django。PyCharm

    有多种许可证形态,比如付费的 Pro 版和免费的 Community 版等。其中付费的

    Pro 版还提供 30 天的免费使用期。

    与 Vim 和 Emacs 相比,PyCharm 自带了许多 Python 开发的辅助功能,在

    安装完之后可以立刻使用。相对地,自行开发插件则需要应用 Java 的知识,所以

    并不算容易。从这种角度来讲,这款工具可能并不适合极客们使用。

    如果各位实在无法适应 Vim 或 Emacs,那么建议先尝试 PyCharm 的

    Community 版。它作为编写 Python 时使用的 IDE,具有以下特征。

    语法高亮

    标准功能。PyCharm会根据当前项目使用的Python版本切换语法及内置函

    数等文字的高亮效果。

    PyCharm标准支持Python、HTML、CSS、JavaScript、XML、SQL以及

    CoffeeScript、Angular JS、LESS、SASS、SCSS等格式的高亮显示。Pro版

    还支持Django、Mako、Jinja2、Web2py、Chameleon模板的记法。

    智能缩进

    标准功能。PyCharm会按照PEP 8的要求缩进到指定位置。

    13

    14

    15

    16

    16与语法高亮相同,PyCharm也支持Python以外的其他格式。另外,用户还

    可以对各个项目的各个语言进行详细设置,比如规定插入Hard Tab还是空格

    等。

    执行 DEBUG

    标准功能。IDE中可以设置断点、逐句执行、显示执行中的变量值。Pro版

    可以用手边终端的IDE调试远程服务器上的进程。

    静态解析类功能

    标准功能。在编写代码的过程中,PyCharm会高亮显示对未使用的变量、未定义的名称、已过期函数的警告等。另外,PyCharm在执行解析功能时会从

    多角度分析Python代码是否存在风险。

    导入 PyCharm 之后,我们就可以不再为搭建环境劳神费心了。它为用户标配

    了大量功能,大部分人都可以在默认设置的状态下轻松使用。不过相对地,一旦习

    惯了这些懒办法,当极客的乐趣自然也会大打折扣。

    PyCharm 也并不适用于所有情况,比如编辑单个文件就很麻烦。这种情况需要

    先创建一个空项目,把待编辑的文件加入项目之后才能打开编辑。另外,PyCharm

    的使用环境建议内存为 2 GB 以上,显示器为 SXGA 以上。

    专栏 PyCharm 适合用来干什么

    PyCharm3 及之前的版本以提供面向 Web 开发者的辅助功能为主。从

    2014 年 11 月发布的 PyCharm4 开始,该系列 IDE 开始内置 IPython

    notebook 等功能,预计今后会逐步增添科学计算相关的辅助功能。

    1.3.2 开发辅助工具

    本部分将向各位介绍一些 Python 开发过程中应当了解的模式及 Python 包。

    交互模式单独执行 python 命令时,该命令会以交互模式执行。交互模式指通过对话方

    式输入并执行 Python 代码的模式。现在请直接输入 python 命令(LIST

    1.33)。

    LIST 1.33 启动交互模式

    python

    Python 2.7.6 (default, Mar 22 2014, 22:59:56)

    [GCC 4.8.2] on linux2

    Type help, copyright, credits or license for more information.

    >>>

    随后系统会进入等待输入的状态。我们可以在这个状态下直接编写 Python 代

    码。代码执行后的内容会直接显示在屏幕上(LIST 1.34)。

    LIST 1.34 Python 代码执行示例

    >>> import sys

    >>> sys.path

    ['', 'usrlibpython2.7', 'usrlibpython2.7plat-x86_64-linux-gnu','usrlibpython2.7lib-tk', 'usrlibpython2.7lib-old','usrlibpython2.7lib-dynload', 'usrlocallibpython2.7dist-packages','usrlibpython2.7dist-packages']

    >>>

    我们导入了标准模块 sys 并显示了 Python 包的搜索路径列表。

    最后一次执行的结果存储在变量“_ ”中,执行它就可以返回相同结果。交互

    模式让我们能随手轻松地查看代码,方便进行 DEBUG 等操作。如果想结束交互模

    式,可以按 Ctrl + d 或输入 exit 。NOTE

    交互模式在启动时会读取环境变量 PYTHONSTARTUP 中设置的文件。如果

    各位在启动交互模式时想顺便导入些什么,可以在这里进行设置。

    另外,IPython 模块可以将 Python 的交互模式用作调试器。该模块可通

    过 pip 安装。

    sudo pip install ipython

    导入IPython 后,交互模式会实现下述功能。

    · TAB 键补全代码

    · 使用通常的 Shell 命令

    · 与pdb(调试器)联动

    flake8(编码格式 语法检测)

    为更好地规范和优化 Python,人们以社区为中心给 Python 制定了

    PEP(Python Enhancement Proposals,Python 增强建议书) 指导规范。

    https:www.python.orgdevpeps

    其中 PEP 8 主要规范 Python 的编码格式。这里即将介绍的 flake8 模块就

    可以检查我们的代码是否符合该编码格式。如 LIST 1.35 所示,flake8 可通过

    pip 安装。

    LIST 1.35 安装 flake8

    17

    17 sudo pip install flake8

    flake8 不但能检查编码格式,还可以帮助我们找出语法错误以及一些已导入

    但未被使用的模块并发出警告。

    使用方法很简单,只要像 LIST 1.36 一样指定文件并执行 flake8 命令即

    可。

    LIST 1.36 flake8 执行示例

    flake8 sample.py

    sample.py:1:12: E401 multiple imports on one line

    sample.py:1:17: E703 statement ends with a semicolon

    sample.py:3:1: E302 expected 2 blank lines, found 1

    sample.py:4:5: E265 block comment should start with ' '

    sample.py:4:80: E501 line too long (83 > 79 characters)

    sample.py:5:15: E225 missing whitespace around operator

    NOTE

    由于我们平时使用的是 flake8,所以这里只对它进行了介绍。该类常用

    的程序包还有 PyLint 等,各位可以根据自己的开发风格选用合适的模块。

    pdb(调试器)最后我们来了解一下 Python 的调试器。如果各位曾经用过 C 语言的 gdb 等

    调试器,或者对 IDE 等上面附属的调试器有所接触,那么一定不会对插入断点、逐

    句执行等功能感到陌生。 Python 的调试器也具备这些功能。

    pdb 是 Python 的标准模块,不必另外安装。其最简单的用法就是在我们希望

    程序停止的位置插入如 LIST 1.37 所示的代码。

    LIST 1.37 pdb 的插入代码

    def add(x, y):

    return x + y

    x = 0

    import pdb; pdb.set_trace

    x = add(1, 2)

    执行这个插入了 LIST 1.37 中的代码的 Python 脚本时,脚本会停在上述插

    入代码的位置,然后启动对话型界面。

    LIST 1.38 pdb 执行示例

    python pdbtest.py

    > pdbtest.py(7)

    -> x = add(1, 2)

    (Pdb)本节我们对一些辅助开发的工具、Python 程序包等作了了解。由于涉及范围

    较广,我们只简单学习了部分使用方法。有关这些工具、程序库的详细信息请各位

    自行查阅相关文档。1.4 小结

    本章对下列话题进行了介绍,意在指导各位完成 Python 语言独立开发的事前

    准备。

    安装 Python

    安装 Mercurial

    编辑器和 DEBUG 工具

    为保证开发前的准备工作,本章介绍了许多工具的安装方法。这里介绍的很多

    内容在 Ubuntu 以外的 OS 上同样适用。此外,各位还可以编写自动完成安装的

    Shell 脚本,或者省略并简化本书介绍的步骤等,总之能做的事情还有很多。各位

    请根据自己的需要搭建适合自己的环境。

    NOTE

    进入第 2 章之前,我们先来看一下 The Zen of Python。The Zen of

    Python 是 Python 开发者之一 Tim Peters 撰写的文章,通过 19 个分项

    简明扼要地表达了 Python 的特点。The Zen of Python 现已作为 PEP

    20 公开发表,在交互模式下输入 import this 命令也可以看到这篇文章。

    我们强烈建议各位去读一读。

    >>> import this

    另外,@atsuoishimoto 在博客上对The Zen of Python 进行了详细讲

    18解,各位不妨参考一下。

    · The Zen of Python 解题 - 前篇 (日语)

    · The Zen of Python 解题 - 后篇 (日语)

    https:www.python.orgdevpepspep-0020

    http:www.gembook.org2010-09-20.html

    http:www.gembook.org2010-09-26.html

    19

    20

    18

    19

    20第 2 章 开发 Web 应用

    本章中,我们先来了解 Web 应用的概念,然后一起实际开发一个简单的留言板

    应用,借此来了解 Web 应用开发的基本流程。至于留言板应用,它类似于观光景点

    的留言板,可以让访问网站的人在上面添加留言,说白了就是一个简单的网络留言

    板。正文中会涉及 HTMLCSS 和 Python 代码,但本书将省去对这些语法的说

    明。另外,本章的开发环境为 VirtualBox 虚拟机上的 Ubuntu 和 Python

    2.7,同时还会用到 virtualenv。2.1 了解Web 应用

    要想开发 Web 应用,首先要知道 Web 应用是什么,它是怎样工作的。所以我

    们先来了解一下什么是 Web 应用。

    2.1.1 Web 应用是什么

    顾名思义,Web 应用就是可以通过网络使用的应用程序。比如 Google 的搜索

    服务、Gmail、Wikipedia、各种博客服务、Twitter 等迷你博客、GREE 和手机

    游戏、Facebook 等社交网站以及上面的社交游戏等,这些都是 Web 应用。人们使

    用 Web 应用时需要通过 Web 浏览器访问(连接)相应服务。

    那么,同样需要通过 Web 浏览器阅览的 Web 站点又如何呢? Web 站点只是

    单纯地显示页面,它们能称作 Web 应用吗?

    答案是不一定。某些 Web 站点或许可以称为 Web 应用。因为虽然有些东西在

    阅览者眼中像 Web 站点,但它实际上却是由 CMS(Content Management

    System,内容管理系统)等 Web 应用构成的。Web 浏览器会从访问对象的计算机

    (服务器)中下载 HTML、CSS、图片等各种内容,然后再把这些内容显示在我们的

    屏幕上。如果负责发送内容的服务器只是返回一些早已准备好的静态内容,那么这

    个 Web 站点就不能称作 Web 应用。只有能够动态生成并返回内容的系统(比如通

    过 Web 浏览器接收用户输入的数据,再根据这些数据生成内容)才能称作 Web 应

    用。

    NOTE

    CMS 是负责管理和发送文章、图片等内容的系统。Wiki 和博客系统也都

    属于 CMS。

    2.1.2 Web 应用与桌面应用的区别

    要通过 Web 浏览器连接服务器使用的应用叫 Web 应用;相对地,要将软件安装在计算机上才能使用的应用叫桌面应用。二者的区别如下。

    比较项目 Web 应用 桌面应用

    服务器 需要 可有可无

    网络连接 需要 部分应用需要

    使用 OS 具备的功能 不可能 可能

    安装 不需要 需要

    升级 不需要使用者专门注意 需要使用者亲自动手

    跨平台使用 有 Web 浏览器就能用 需要各平台分别作处理

    移动端支持 与 PC 端基本相同 需要各平台分别作处理

    运行速度 慢 快

    从这张表上看,二者各有所长。但如果要开发一个让使用者通过网络互相交流

    信息的应用,那么由于桌面应用也同样需要用到服务器,所以使用 Web 应用开发起

    来会简单很多。不过,这个表中的内容也不是一成不变的。

    比如 Web 应用本来离不开网络,但如今已有一部分应用可以离线运行。另外,某些桌面应用也开始具备自动升级新版本的功能(比如 Google Chrome),这让使

    用者不必再费心手动升级。可以说,Web 应用和桌面应用之间的距离正在逐渐缩

    小。

    2.1.3 Web 应用的机制接下来我们来了解一下 Web 应用的机制。

    从我们在 Web 浏览器中输入 URL 到显示出页面,其间要进行下述处理。

    ① 用户在 Web 浏览器中输入 URL

    ② 向 DNS 服务器询问该 URL 中的域名,获取 IP 地址

    ③ Web 浏览器连接该 IP 地址的 Web 服务器,开始 HTTP 通信

    ④ Web 服务器根据 HTTP 发送来的信息运行 Web 应用,获取相应内容

    ⑤ Web 服务器响应,返回执行应用后得到的 HTML、CSS、JavaScript、图片

    文件等内容

    ⑥ Web 浏览器将收到的内容显示在页面中

    下表是对上述处理流程中的术语进行的说明。

    Web 浏览器 通过 HTTP 等协议与 URL 所示的计算机通信,将 HTML、CSS、图片等内容显示在

    页面中的软件

    URL

    Uniform Resource Locator(统一资源定位符)的简称,其中包含域名。这个字

    符串用来表示计算机需要访问网络上的哪些内容

    域名 与 IP 地址挂钩的字符串(比如 URL 中包含的 www.beproud.jp 等字符串)

    DNS 服务器 可以通过域名查询 IP 地址的服务器

    IP 地址 这个数值用来在网络上识别我们想访问的计算机(以 IPv4 地址为例,IP 地址由 0

    ~ 255 的数字和点组成,比如 192.168.0.1)

    HTTP

    Hypertext Transfer Protocol(超文本传输协议)的简称,是与被访问计算机之

    间的通信协议

    HTML 用来描述文档(包括文字和图片等)结构的语言

    CSS 描述 HTML 等语言描述的文档该如何显示的语言、机制

    JavaScript 在 Web 浏览器上运行的程序

    Web 服务器 通过 HTTP 进行通信的服务器程序 计算机

    Web 应用 在 Web 服务器上运行的程序

    CGI Common Gateway Interface(通用网关接口)的简称,Web 应用的机制之一上述流程可以用图 2.1 表示。

    图 2.1 Web 应用的处理流程

    Web 应用与 CGI

    CGI 是 Web 服务器运行 Web 应用的一种机制。Web 服务器执行 CGI 程序

    (CGI 脚本),然后将该程序的标准输出结果作为 HTTP 通信的响应返回给对方。

    最简单的 CGI 程序就是在控制台界面上显示字符串。

    CGIHTTPServer 是 Python 标准模块中的 Web 服务器,它可以运行 CGI 程

    序。现在我们试着运行下面这个 CGI 程序(LIST 2.1)。

    LIST 2.1 hello.py

    !usrbinenv python

    print 200 OK

    print Content-Type: textplain

    print

    print Hello CGI!用 python 命令运行这个脚本,然后控制台界面中将显示如 LIST 2.2 所示

    的 4 行字符串。

    LIST 2.2 用 python 命令运行 hello.py 的结果

    python hello.py

    200 OK

    Content-Type: textplain

    Hello CGI!

    用 CGIHTTPServer 运行 CGI 程序时,待运行文件必须位于 cgi-bin 目录

    下,所以我们要创建这个目录并将 hello.py 放进去。另外,必须具有运行权限才

    可以运行这些文件,因此还要用 chmod 命令赋予运行权限。配置好 CGI 程序之

    后,我们就可以按照下面的例子,用 python 命令的 -m 选项运行

    CGIHTTPServer 了。

    LIST 2.3 CGI 程序的配置与 CGIHTTPServer 的运行

    mkdir cgi-bin

    mv hello.py cgi-bin

    chmod u+x cgi-binhello.py

    python -m CGIHTTPServer

    Serving HTTP on 0.0.0.0 port 8000 ...执行 LIST 2.3 中的命令后,在该环境(这里是 VirtualBox 上的

    Ubuntu)的 8000 端口等待请求的 Web 服务器将会启动。在终端按下 Ctrl + C

    键可以关闭服务器。

    要想通过本地环境(主 OS)的 Web 浏览器查看效果,我们需要先设置端口转

    发。设置方法与附录 B 中介绍的 SSH 端口的设置方法一样,这里我们给

    VirtualBox 的端口转发添加如下设置:主、客端口均为 8000,协议为 TCP。

    完成端口转发的设置后,我们只要通过 Web 浏览器访问

    http:127.0.0.1:8000cgi-binhello.py ,即可看到 Hello CGI! 字样。

    NOTE

    127.0.0.1 代表的是自己的计算机的 IP 地址。设置过 VirtualBox 的

    端口转发之后,我们对自己的计算机(主OS)的 8000 端口的访问会被转发到

    客 OS 的 8000 端口。

    本例中的 CGI 程序由 Python 代码编写而成。实际上,只要 CGI 程序能够

    进行标准输出,用任何语言都没有问题。

    Web 应用与应用服务器

    应用服务器指能运行 Web 应用的功能且能与 Web 服务器通信的服务器。处于

    启动状态的应用服务器会一直等待 Web 服务器发来请求,一旦接到请求便会运行

    Web 应用并返回结果。由于待运行的程序一直放在内存里,所以它的速度通常要比

    CGI 程序的速度更快。Web 服务器与应用服务器之间的通信协议通常为 HTTP 或

    FCGI 等。如果一个应用服务器可以通过 HTTP 通信,那么我们就可以用 Web 浏览

    器访问它。

    本章使用的 Flask 内置了用于开发的应用服务器(Web 服务器),因此不需

    要再另外准备 Web 服务器。2.2 前置准备

    接下来我们需要为开发 Web 应用做一些前置准备。这里需要使用 Python 和

    virtualenv,二者的安装请参考第 1 章。

    2.2.1 关于 Flask

    开发留言板应用时,我们会用到 Flask ,因此需要事先安装。Flask 是一个

    用 Python 编写的 Web 应用框架,它整合了 Werkzeug(WSGI 实用工具)和

    Jinja2(模板引擎)两个库。用它可以轻松完成小规模的应用程序开发。

    http:flask.pocoo.org

    2.2.2 安装Flask

    安装 Flask 之前,我们先用 virtualenv 命令搭建开发应用所需的虚拟环

    境。用 LIST 2.4 中的命令可以搭建出名为 venv 的虚拟环境。

    LIST 2.4 搭建名为 venv 的虚拟环境

    virtualenv venv

    通过 source 命令执行 venvbin 目录下的 activate 脚本,启动我们刚刚

    搭建好的虚拟环境(LIST 2.5)。执行完成后,命令提示符上会显示虚拟环境名

    (venv) 。

    1

    1LIST 2.5 启动虚拟环境 venv

    source venvbinactivate

    NOTE

    Windows 需要使用 venv\Scripts\activate 命令启动虚拟环境。

    接下来使用 pip 命令在虚拟环境上安装最新版本的 Flask。我们需要在 venv

    虚拟环境处于激活状态时执行 LIST 2.6 中的命令。

    LIST 2.6 用 pip 命令安装 Flask

    pip install -U Flask

    指定 -U 选项之后,可以用新版本替换已经安装的旧版本。2014 年 12 月

    时,最新的 Flask 版本为 0.10.1。至此 Flask 安装完毕,前置准备结束。2.3 Web 应用的开发流程

    那么,接下来我们应该按什么顺序开发 Web 应用呢?

    现在唯一确定下来的事情就是要开发一个留言板应用,除此之外毫无计划。首

    先我们要确定这个应用的需求,再以需求为出发点考虑如何实现页面和功能,然后

    开始敲代码。等编码完成后,还要测试该应用是否能够正常运行。

    整个流程总结起来是下面这样的。

    ① 确认需求(确认要开发什么应用)

    ② 根据需求明确成品必备的功能

    ③ 根据功能明确成品必备的页面

    ④ 页面设计

    ⑤ 实现功能

    ⑥ 将功能植入到页面中

    ⑦ 确认是否能正常运行

    ⑧ 完成

    关于上述各流程,我们将在实际开发过程中详细了解。2.4 明确要开发什么应用

    这里,我们来了解一下这个应用的需求以及必备功能和页面。

    2.4.1 留言板应用的需求

    首先,我们来确定留言板应用是个什么样的应用,需要实现些什么(即需

    求)。

    如果不事先明确需求或规格,很容易在编码过程中遇到“原本想做什么来

    着”“这个功能有必要做吗”之类的问题,导致项目一团乱。因此我们需要先确定

    这个留言板应用的需求,其具体内容如下。

    ① 在 Web 浏览器上显示一个包含“提交留言”表单的页面

    ② 可以在提交留言表单中输入名字和留言正文

    ③ 通过提交留言表单发送的名字和留言内容会被保存

    ④ 已保存的名字、留言、提交日期会显示在页面中

    ⑤ 整个应用由一个页面构成,页面上部为提交留言表单,下部显示已提交的内

    容

    ⑥ 提交的内容按新旧顺序由上到下排列

    ⑦ 可经由网络(互联网)使用本系统

    ⑧ 可同时在多台计算机上显示已提交的内容

    2.4.2 明确必备的功能

    确定好该应用的需求后,我们来思考一下该用哪些功能来满足这些需求。这次我们要开发的是一个 Web 应用,并且导入了专门开发 Web 应用的框架,因此能够轻松实现需求①在 Web 浏览器上显示、⑦经由网络使用以及⑧同时在多台

    计算机上显示。

    从该应用的需求来看,我们需要的功能如下表所示。

    功能 说明 需求编

    号

    提交留言

    功能 显示可输入名字和留言的表单,保存该表单发送的数据 ①、②、③

    留言显示

    功能

    取出提交留言功能保存的数据(优先提交日期较新的数据)并

    显示在页面上 ④、⑥

    Web 应用 在 Web 浏览器上显示,并且可让多台计算机同时经由网络使

    用该应用

    ①、⑦、⑧

    需求⑤是与页面相关的问题,我们在下一小节学习页面的时候再处理。这里,我们再确认一遍已明确的功能,看看是否能满足需求。

    2.4.3 明确必备的页面

    接下来我们根据应用的功能分析所需的页面,结果如下。

    功能 必备的页面 说明

    提交留言功能 可以输入名字和留言的表单 可供输入名字与留言的栏、提交按钮

    留言显示功能 显示有名字和留言的列表 在页面上列表显示已提交的名字和留言

    需求中提到整个应用由一个页面构成(需求⑤),所以我们要将这两个页面元素糅合到同一个页面中。于是,必备的页面就成了下面这样。

    必备的页面 页面元素

    提交和显示留言的页面 可以输入名字和留言的表单、显示有名字和留言的列表

    至此,我们明确了必备的页面。接下来可以开始设计页面了。2.5 页面设计

    需要的功能和页面都已经敲定,接下来,我们就动手设计页面吧。

    至于为什么先实现页面而非功能,是因为当页面完成后,我们可以更好地把握

    成品应用的整体印象。在把功能植入系统之前,即页面设计阶段,我们需要先写好

    HTML 文件和 CSS 文件。

    2.5.1 确定成品页面的形式

    在开始编写 HTML 代码之前,还需先按捺住自己跃跃欲试的心情,把我们希望

    呈现的页面明确下来。所以,现在要做的就是把必备页面转化成图。这一步称为页

    面设计。

    建议各位先在纸上画出页面的草图。如果希望后期修改起来方便,或者希望页

    面草图干净漂亮,还可以考虑用绘图软件或页面设计方面的专业软件来画。

    这次我们没有使用工具,而是直接画了一张页面草图(图 2.2)。图 2.2 留言板应用的页面草图

    按照需求,上面是表单,下面显示提交的评论内容。另外,这张草图还为各个

    显示元素(表单和文章)添加了注释。这样一张草图不但能在植入功能时为我们提

    供参考,还能随时提醒我们仍缺少哪些功能,这对开发来说意义重大。

    2.5.2 编写 HTML 和 CSS

    下面我们开始编写 HTML 文件和 CSS 文件。为了查看其在 Web 浏览器中的效

    果,我们将在本地环境(主 OS)中进行编写。编写完成的文件可以通过 scp 命令

    发送到服务器,以便后续使用。

    首先我们来参考草图编写 HTML 文件。现阶段不必太在意页面布局,这些外观

    上的东西都可以留在编写 CSS 文件的时候进行调整。

    LIST 2.7 是我们编写的 HTML 文件的源码。LIST 2.7 index.html

    

    

    

    

     留言板<title><head><br/><br/>     <body><br/><br/>     <h1> 留言板<h1><br/><br/>     <form action=post method=post><br/><br/>     <p> 请留言<p><br/><br/>     <table><tr><br/><br/>     <th> 名字<th><td><br/><br/>     <input type=text size=20 name=name><td><tr><tr><br/><br/>     <th> 留言<th><td><br/><br/>     <textarea rows=5 cols=40 name=comment><textarea><td><tr><table><br/><br/>     <p><button type=submit> 提交<button><p><form><br/><br/>     <div><br/><br/>     <h2> 留言记录<h2><br/><br/>     <h3> 游客 的留言(20141031 10:00:00):<h3><br/><br/>     <p><br/><br/>     留言内容<br/><br/>     留言内容<p><br/><br/>     <h3> 游客 的留言(20141031 09:00:00):<h3><br/><br/>     <p><br/><br/>     留言内容<br/><br/>     留言内容<p><div><body><html>用 Web 浏览器打开这个 HTML 文件,结果如图 2.3 所示。<br/><br/>     图 2.3 只有 HTML 文件的页面<br/><br/>     这样,HTML 文件就写好了,接下来开始写 CSS 文件。此时需要调整字体大<br/><br/>     小、颜色、显示位置等外观(风格)。<br/><br/>     LIST 2.8 是写好的 CSS 文件。<br/><br/>     LIST 2.8 main.css<br/><br/>     body {<br/><br/>     margin: 0;<br/><br/>     padding: 0; color: 000E41;<br/><br/>     background-color: 004080;<br/><br/>     }<br/><br/>     h1 {<br/><br/>     padding: 0 1em;<br/><br/>     color: FFFFFF;<br/><br/>     }<br/><br/>     form {<br/><br/>     padding: 0.5em 2em;<br/><br/>     background-color: 78B8F8;<br/><br/>     }<br/><br/>     .main {<br/><br/>     padding: 0;<br/><br/>     }<br/><br/>     .entries-area {<br/><br/>     padding: 0.5em 2em;<br/><br/>     background-color: FFFFFF;<br/><br/>     }<br/><br/>     .entries-area p {<br/><br/>     padding: 0.5em 1em;<br/><br/>     background-color: DBDBFF;<br/><br/>     }<br/><br/>     为了让这个样式表生效,我们需要在 HTML 文件中添加 link 标签读取 CSS,并在相应位置指定 class。修改后的 HTML 文件如 LIST 2.9 所示。<br/><br/>     LIST 2.9 index.html<br/><br/>     <!DOCTYPE html><br/><br/>     <html lang=zh><br/><br/>     <head><br/><br/>     <meta charset=utf-8><br/><br/>     <title> 留言板<title><br/><br/>     <link rel=stylesheet href=main.css type=textcss> <!-- 添加link 标签 --><head> <body><br/><br/>     <h1> 留言板<h1><br/><br/>     <form action=post method=post><br/><br/>     <p> 请留言<p><br/><br/>     <table><tr><br/><br/>     <th> 名字<th><td><br/><br/>     <input type=text size=20 name=name><td><tr><tr><br/><br/>     <th> 留言<th><td><br/><br/>     <textarea rows=5 cols=40 name=comment><textarea><td><tr><table><br/><br/>     <p><button type=submit> 提交<button><p><form><br/><br/>     <div class=entries-area> <!-- 在div 标签中添加class 属性 --><br/><br/>     <h2> 留言记录<h2><br/><br/>     <h3> 游客 的留言(20141031 10:00:00):<h3><br/><br/>     <p><br/><br/>     留言内容<br/><br/>     留言内容<p><br/><br/>     <h3> 游客 的留言(20141031 09:00:00):<h3><br/><br/>     <p><br/><br/>     留言内容<br/><br/>     留言内容<p><div><body><html>我们用 Web 浏览器打开套用 CSS 后的 HTML 文件,如图 2.4 所示。<br/><br/>     图 2.4 套用 CSS 后的页面<br/><br/>     这样我们就写好了显示页面用的 HTML 文件和 CSS 文件。现在用 scp 命令将<br/><br/>     已写好的文件发送到 VirtualBox 上的 Ubuntu 环境下。发送文件的命令如 LIST<br/><br/>     2.10 所示。<br/><br/>     LIST 2.10 用 scp 命令发送文件<br/><br/>     scp -P 2222 index.html main.css bpbook@127.0.0.1:<br/><br/>     NOTESSH 连接的设置等问题请参考附录 B。<br/><br/>     下一步我们要实现功能,并将其植入页面中。2.6 实现功能<br/><br/>     终于到了编写 Python 程序的阶段。我们准备让服务器端的程序来实现这个应<br/><br/>     用的必备功能。这里将优先实现比较重要的功能,或者能提高其他部分实现速度的<br/><br/>     功能。<br/><br/>     保存和读取用户提交的数据是这个应用的核心部分,所以我们先从它下手。<br/><br/>     2.6.1 保存留言数据<br/><br/>     提交功能不但要能保存表单传来的名字和留言,还得能将提交日期及时间存储<br/><br/>     下来,供显示时使用。<br/><br/>     这里我们用 Python 的标准模块 shelve 来存储数据。shelve 能够像<br/><br/>     Python 字典对象一样操作数据,将对象持久化。也就是说,shelve 会将提交的数<br/><br/>     据转换成字典对象,以列表形式保存多个字典,然后将这些字典保存在 shelve<br/><br/>     中。<br/><br/>     下面来编写留言板的脚本文件。guestbook.py 实现了负责保存数据的<br/><br/>     save_data 函数,具体代码如 LIST 2.11 所示。<br/><br/>     LIST 2.11 guestbook.py<br/><br/>     coding: utf-8<br/><br/>     import shelve<br/><br/>     DATA_FILE = 'guestbook.dat'<br/><br/>     def save_data(name, comment, create_at):<br/><br/>     保存提交的数据<br/><br/>     通过shelve 模块打开数据库文件<br/><br/>     database = shelve.open(DATA_FILE)<br/><br/>     如果数据库中没有greeting_list,就新建一个表<br/><br/>     if 'greeting_list' not in database:<br/><br/>     greeting_list = [] else:<br/><br/>     从数据库获取数据<br/><br/>     greeting_list = database['greeting_list']<br/><br/>     将提交的数据添加到表头<br/><br/>     greeting_list.insert(0, {<br/><br/>     'name': name,'comment': comment,'create_at': create_at,})<br/><br/>     更新数据库<br/><br/>     database['greeting_list'] = greeting_list<br/><br/>     关闭数据库文件<br/><br/>     database.close<br/><br/>     然后再来看看 save_data 函数的运行情况。我们通过终端在 guestbook.py<br/><br/>     文件所在的目录下启动 Python shell,然后像 LIST 2.12 这样通过 Python<br/><br/>     shell 加载并执行 guestbook 模块的 save_data 函数。<br/><br/>     LIST 2.12 save_data 函数的运行测试<br/><br/>     ls 确认guestbook.py 位于当前目录下<br/><br/>     guestbook.py<br/><br/>     python 启动Python shell<br/><br/>     >>> import datetime<br/><br/>     >>> from guestbook import save_data<br/><br/>     >>> save_data('test', 'test comment',... datetime.datetime(2014, 10, 31, 10, 0, 0))<br/><br/>     >>>这里我们将 datetime 模块的日期时间对象传递给传值参数 create_at,以<br/><br/>     此来保存提交的日期和时间。在这个阶段,我们只能看出它的运行是否报错,至于<br/><br/>     数据是不是真的被保存下来了,还要等取出数据的功能实现之后才能知道。<br/><br/>     2.6.2 获取已保存的留言列表<br/><br/>     实际上,我们在保存数据的时候就从 shelve 模块中取出过数据,现在只把这<br/><br/>     部分代码单独拿出来做成函数即可。<br/><br/>     在 guestbook.py 中添加 load_data 函数(LIST 2.13)。<br/><br/>     LIST 2.13 guestbook.py<br/><br/>     def load_data:<br/><br/>     返回已提交的数据<br/><br/>     通过shelve 模块打开数据库文件<br/><br/>     database = shelve.open(DATA_FILE)<br/><br/>     返回greeting_list。如果没有数据则返回空表<br/><br/>     greeting_list = database.get('greeting_list', [])<br/><br/>     database.close<br/><br/>     return greeting_list<br/><br/>     这里同样通过 Python shell 查看其运行情况。启动 Python shell,加载<br/><br/>     函数并运行(LIST 2.14)。<br/><br/>     LIST 2.14 load_data 函数的运行测试>>> from guestbook import load_data<br/><br/>     >>> load_data<br/><br/>     [{'comment': 'test comment', 'name': 'test', 'create_at': datetime.datetime (2014, 10,31, 10, 0)}]<br/><br/>     如果运行正常,那就表示我们能获取 save_data 函数保存下来的数据。<br/><br/>     2.6.3 用模板引擎显示页面<br/><br/>     从文件中取出数据之后,为了将其显示到页面上,我们要使用模板引擎。模板<br/><br/>     引擎可以将模板(程序的雏形)与要植入模板内的数据合并输出。Flask 标准支持<br/><br/>     Jinja2 模板引擎。<br/><br/>     接下来创建 templates 目录,然后将前面已经写好的 HTML 文件放到该目录<br/><br/>     下(LIST 2.15)。这样一来,我们就可以以它为模板生成 HTML 了。<br/><br/>     LIST 2.15 放置模板<br/><br/>     mkdir templates<br/><br/>     mv index.html templates<br/><br/>     下面从程序端入手,用这个 HTML 文件(模板)来完成页面的显示。先添加代<br/><br/>     码,让 guestbook.py 调用 Flask,然后再添加用来显示首页的函数以及用来启<br/><br/>     动 Web 服务器的代码(LIST 2.16)。<br/><br/>     LIST 2.16 guestbook.py<br/><br/>     coding: utf-8<br/><br/>     import shelvefrom flask import Flask, request, render_template, redirect, escape, Markup<br/><br/>     application = Flask(__name__)<br/><br/>     DATA_FILE = 'guestbook.dat'<br/><br/>     def save_data(name, comment, create_at):<br/><br/>     保存提交的数据<br/><br/>     省略<br/><br/>     def load_data:<br/><br/>     返回已提交的数据<br/><br/>     省略<br/><br/>     @application.route('')<br/><br/>     def index:<br/><br/>     首页<br/><br/>     使用模板显示页面<br/><br/>     return render_template('index.html')<br/><br/>     if __name__ == '__main__':<br/><br/>     在IP 地址127.0.0.1 的8000 端口运行应用程序<br/><br/>     application.run('127.0.0.1', 8000, debug=True)<br/><br/>     我们将 Flask 类的实例赋给变量 application,传值参数指定为 __name__<br/><br/>     变量的模块名。方法 route 是一个装饰器,负责注册针对特定 URL 执行的函数。<br/><br/>     这里我们让主页的 URL 对应执行 index 函数。render_template 函数负责将指<br/><br/>     定文件用作模板,再通过模板引擎进行输出。<br/><br/>     Flask 类的 run 方法用于启动 Web 服务器并执行应用程序,传值参数用来指定要绑定的 IP 地址及端口。另外,将 debug 选项指定为 True 时,一旦应用程<br/><br/>     序出错,Web 浏览器端就会启动可用的调试程序。<br/><br/>     接下来用 python 命令运行 guestbook.py(LIST 2.17)。<br/><br/>     LIST 2.17 运行已开发完毕的 Web 应用<br/><br/>     python guestbook.py<br/><br/>     Running on http:127.0.0.1:8000<br/><br/>     Restarting with reloader<br/><br/>     运行 guestbook.py 之后,在该环境的(这里是 VirtualBox 上的<br/><br/>     Ubuntu)127.0.0.1 地址的 8000 端口等待请求的应用服务器(Web 服务器)就<br/><br/>     会启动。我们可以在终端同时按下 Ctrl 键和 C 键,关闭这个服务器。<br/><br/>     现在我们需要设置好 8000 端口的端口转发,然后在 Web 浏览器中打开<br/><br/>     http:127.0.0.1:8000 。如何,看到页面没有?<br/><br/>     我们会发现 CSS 文件并没有生效,所以需要重新调整一下 CSS 文件的位置,让它能够被读取。Flask 会公开 static 目录下存放的静态文件。接下来我们创建<br/><br/>     一个 static 目录,把 main.css 文件放进去(LIST 2.18)。<br/><br/>     LIST 2.18 放置静态文件<br/><br/>     mkdir static<br/><br/>     mv main.css static另外,还要将 templatesindex.html 中的 CSS 文件引用位置改为<br/><br/>     staticmain.css(LIST 2.19、LIST 2.20)。<br/><br/>     LIST 2.19 templatesindex.html(更改前)<br/><br/>     <link rel=stylesheet href=main.css type=textcss><br/><br/>     LIST 2.20 templatesindex.html(更改后)<br/><br/>     <link rel=stylesheet href=staticmain.css type=textcss><br/><br/>     现在再用 Web 浏览器打开该页面,就会发现 CSS 文件这时已经生效了。<br/><br/>     接下来,我们把从数据库中取出的内容显示在页面上。修改 guestbook.py 文<br/><br/>     件,让 index 函数调用 load_data 函数,同时使模板能够使用 load_data 函<br/><br/>     数取出来的数据(LIST 2.21)。<br/><br/>     LIST 2.21 guestbook.py<br/><br/>     @application.route('')def index:<br/><br/>     首页<br/><br/>     使用模板显示页面<br/><br/>     读取已提交的数据<br/><br/>     greeting_list = load_data<br/><br/>     return render_template('index.html', greeting_list=greeting_list)<br/><br/>     render_template 函数可以将关键字传值参数所指定的值用作模板变量。比如<br/><br/>     本例就使用了名为 greeting_list 的模板变量。<br/><br/>     此外,我们还要修改模板 templatesindex.html,使其能够使用模板变量进<br/><br/>     行显示。现在对 HTML 中的显示留言部分作如下修改(LIST 2.22)。<br/><br/>     LIST 2.22 templatesindex.html<br/><br/>     <div class=entries-area><br/><br/>     <h2> 留言记录<h2><br/><br/>     {% for greeting in greeting_list %}<br/><br/>     <h3>{{ greeting.name }}<br/><br/>     的留言({{ greeting.create_at }}):<h3><br/><br/>     <p>{{ greeting.comment }}<p><br/><br/>     {% endfor %}<div>模板内可以使用一种特殊的描述方式,即模板语言。Jinja2 的模板可以通过<br/><br/>     {%…%} 的形式使用 if 或 for 等控制语句。植入有模板变量的部分用 {{…}} 的<br/><br/>     形式描述。在上述模板中,程序会从 greeting_list 中逐一取值并赋给模板变量<br/><br/>     greeting,然后使用从 for 到 endfor 之间的模板变量进行循环输出。<br/><br/>     这样一来,应用就能将 save_data 函数保存的数据显示在页面上了。<br/><br/>     2.6.4 准备评论接收方的 URL<br/><br/>     下一步我们用 save_data 函数保存表单提交来的数据。由于模板文件中表单<br/><br/>     的 action 值为 post,所以我们就做出这个 URL。<br/><br/>     这里,我们将 post 函数添加到 guestbook.py 的 if __main__ ... 前面<br/><br/>     (LIST 2.23)。<br/><br/>     LIST 2.23 guestbook.py<br/><br/>     @application.route('post', methods=['POST'])<br/><br/>     def post:<br/><br/>     用于提交评论的URL<br/><br/>     获取已提交的数据<br/><br/>     name = request.form.get('name') 名字<br/><br/>     comment = request.form.get('comment') 留言<br/><br/>     create_at = datetime.now 投稿时间(当前时间)<br/><br/>     保存数据<br/><br/>     save_data(name, comment, create_at)<br/><br/>     保存后重定向到首页<br/><br/>     return redirect('')<br/><br/>     在 Flask 中,可以用 request.form 引用表单发来的数据。此外,由于保存数据后需要重新显示首页,所以我们要返回 redirect 函数的结果并进行重定向。<br/><br/>     post 函数使用了 datetime 模块,所以需要在文件开头添加如 LIST 2.24<br/><br/>     所示代码,以导入该模块。<br/><br/>     LIST 2.24 导入 datetime 模块(guestbook.py)<br/><br/>     coding: utf-8<br/><br/>     import shelve<br/><br/>     from datetime import datetime 添加此行<br/><br/>     至此,保存数据的功能也实现了。应用的运行部分基本完工。<br/><br/>     2.6.5 调整模板的输出<br/><br/>     程序运行所需的功能现在已经基本上都实现了,但这里至少还有两点需要注<br/><br/>     意。<br/><br/>     表单提交多行留言时,无法正常显示留言<br/><br/>     显示的时间精确到了毫秒<br/><br/>     要想解决这两个问题需创建一个模板过滤器。模板过滤器会对模板变量的值加<br/><br/>     以转换并输出。接下来,我们在 guestbook.py 的 if __main__ ... 前添加如<br/><br/>     LIST 2.25 所示代码,将模板过滤器导入模板。<br/><br/>     LIST 2.25 guestbook.py<br/><br/>     @application.template_filter('nl2br')<br/><br/>     def nl2br_filter(s): 将换行符置换为br 标签的模板过滤器<br/><br/>     return escape(s).replace('\n', Markup('<br/><br/>     '))<br/><br/>     @application.template_filter('datetime_fmt')<br/><br/>     def datetime_fmt_filter(dt):<br/><br/>     使datetime 对象更容易分辨的模板过滤器<br/><br/>     return dt.strftime('%Y%m%d %H:%M:%S')<br/><br/>     Flask 类的 template_filter 方法是一个装饰器,它负责将函数注册为指定<br/><br/>     名称的模板过滤器。程序运行时,指定了模板过滤器的模板变量会被作为传值参数<br/><br/>     传递给相应函数,而函数的返回值则为最后输出的值。在上述源码中,我们注册了<br/><br/>     nl2br 和 datetime_fmt 两个模板过滤器。<br/><br/>     接下来,我们修改一下 templatesindex.html 文件,让模板能够使用这两<br/><br/>     个模板过滤器(LIST 2.26)。<br/><br/>     LIST 2.26 templatesindex.html<br/><br/>     <div class=entries-area><br/><br/>     <h2> 留言记录<h2><br/><br/>     {% for greeting in greeting_list %}<br/><br/>     <h3>{{ greeting.name }}<br/><br/>     的留言({{ greeting.create_at|datetime_fmt }}):<h3><br/><br/>     <p>{{ greeting.comment|nl2br }}<p><br/><br/>     {% endfor %}<div>在模板内指定模板过滤器的方法很简单,只需要在模板变量的名称后面加管道<br/><br/>     符“| ”再加模板过滤器名即可。在本次的模板中,我们给 greeting.create_at<br/><br/>     指定了 datetime_fmt 过滤器,给 greeting.comment 指定了 nl2br 过滤器。<br/><br/>     至此,服务器端的功能、功能与页面的对接已经全部完工。从 Web 浏览器看到<br/><br/>     的效果如图 2.5 所示。显示留言部分 显示了我们已提交的内容。<br/><br/>     留言记录部分的 tokibito 为本章撰写者冈野真也先生的 Twitter 用户名。——编者注<br/><br/>     图 2.5 植入功能后的页面<br/><br/>     整个应用的开发过程到这里就结束了,接下来就是确认该应用的运行是否正<br/><br/>     常,以及看一看成品是否能满足我们当初定下的需求。<br/><br/>     2<br/><br/>     22.7 查看运行情况<br/><br/>     虽然程序的编写已经结束,但我们还需要确认应用程序能不能按预想的样子运<br/><br/>     行。下面就来逐条确认刚刚开发完成的应用是否满足需求,以及运行上是否存在问<br/><br/>     题。到了这一步,可能会有人觉得“开发的时候就已经逐条确认过了,肯定不会有<br/><br/>     问题的”。这种心情可以理解。但要知道,我们在编码后期阶段所作的修改可能会<br/><br/>     导致之前的功能出现 Bug,而且也难保开发过程中不会遗漏某些需求。因此要想制<br/><br/>     作一个品质上乘的应用程序,这项确认工作必不可少。<br/><br/>     好了,现在让我们回顾一下这个留言板应用的需求。<br/><br/>     ① 在 Web 浏览器上显示一个包含“提交留言”表单的页面<br/><br/>     ② 可以在提交留言表单中输入名字和留言正文<br/><br/>     ③ 通过提交留言表单发送的名字和留言内容会被保存<br/><br/>     ④ 已保存的名字、留言、提交日期会显示在页面中<br/><br/>     ⑤ 整个应用由一个页面构成,页面上部为提交留言表单,下部显示已提交的内<br/><br/>     容<br/><br/>     ⑥ 提交的内容按新旧顺序由上到下排列<br/><br/>     ⑦ 可经由网络(互联网)使用本系统<br/><br/>     ⑧ 可同时在多台计算机上显示已提交的内容<br/><br/>     现在运行开发服务器,查看成品是否能满足这 8 项需求。<br/><br/>     只要通过 Web 浏览器访问 http:127.0.0.1:8000 即可查看需求①是否<br/><br/>     得到了满足。与此同时,由于虚拟机和本地计算机之间经由网络连接,所以⑦和⑧<br/><br/>     也没有问题。至于②,只要我们能在页面中的表单里填写名字和留言内容,那就是<br/><br/>     过关了。接下来输入内容并点击提交按钮,随后页面被刷新,刚刚提交的内容显示在了页面上。于是⑤也搞定了。然后重启开发服务器,再次通过 Web 浏览器读取页<br/><br/>     面,如果之前提交的内容能够正常显示,就表示③和④也 OK。最后我们再进行一次<br/><br/>     输入和提交,只要后来提交的内容显示在最上方,那么需求⑥也就满足了。<br/><br/>     另外,这次我们开发的应用没有对使用者输入的字符串做任何限制,而且输入<br/><br/>     的内容会直接以植入 HTML 的形式显示出来。因此,接下来需要确认是否存在跨站<br/><br/>     脚本攻击漏洞。<br/><br/>     NOTE<br/><br/>     跨站脚本攻击(Cross Site Scripting,XSS )是一种常见的漏洞,用<br/><br/>     户能在某些以植入 HTML 的形式显示输入内容的应用中,故意植入一些攻击型<br/><br/>     的脚本(比如 HTML 标签或 JavaScript 等)。<br/><br/>     XSS 漏洞可被用在会话劫持、钓鱼等恶意行为上。<br/><br/>     Cross Site Scripting 的缩写为 XSS,这是为了和层叠样式表(Cascading Style Sheet,CSS)<br/><br/>     有所区分。——编者注<br/><br/>     要验证应用中是否含有 XSS 漏洞,只需要像 LIST 2.27 这样,在留言输入栏<br/><br/>     中键入带有 JavaScript 代码的 HTML 标签,然后点击提交即可。<br/><br/>     LIST 2.27 验证跨站脚本攻击时需要输入的内容<br/><br/>     <script>alert('NG')<script><br/><br/>     显示提交内容的区域内是否显示出了我们输入的字符串呢?如果该应用含有<br/><br/>     XSS 漏洞,那么 NG 字样将显示在浏览器的警告中。<br/><br/>     我们在本次开发中使用的是 Jinja2 模板引擎,它在翻译字符串时会自动忽略<br/><br/>     3<br/><br/>     3HTML 标签的“< 和 >”符号。因此,我们的应用能够成功避免 XSS 漏洞。<br/><br/>     建议各位在最后查看运行情况时也检测一下其他可能造成安全问题的漏洞。<br/><br/>     NOTE<br/><br/>     与 XSS 同样恶名昭彰的漏洞还有跨站请求伪造(Cross Site Request<br/><br/>     Forgery,CSRF)。用户通过与目标应用程序无关的外部输入表单(这些输入<br/><br/>     表单通常用于攻击)发送数据,一旦目标应用程序处理了这些数据,就会引发<br/><br/>     使用者意料之外的操作。<br/><br/>     CSRF 漏洞可被用来触发使用者意料之外的操作(比如在线购买商品、泄露<br/><br/>     个人信息等)。<br/><br/>     本章中开发的应用并没有对 CSRF 进行防范。由于 XSS 和 CSRF 这两种<br/><br/>     攻击手法可以相互组合出新的攻击手法,所以建议各位务必做好防范工作。<br/><br/>     如果上述过程全部顺利通过,我们的应用开发就可以宣告完工了。各位辛苦<br/><br/>     了。<br/><br/>     最终的文件结构如下表所示。<br/><br/>     文件路径 说明<br/><br/>     guestbook.py 服务器程序<br/><br/>     guestbook.dat 提交数据文件<br/><br/>     staticmain.css CSS 文件<br/><br/>     templatesindex.html 输出 HTML 的模板,用于显示提交 留言列表页面<br/><br/>     Web 应用开发的第一步是确定自己要开发什么东西。要是对自己要做的东西没<br/><br/>     有概念,开发就不可能进行下去。另外,如果必备的页面和功能不够明确,那么编写代码的过程将是相当痛苦的。要想让开发如行云流水般流畅,那就必须将这些不<br/><br/>     确定的因素统统明确下来,确定一个开发流程。<br/><br/>     在本章中,我们强调了 Web 应用是一个发送动态内容的程序,并且用户可以经<br/><br/>     由 Web 浏览器使用 Web 应用,同时还学习了 Web 浏览器 服务器 应用之间<br/><br/>     的基本通信机制。另外,我们还以留言板应用为例,从确定需求到最终完成,边学<br/><br/>     边练地一起了解了整个应用开发流程。本章学习的开发流程适用于多种应用的开<br/><br/>     发。<br/><br/>     第 3 章 Python 项目的结构与包的创<br/><br/>     建<br/><br/>     在 Python 圈子里,有许多开发者会无偿公开自己开发的程序库。为了让使用<br/><br/>     者能够通过 pip 命令安装这些库,我们在发布时需要将其创建成一种特殊的文件,这种文件就是程序包。在使用 Python 语言进行开发的过程中,Python 自带的库<br/><br/>     往往不能满足我们,因此我们还需要用到这些程序包。<br/><br/>     本章将介绍程序包的制作流程。首先,我们要了解一下 Python 项目开发环境<br/><br/>     的相关工具。然后,我们来了解一下该环境下的相对易于掌握的 Python 项目目录<br/><br/>     结构以及文件结构,同时对第 2 章中开发的留言板应用进行整理,封装成包。最后<br/><br/>     还将学习如何将我们开发的项目发布在 PyPI 上,与全世界人分享。3.1 Python 项目<br/><br/>     用 Python 开发的应用程序达到一定规模后,必然会出现多个模块(.py)或<br/><br/>     程序包目录。同时除源码以外,说明性质的文本文件、管理相关程序库的元信息等<br/><br/>     都会越来越多。这些为同一个目的服务的文件、目录以及元信息,就是我们所说的<br/><br/>     项目。<br/><br/>     实际上,Python 项目的内部结构是因项目而异的。这里,一个完整的结构需<br/><br/>     要满足以下条件。<br/><br/>     拥有一个在版本管理之下的源码目录<br/><br/>     程序信息在 setup.py 中定义<br/><br/>     在一个 virtualenv 环境中运行<br/><br/>     对于 Python 开发上的一些约定俗成的工具来说,满足上述条件的结构更便于<br/><br/>     处理。我们在第 1 章中介绍的 pip 和 virtualenv 都属于这类工具。<br/><br/>     这些 Python 中的约定俗成的工具也随着时代逐渐变化着。近年来 PEP 标准<br/><br/>     正被逐渐推行。为了规范这些约定俗成的东西,2013 年成立了 PyPA(Python<br/><br/>     Packaging Authority)工作组。PyPA 负责 Python 封装方面相关工具的维护,以及 PEP 标准化等工作。许多老牌的封装相关工具都被移交给 PyPA 管理,包括<br/><br/>     本书中使用的 pip、virtualenv、wheel 现在也都由 PyPA 提供。<br/><br/>     如今,许多 Python 项目的结构都以 PyPA 提供的工具为参照,选用了适合这<br/><br/>     些工具的文件、目录结构。<br/><br/>     如果项目的结构符合标准,那么它与工具之间就会有很强的亲和力,而且便于<br/><br/>     今后自己或其他开发者进一步开发。另外,本章中介绍的结构与流程不但适用于个<br/><br/>     人的开发环境,同样也适用于团队的开发环境。<br/><br/>     NOTE在 PyPA 的封装文档中,将以发布为目的的一个整体单位称为一个项目<br/><br/>     (Project)。<br/><br/>     https:packaging.python.orgenlatestglossary.htmlterm-<br/><br/>     project3.2 环境与工具<br/><br/>     本节,我们将对 Python 项目开发的必备工具进行了解。此外,还将学习项目<br/><br/>     的目录结构、必备程序包的管理方法以及安装方法。<br/><br/>     3.2.1 用 virtualenv 搭建独立环境<br/><br/>     如果大量项目全都混杂在一个环境下,程序很可能会在预想不到的地方停止运<br/><br/>     行,而且不利于我们把握当前环境的具体状态。所以为了防止出现这些恼人的情<br/><br/>     况,我们建议各位搭建简单的独立环境。<br/><br/>     使用 virtualenv 可以给每个项目搭建一个独立的 Python 环境。<br/><br/>     独立环境有以下优点。<br/><br/>     添加程序包以及变更版本时,能将影响控制在当前环境内<br/><br/>     便于判断已安装的程序包是否可以删除<br/><br/>     不再需要该环境时,可以直接删除整个环境<br/><br/>     一旦出了问题,那么问题必然出在该环境的项目上,这就有助于我们找出<br/><br/>     问题所在<br/><br/>     virtualenv<br/><br/>     NOTE<br/><br/>     当前介绍的版本为 virtualenv 1.11.6。<br/><br/>     用 pip 安装外部程序库时,该库会被安装到 Python 的安装目录下。比如<br/><br/>     Python 是安装在了 usrlocal 目录下,那么该外部程序库就会被安装在<br/><br/>     usrlocallibpython2.7site-packages 目录下,这就是库的默认安装路<br/><br/>     径。但这样一来,不同目的的程序库就全都安装到了同一目录下,不但容易导致版本冲突,而且很难分辨出哪些程序库已经没用了。<br/><br/>     另外,在 usrlocal 下安装东西时,需要我们提供该目录的写入权限。我<br/><br/>     们对自己的计算机中的 OS 目录具有写入权限,但是不一定对其他计算机的 OS 目<br/><br/>     录也拥有写入权限。就算有,乱用权限也很容易导致意外事故,因此应尽量避免乱<br/><br/>     用权限。<br/><br/>     其实,这些问题都可以用 virtualenv 解决。<br/><br/>     virtualenv 的主要特征体现在下列功能上。<br/><br/>     在 virtualenv 环境中可自由安装 Python,不需要提供 OS 管理员权限<br/><br/>     在 virtualenv 环境下,可根据目的不同来安装程序库,这样一来包的安<br/><br/>     装目的和依存关系就会更加明确<br/><br/>     仍然使用 Python 主体,且虚拟环境仅由一小部分备份文件构成,因此环<br/><br/>     境搭建速度快,占用硬盘空间小<br/><br/>     无视 Python 主体的 site-packages,而且能分离主体上已安装完毕的<br/><br/>     程序包<br/><br/>     可以用 activatedeactivate 命令随时启动 关闭 virtualenv 环境<br/><br/>     virtualenv 命令可以将任意目录设置为“virtualenv 环境(Python 虚拟<br/><br/>     环境)”。激活 virtualenv 环境之后,Python 解释器会将该目录识别为默认安<br/><br/>     装目录。所以,如果我们此时用 pip 命令安装程序库,那么这个程序库将被安装到<br/><br/>     virtualenv 环境中。<br/><br/>     下面我们来了解一下 virtualenv 的一般使用方法以及一些常用选项。其他详<br/><br/>     细知识请参考以下网站。<br/><br/>     Reference Guide - virtualenv 1.11.6 documentation<br/><br/>     https:virtualenv.pypa.ioenlatest<br/><br/>     专栏 Python 标配的用户站点目录功能与 virtualenv 的差异<br/><br/>     用户站点目录功能由PEP 370 提出,随后被 Python 采纳并从 Python<br/><br/>     2.6 版本开始提供。这个功能让 Python 解释器能够识别安装在用户目录<br/><br/>     HOME.local 下的程序库。与此同时,pip 也纳入了这一机制,允许用户使<br/><br/>     用 --user 选项将程序库安装到 HOME.local 目录下。<br/><br/>     有了这个功能之后,用户不必使用 virtualenv 就能自由地安装程序库。<br/><br/>     不过,用户站点目录功能无法像 virtualenv 一样搭建多个环境,自然也就不<br/><br/>     能在多个环境中切换。<br/><br/>     https:www.python.orgdevpepspep-0370<br/><br/>     virtualenv 的使用方法<br/><br/>     接下来我们看一看 virtualenv 的安装、virtualenv 环境的搭建以及启动<br/><br/>     (LIST 3.1、LIST3.2)。<br/><br/>     LIST 3.1 安装 virtualenv<br/><br/>     sudo pip install virtualenv<br/><br/>     LIST 3.2 virtualenv 环境的搭建及启动<br/><br/>     cd homebpbookwork<br/><br/>     virtualenv venv<br/><br/>     ls -F<br/><br/>     venv<br/><br/>     source venvbinactivate<br/><br/>     1<br/><br/>     1(venv)<br/><br/>     如上所示,使用某一 virtualenv 环境的 activate 命令后,该<br/><br/>     virtualenv 环境就会被设置为默认的 Python 执行环境。这里我们搭建了名为<br/><br/>     venv 的 virtualenv 环境,因此命令提示符前会出现环境名 (venv) 。<br/><br/>     执行 activate 后,PATH、PROMPT 等数个环境变量会被改写。这样一来,对<br/><br/>     象 virtualenv 环境的 bin 目录将在 PATH 搜索中被优先处理。此时,只有环境<br/><br/>     变量会被修改,文件并不会有任何变动。<br/><br/>     在这个状态下,计算机会优先使用 venvbin 目录下的执行文件来执行各个命<br/><br/>     令。给 virtualenv 环境安装额外的程序库时,我们需要如 LIST 3.3 所示,在<br/><br/>     命令提示符前有“(venv) ”的状态下执行 pip 命令。<br/><br/>     LIST 3.3 给 virtualenv 环境安装程序库<br/><br/>     (venv) pip install requests bottle<br/><br/>     (venv) pip freeze<br/><br/>     bottle==0.12.7<br/><br/>     requests==2.4.3<br/><br/>     如果要使用这个 virtualenv 环境的 Python,则要执行该 virtualenv 环<br/><br/>     境的 python 命令(LIST 3.4)。LIST 3.4 运行 virtualenv 环境的 Python<br/><br/>     (venv) python<br/><br/>     Python 2.7.6 (default, Mar 22 2014, 22:59:56) [GCC 4.8.2] on linux2<br/><br/>     Type help, copyright, credits or license for more information.<br/><br/>     >>> import sys<br/><br/>     >>> sys.executable<br/><br/>     'homebpbookworkvenvbinpython'<br/><br/>     >>> import requests<br/><br/>     >>> import bottle<br/><br/>     解除 activate 时,需要还原之前被 activate 更改的环境变量。因此我们<br/><br/>     要结束 shell,或者执行 deactivate 命令(LIST 3.5)。<br/><br/>     LIST 3.5 通过 deactivate 命令关闭 virtualenv 环境<br/><br/>     (venv) deactivate<br/><br/>     python -c import sys; print sys.executable<br/><br/>     usrlocalbinpython<br/><br/>     virtualenv 环境的数量没有上限。这里我们再来搭建一个名为 another-<br/><br/>     venv 的 virtualenv 环境(LIST 3.6)。<br/><br/>     LIST 3.6 搭建另一个 virtualenv 环境 virtualenv another-venv<br/><br/>     ls -F<br/><br/>     another-venv venv<br/><br/>     使用 another-venv 环境的 Python 时,我们无法 import 其他<br/><br/>     virtualenv 环境安装的库。<br/><br/>     LIST 3.7 运行另一个 virtualenv 环境的 Python<br/><br/>     source another-venvbinactivate<br/><br/>     (another-venv) python<br/><br/>     Python 2.7.6 (default, Mar 22 2014, 22:59:56) [GCC 4.8.2] on linux2<br/><br/>     Type help, copyright, credits or license for more information.<br/><br/>     >>> import sys<br/><br/>     >>> sys.executable<br/><br/>     'homebpbookworkanother-venvbinpython'<br/><br/>     >>> import requests<br/><br/>     Traceback (most recent call last):<br/><br/>     File <stdin>, line 1, in <module><br/><br/>     ImportError: No module named 'requests'<br/><br/>     可见,每一个 virtualenv 环境都是相互独立运行的 Python 环境(LIST<br/><br/>     3.7)。而且每个环境都仅由 Python 的一部分文件构成,所以能够很快搭建完成<br/><br/>     或者删掉,并不会占用太多硬盘空间。专栏 virtualenv 环境的硬盘使用量<br/><br/>     在 Ubuntu 14.04 下,Python 主体的硬盘使用量大约为 100 MB,每个<br/><br/>     virtualenv 环境的硬盘使用量约为 6 MB。不过,如果使用了我们后面即将了<br/><br/>     解的 --always-copy 选项,那么每个 virtualenv 环境将占用约 50 MB。<br/><br/>     不再使用的 virtualenv 环境可以连同其所在目录一起删除(LIST 3.8)。<br/><br/>     LIST 3.8 删除 virtualenv 环境<br/><br/>     (another-venv) deactivate<br/><br/>     rm -R another-venv<br/><br/>     专栏 在不 activate 的状态下执行 virtualenv 环境的命令<br/><br/>     我们执行 activate 命令启动 virtualenv 环境时,环境变量会被更<br/><br/>     新,此后执行命令时会优先使用 venvbin 目录下的文件。实际上,即便是<br/><br/>     在没有执行 activate 命令的状态下,只要我们用完整路径执行了<br/><br/>     venvbin 下的命令,就可以运行 virtualenv 环境中的程序。<br/><br/>     python -c import sys; print sys.executable<br/><br/>     usrlocalbinpython<br/><br/>     venvbinpython -c import sys; print sys.executable<br/><br/>     homebpbookworkvenvbinpython<br/><br/>     venvbinpython<br/><br/>     >>> import requests 可以从venv环境中导入<br/><br/>     venvbinpip install flask 安装到venv环境中...因此,当我们想有计划地执行 venv 环境的程序,或者想启动服务器时,只要用完整路径指定 venv 环境的程序,就可以在不执行 activate 命令的状<br/><br/>     态下完成运行了。<br/><br/>     virtualenv 的选项<br/><br/>     virtualenv 为用户提供了许多可用选项。我们可以通过 virtualenv --<br/><br/>     help 来查看选项列表。现在我们选其中一些比较好用的选项来了解一下。<br/><br/>     -p、--python<br/><br/>     指定virtualenv环境下使用的Python,格式如--<br/><br/>     python=usrlocalbinpython2.7 。<br/><br/>     如果省略该选项,则默认选择执行virtualenv命令的Python。--system-site-packages<br/><br/>     使用当前Python主体上已经安装的程序库。如果省略该选项,则默认忽略<br/><br/>     Python主体上已经安装的程序库。--always-copy<br/><br/>     无论符号链接是否可用,一概不使用符号链接,而是直接复制文件。即便<br/><br/>     是允许使用符号链接的OS,在某些文件系统下仍会出现符号链接不可用的情<br/><br/>     况。此时就可以用到这个选项。--clear删除指定的virtualenv环境中安装的依赖库等,初始化环境。<br/><br/>     -q、-quiet<br/><br/>     执行virtualenv命令时,控制向工作台输出的信息量。<br/><br/>     -v、-verbose<br/><br/>     执行virtualenv命令时,增加向工作台输出的信息量。<br/><br/>     LIST 3.9 virtualenv 的选项示例<br/><br/>     virtualenv -q --system-site-packages -p usrlocalbinpython2.7 venv<br/><br/>     如果我们经常用到某些选项,可以事先将其写入设置文件。这样一来,我们就<br/><br/>     不用每次执行命令时都再写一遍了。<br/><br/>     在 Linux 系统下,设置文件默认使用<br/><br/>     HOME.virtualenvvirtualenv.ini。举个例子,如果要在 virtualenv.ini<br/><br/>     中指定 LIST 3.9 里的选项,我们可以按照 LIST 3.10 进行描述。<br/><br/>     LIST 3.10 virtualenv.ini<br/><br/>     [virtualenv]<br/><br/>     python = usrlocalbinpython2.7<br/><br/>     quiet = true<br/><br/>     system-site-packages = true另外,还可以在环境变量中指定选项。如果我们同时用环境变量和设置文件指<br/><br/>     定了某个选项,那么将以环境变量的指定为准。当然,命令行传值参数的指定优先<br/><br/>     于一切。<br/><br/>     环境变量名是根据选项名自动生成的。将选项名的“-- ”后的字母全改为大<br/><br/>     写,短线改为下划线,然后在开头加上 VIRTUALENV_ ,就是该选项所对应的环境<br/><br/>     变量。请各位在设置环境变量时记住这个规律。<br/><br/>     ● 示例--quiet -> VIRTUALENV_QUIET=true--python -> VIRTUALENV_PYTHON=usrlocalbinpython2.7--system-site-packages -> VIRTUALENV_SYSTEM_SITE_PACKAGES=true<br/><br/>     专栏 --system-site-packages 选项<br/><br/>     virtualenv 环境不会引用 Python 主体上安装的程序包,也就是<br/><br/>     usrlocallibpython2.7sitepackages 目录下的程序包。因此,当我<br/><br/>     们新建了一个 virtualenv 环境时,这个环境处于干净的初始状态,没有安装<br/><br/>     任何多余的包。<br/><br/>     相反地,如果我们想在 virtualenv 环境中使用 Python 主体上安装的<br/><br/>     程序包,那么在新建环境时可以加上 --system-site-packages 选项。<br/><br/>     不过,一旦加上这个选项,我们就相当于同时使用两个环境,因此很难分<br/><br/>     辨出程序包在哪里,以及正在使用的是哪个程序包。这会导致 virtualenv 环境的优势大打折扣。所以,除非迫不得已,建议各位尽量不要使用 --system-<br/><br/>     site-packages 选项。<br/><br/>     3.2.2 用 pip 安装程序包<br/><br/>     NOTE<br/><br/>     我们使用的是 pip 1.5.6。<br/><br/>     给 virtualenv 环境额外安装程序包时,需要用该环境的 pip 命令。<br/><br/>     pip 是用来安装程序包的命令。既可以经由网络进行安装,也可以直接从本地<br/><br/>     的程序包文件进行安装。第三方的程序库发布在 PyPI 上。pip 命令会默认从<br/><br/>     PyPI 上搜索并安装程序包。<br/><br/>     pip 提供了多个子命令。下面便是其子命令列表。<br/><br/>     install 安装程序包(指定包名、包文件名、URL 等)<br/><br/>     uninstall 卸载程序包<br/><br/>     freeze 以 requirements 格式列表输出当前已安装的程序包及其版本<br/><br/>     list 列表显示当前已安装的程序包<br/><br/>     show 列表显示当前已安装程序包的版本信息<br/><br/>     search 按指定关键字在 PyPI 上搜索程序包并显示结果列表<br/><br/>     wheel 根据指定 requirement 构建 wheel 文件<br/><br/>     help 显示帮助<br/><br/>     接下来,我们将对 pip 的选项以及安装、卸载方法进行学习。其他详细内容请<br/><br/>     参考以下网站。<br/><br/>     Reference Guide - pip 1.5.6 documentation<br/><br/>     https:pip.pypa.ioenlatestreferenceindex.html<br/><br/>     User Guide - pip 1.5.6 documentationhttps:pip.pypa.ioenlatestuser_guide.htmlconfiguration<br/><br/>     pip 的选项<br/><br/>     pip 的选项有两种,一种是不依赖于子命令的共通选项,另一种是指定给子命<br/><br/>     令的选项。比如 --quiet 和 --proxy 就是所有命令共通的选项,而 install<br/><br/>     子命令则拥有 --upgrade 等自己独有的选项(LIST 3.11)。<br/><br/>     这两种选项都需要在执行时通过命令行指定。<br/><br/>     LIST 3.11 pip 的选项示例<br/><br/>     pip --quiet --proxy=server:9999 install --upgrade requests<br/><br/>     常用的选项可以事先写在设置文件中。这样可以省去每次都写的麻烦。<br/><br/>     Linux 的默认设置文件为 HOME.pippip.conf。比如我们要在 pip.conf<br/><br/>     中指定 LIST 3.11 pip 的选项示例中的选项,则可以按照 LIST 3.12 进行描<br/><br/>     述。<br/><br/>     LIST 3.12 pip.conf<br/><br/>     [global]<br/><br/>     quiet = true<br/><br/>     proxy = server:9999<br/><br/>     [install]<br/><br/>     upgrade = trueNOTE<br/><br/>     上述内容只是个例子,并非推荐设置。各位请严格按照自己的需要设置各<br/><br/>     个选项。<br/><br/>     另外,还可以在环境变量中指定选项。如果我们同时用环境变量和设置文件指<br/><br/>     定了某个选项,那么将以环境变量的指定为准。当然,命令行传值参 ......</div> <!--DuYiHuaAdd EndContent--></div> <div id="txtThisUrl"><br/>    <a href="http://www.100md.com/html/file/202004/114485.htm" target="_blank">http://www.100md.com/html/file/202004/114485.htm</a></div> <div id="txttips"><br/>您现在查看是摘要介绍页,<a href="http://www.100md.com/about/help.htm"> 详见PDF附件(7922KB,706页)</a>。</div> <script language="javascript" type="text/javascript" src="http://www.100md.com/comm/v2019/login.js"></script> <script language="javascript" type="text/javascript" src="http://www.100md.com/comm/v2019/after.js"></script> <div id="theRInfo"><script language="javascript" type="text/javascript" src="http://www.100md.com/rjs/file/202004/114485.js"></script><script language="javascript" type="text/javascript" src="http://www.100md.com/comm/v2019/related.js"></script></div> </div><div id="right"><script language="javascript" type="text/javascript" src="http://www.100md.com/comm/v2019/right.js"></script></div> </div><div id="copyright"><script language="javascript" type="text/javascript" src="http://www.100md.com/comm/v2019/copyright.js"></script></div></body></html>