Programming Python,第一部分
Python 是一种编程语言,因其简洁性和易用性而备受推崇。它通常被推荐给编程新手作为良好的入门语言。Python 也是一个解释用 Python 编写的程序的程序。Python 还有其他实现,例如 Jython (Java)、CLPython (Common Lisp)、IronPython (.NET) 等等。在这里,我们只使用 Python。
安装 Python 并使其运行是第一步。现在,这应该非常容易。如果您运行的是 Gentoo GNU/Linux,您已经安装了 Python 2.4。Gentoo 的软件包管理系统 Portage 是用 Python 编写的。如果您没有安装,则您的安装已损坏。
如果您运行的是 Debian GNU/Linux、Ubuntu、Kubuntu 或 MEPIS,只需运行以下命令(或以 root 用户身份登录并省略 sudo)
sudo apt-get install python
需要注意的是,Debian 的稳定版 Python 是 2.3,而对于其余发行版,您很可能会找到 2.4。它们之间的差异不大,并且大多数代码都可以在这两个版本上运行。我遇到的主要差异是一些库类的 API、添加到 2.4 的新功能以及一些内部机制,这些都不应在此处引起我们的关注。
如果您运行的是其他发行版,则很可能 Python 已为其预先打包。使用您用于其他软件包的常用资源和工具来查找 Python 软件包。
如果所有这些都失败了,您需要执行手动安装。这并不困难,但请注意,除非您遵循以下简单指南,否则很容易破坏您的系统:将 Python 安装到一个隔离良好的位置,我喜欢 /opt/python/2.4.3,或任何版本。
要执行安装,请下载 Python,解压缩,然后运行以下命令
./configure --prefix=/opt/python2.4/ make make install
此任务在 Python 的 README 中有详细记录,该文件包含在下载的 tarball 中;请查看以了解更多详细信息。这里唯一缺少的任务是将 Python 添加到您的路径中。或者,您可以直接通过其路径调用来运行它,我建议用于初始探索。
现在我们已经运行了 Python,让我们直接进入编程,并在进行过程中检查该语言。首先,让我们构建一个博客引擎。我所说的引擎是指它不会有任何类型的界面,例如 Web 界面,但这仍然是一个很好的练习。
Python 自带 REPL——Lisp 社区的一个不错的发明。REPL 代表 Read Eval Print Loop(读取-求值-打印循环),这意味着有一个程序可以读取表达式和语句,对其求值,打印结果并等待更多输入。让我们运行 REPL(根据您在上一节中安装 Python 的位置调整您的路径)
$ python Python 2.4.3 (#1, Sep 1 2006, 18:35:05) [GCC 4.1.1 (Gentoo 4.1.1)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>
这三个大于号 (>>>) 是 Python 提示符,您可以在其中编写语句和表达式。要退出 Python,请按 Ctrl-D。
让我们输入一些简单的表达式
>>> 5 5
这更有趣,不是吗?
还有其他类型的表达式,例如字符串
>>> "Hello" 'Hello'
引号用于创建字符串。单引号或双引号的处理方式基本相同。实际上,您可以看到我使用了双引号,而 Python 以单引号显示字符串。
另一种表达式是列表
>>> [1,3,2] [1, 3, 2]
方括号用于创建列表,其中项目用逗号分隔。并且,正如我们可以添加数字一样,我们可以添加——实际上是连接——列表
>>> [1,3,2] + [11,3,2] [1, 3, 2, 11, 3, 2]
到现在为止,您可能已经感到无聊了。让我们切换到更令人兴奋的东西——博客。博客是一系列帖子,而 Python 列表是表示博客的好方法,帖子作为字符串。在 REPL 中,我们可以构建一个简单的博客,如下所示
>>> ["My first post", "Python is cool"] ['My first post', 'Python is cool'] >>>
这是一个字符串列表。您可以创建任何您想要的列表,包括列表的列表。到目前为止,我们所有的表达式都被求值、显示并丢失了。我们无法回忆起我们的博客以添加更多项目或在浏览器中显示它们。赋值来解救了
>>> blog = ["My first post", "Python is cool"] >>>
现在,名为 blog 的变量包含该列表。与之前的示例不同,这次没有打印任何内容,因为这是一个赋值。赋值是语句,而语句没有返回值。简单地求值变量会向我们显示内容
>>> blog ['My first post', 'Python is cool']
访问我们的博客很容易。我们只需通过数字识别每个帖子
>>> blog[0] 'My first post' >>> blog[1] 'Python is cool'
如果我们不能添加新帖子,博客就不是博客,所以让我们这样做
>>> blog = blog + ["A new post."] >>> blog ['My first post', 'Python is cool', 'A new post.']
这里我们将博客设置为一个新值,它是旧博客和一个新帖子。仅仅为了添加一个新帖子而记住所有这些是不愉快的,因此我们可以将其封装在所谓的函数中
>>> def add_post(blog, new_post): ... return blog + [new_post] ... >>>
def 是用于定义新函数或方法(更多关于结构化或函数式编程中的函数以及面向对象编程中的方法将在本文后面介绍)的关键字。接下来是函数的名称。在括号内,我们有形式参数。这些就像变量,将由函数的调用者定义。在冒号之后,提示符已从 >>> 更改为 ... 以表明我们正在定义内部。函数由所有缩进级别低于 def 行级别的行组成。
因此,当其他编程语言使用花括号或 begin/end 关键字时,Python 使用缩进。这个想法是,如果您是一个优秀的程序员,您无论如何都会缩进它,所以我们将使用该缩进并同时让您成为一个优秀的程序员。实际上,这是一个有争议的问题;我一开始不喜欢它,但我学会了适应它。
在使用 REPL 时,您可以安全地按 Tab 键进行缩进级别,尽管 Tab 字符可以做到这一点,但使用四个空格是强烈推荐的方式。许多文本编辑器都知道在编辑 Python 文件时,当您按 Tab 键时放置四个空格。无论您做什么,永远不要,我再说一遍,永远,将制表符与空格混合使用。在其他编程语言中,这可能会使社区不喜欢您,但在 Python 中,它会使您的程序因奇怪的错误消息而失败。
为了实用起见,要重现我所做的,只需键入类头,def add_post(blog, new_post),按 Enter 键,按 Tab 键,键入return blog + [new_post],按 Enter 键,再次按 Enter 键,就这样。让我们看看该函数的作用
>>> blog = add_post(blog, "Fourth post") >>> blog ['My first post', 'Python is cool', 'A new post.', 'Fourth post'] >>>
add_post 接受两个参数。第一个是博客本身,它被赋值给 blog。这很棘手。函数内部的 blog 与函数外部的 blog 不同。它们在不同的作用域中。这就是为什么以下
>>> def add_post(blog, new_post): ... blog = blog + [new_post]
不起作用的原因。blog 仅在函数内部被修改。到目前为止,您可能知道 new_post 包含传递给函数的帖子。
我们的博客正在增长,现在是时候看到帖子只是字符串,但我们希望有一个标题和一个正文。一种方法是使用元组,像这样
>>> blog = [] >>> blog = add_post(blog, ("New blog", "First post")) >>> blog = add_post(blog, ("Cool", "Python is cool")) >>> blog [('New blog', 'First post'), ('Cool', 'Python and is cool')] >>>
在第一行中,我将博客重置为空列表。然后,我添加了两个帖子。看到双括号了吗?外括号是函数调用的一部分,内括号是元组的创建。
元组由括号创建,其成员用逗号分隔。它们类似于列表,但在语义上,它们是不同的。例如,您无法更新元组的成员。元组用于构建具有固定元素集的一些结构。让我们看看博客之外的元组
>>> (1,2,3) (1, 2, 3)
访问帖子的每个部分类似于访问博客的每个部分
>>> blog[0][0] 'New blog' >>> blog[0][1] 'This is my first post'
如果我们只想存储标题和正文,这可能是一个好的解决方案。但是,我们多久才会想要添加日期和时间、摘要、标签或消息?您可能会开始考虑您需要在墙上挂一张纸,如图 1 所示,以记住每个字段的索引——一点都不愉快。为了解决这个问题,以及其他一些问题,Python 为我们提供了面向对象编程。
面向对象编程诞生于 20 多年前,以便开发人员可以以类似于现实世界中对象分离的方式分离计算机程序的每个部分。Python 通过使用类来建模对象。类是对象拥有什么以及对象可以做什么的抽象定义。如果这听起来很陌生,请不要担心,OOP(面向对象编程)一开始很困难。
一个例子可能会有所帮助。桥梁是一种结构,允许人或车辆跨越障碍物,例如河流、运河或铁路。桥梁具有一定的长度、宽度甚至颜色。它可能允许车辆或仅允许行人。它可能允许重型车辆或不允许。当我说“桥梁”时,我没有定义任何这些细节。“桥梁”是一个类。如果我说金门大桥、诺曼底大桥或明石海峡大桥,我是在命名特定的桥梁;它们具有一些特定的长度、宽度、车辆允许和颜色。在 OOP 术语中,它们是桥梁的实例。
回到我们的博客,让我们创建一个类来建模我们的帖子
>>> class Post(object): ... pass ... >>>
我们以 class 开头,这是创建新类的关键字。接下来是类的名称——在本例中为 Post。在括号中,我们有超类——现在忽略它。
同样,提示符已从 >>> 更改为 ...,Python 期望类中有东西。因为我们现在不想放入任何东西,所以我们写pass,这是东西,但实际上,它是空的。Python 知道类的开始和结束,因为缩进,与函数相同。
要重现我所做的,只需键入类头,class Post(object),按 Enter 键,按 Tab 键,键入pass,按 Enter 键,再次按 Enter 键,就这样。
现在,我们可以创建一个 Post
>>> cool = Post() >>> cool <__main__.Post object at 0xb7ca642c>
请注意,当我们求值帖子时打印的内容是对象的通用表示形式。我们可以设置其标题和正文
>>> cool.title = "Cool" >>> cool.body = "Python is cool."
并检索它们
>>> cool.title 'Cool' >>> cool.body 'Python is cool.'
到目前为止,Post 就像一个简单的容器,可以容纳您能想到的任何东西。这样做的问题是我们可能会迷失在应该放入什么或不应该放入什么中。回到纸上?不!虽然我们不能阻止以这种方式使帖子成为容器,但我们可以在那里放置一些方法,以便用户了解帖子可能包含什么。为此,我们在 Post 类中编写我们自己的方法
>>> class Post(object): ... def set_title(self, title): ... self._title = title ... def get_title(self): ... return self._title ... >>>
方法类似于函数,但由于它们在类中,因此它们与类的对象相关联。这意味着不同的类可以具有相同名称的不同方法。想象一下 bat.hit(ball) 和 stick.hit(drum) 之间的区别。
Python 有一个约定,方法的第一个参数(通常称为 self)是我们正在调用该方法的对象。这意味着运行cool.set_title("Cool")将设置self为cool,以及title为"Cool"。运行
cool.set_title("Cool")
等同于
cool._title = "Cool"
前导下划线让其他人知道我们不希望他们使用它。它的意思是“不要访问 _title;使用 get_title 和 set_title”。
先前与 cool 对象的交互可以重写为
>>> cool = Post() >>> cool.set_title("Cool") >>> cool.set_body("Python is cool.") >>> cool.get_title() 'Cool' >>> cool.get_body() 'Python is cool.'
现在应该很容易编写用于正文的相同方法集。但是,请注意,您必须一次性编写整个类。编写类头、set_title 和 get_title 方法,然后创建您的 set_body 和 get_body 方法。这可能需要您尝试几次。
随着 Post 类变得越来越大,您会厌倦每次想要添加方法时都重写它。如果您已经厌倦了,这是一个好兆头。此外,REPL 中的所有内容将在我们退出 Python 时丢失。我们应该开始将我们的工作保存在文件中。
Python 模块是简单的文本文件,您可以使用任何您想要的文本编辑器。作为一名程序员,您将花费大部分时间在编辑器上,因此请花一些时间选择一个您真正喜欢的编辑器并学习如何好好使用它。
Emacs 可能不是最漂亮的编辑器,但对于许多编程任务来说,它非常棒。(您可以将其理解为“我不喜欢 Emacs,但它使我的生活变得如此轻松,以至于我一次又一次地回到它”。)从源代码安装 Emacs 超出了本文的范围。与如此流行的程序一样,您的发行版很可能会提供它。在 Debian 及其衍生产品中尝试
apt-get install emacs
对于 Gentoo,对应的是
emerge emacs
为了实现我将要展示的魔力,您需要 python-mode。
在 Debian 中
apt-get install python-mode
在 Gentoo 中
emerge python-mode
运行 Emacs。如果您认真学习如何使用它,现在是按 Ctrl-H T 的时候了,这在 Emacs 术语中意味着按 Ctrl-H,释放它,然后按 T。但是,您可以稍后这样做,当您完成阅读本期 Linux Journal 时。对于本文,我提供了您需要的所有按键。
按 Ctrl-X Ctrl-F(Ctrl-X,释放,Ctrl-F)访问文件。在 Emacs 窗口的底部,您将看到光标等待您键入路径和文件名。输入blog.py并按 Enter 键。(Python 模块应具有扩展名 .py。)现在,您可以开始键入我们之前编程的 Post 类。Emacs 尝试智能地处理缩进,并将其放置在您可能想要的位置。如果您需要不同的缩进,只需按 Tab 键并继续按直到获得所需的结果。
在顶部,您应该有两个菜单:IM-Python 和 Python。第一个包含您正在编辑的文件中的类和方法的列表。如果它没有显示您知道存在的信息,请单击“重新扫描”。这在处理大型文件时非常有用。第二个菜单甚至更有用,但稍后探索和使用它。现在,只需运行启动解释器...或按 Ctrl-C !。
突然窗口被拆分,您在您正在编辑的文件下方嵌入了一个 Python 解释器(图 2)。乐趣才刚刚开始。单击您正在编辑的文件以将焦点设置在其上。从 Python 菜单运行“导入/重新加载文件”或按 Ctrl-C Enter。现在,您已准备好在 REPL 上测试您的代码,但请注意,您必须添加blog.在类名之前,Post,因为现在该类在模块 blog 中。有关更多参考,请参见图 2。
当然,您也可以在没有 Emacs 的情况下执行相同的操作。但是为此,您需要学习如何制作 Python 模块和包。相应地设置环境变量 PYTHON_PATH,并使用内置函数 reload。使用 Emacs,您会发现编码和测试代码之间的迭代非常快。这种速度可以提高您的性能并使编程更有趣。实际上,Lisp 程序员已经提倡这种工作方式超过二十年了。
必须创建一个对象,然后设置其每个成员是不愉快的。这需要很多行,而且很容易出错——我记得设置标签了吗?有一种更好的方法可以做到这一点——使用初始化方法。
这种特殊方法称为 __init__,您定义它要接受的参数必须在创建对象时传递。可能的初始化方法是
class Post(object): def __init__(self, title, body): self.set_title(title) self.set_body(body)
只需将 __init__ 定义添加到文件中并重新加载它。我们现在可以并且必须在初始化时设置标题和正文
>>> cool = blog.Post("Cool", "Python is cool") >>> cool.get_title() 'Cool' >>> cool.get_body() 'Python is cool' >>>
提示:要在 Emacs 中的 REPL 中检索之前的行,请使用 Alt-P。
还有其他特殊方法。还记得求值 Post 本身有多丑陋吗?让我提醒您
>>> cool <blog.Post object at 0xb7c7e9ac>
我们可以解决这个问题。还有另一种特殊方法称为 __repr__,用于检索该字符串。在 Post 类中添加
def __repr__(self): return "Blog Post: %s" % self.get_title()
以与之前加载文件相同的方式重新加载文件,并求值一个帖子
>>> ## working on region in file /usr/tmp/python... >>> cool <blog.Post object at 0xb7c7e9ac> >>>
糟糕!那不是我们想要的。这里的问题是 cool 对象是使用旧版本的 Post 类创建的,因此它没有新方法。这是一个非常常见的错误,并且没有为此做好准备可能会导致很多麻烦。但是,只需重新创建对象,您就设置好了
>>> ## working on region in file /usr/tmp/python... >>> cool = blog.Post("Cool", "Python is cool") >>> cool Blog Post: Cool >>>
资源
Python: python.org
Python 下载: python.org/download
Python 2.4.3: www.python.org/ftp/python/2.4.3/Python-2.4.3.tgz
José P. E. “Pupeno” Fern´ndez 从...儿童能够坐在椅子上并够到键盘的年龄开始编程。他尝试过的语言比此页面上可以列出的还要多。他的网站是 pupeno.com,除非您是垃圾邮件发送者,否则总能通过 pupeno@pupeno.com 联系到他。