第一章 快速改造:基础知识

来源:http://www.cnblogs.com/Marlowes/p/5280405.html

作者:Marlowes

1.1 安装Python (略······)

安装Python教程网上能找到很多,这里我不想手打了......

1.2 交互式解释器

当启动Python的时候,会出现和下面相似的提示:

Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec  5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

注:不同的版本的提示和错误信息可能会有所不同。

进入Python的交互式解释器之后输入下面的命令查看它是否正常的工作:

>>> print "Hello,world!"

按下回车后,会得到下面的输出:

Hello,world!

1.3 算法是什么

首先解释一下什么是计算机程序设计。简单地说,它就是告诉计算机要做什么。计算机可以做很多的事情,但是不太擅长自主思考,程序员要像给小孩喂饭一样告诉它具体的细节,并且使用计算机能够理解的语言——算法。“算法”不过是“步骤”或者“食谱”的另外一种说法——对于如何做某事的一份详细的表述。比如:

  SPAM拌SPAM、SPAM、鸡蛋和SPAM:

  首先,拿一些SPAM;

  然后加入一些SPAM、SPAM和鸡蛋;

  如果喜欢吃特别辣的SPAM,再多加点SPAM;

  煮到熟为止——每10分钟检查一次。

这个食谱可能不是很有趣,但是它的组成结构还是有些讲究的。它包括一系列按顺序执行的指令。有些指令可以直接完成(“拿一些SPAM”),有些则需要考虑特定的条件(“如果需要特别辣的SPAM”),还有一些则必须重复次数(“每10分钟检查一次”)。

食谱和算法都包括一些材料(对象,物品),以及指令(语句)。本例中,“SPAM”和“鸡蛋”就是要素,指令则包括添加SPAM、按照给定的时间烹调,等等。

1.4 数字和表达式

交互式Python解释器可以当作非常强大的计算器使用,如以下的例子:

>>> 256868 + 684681
941549

以上是非常普通的功能。在绝大多数情况下,常用算术运算符的功能和计算器的相同。这里有个潜在的陷阱,就是整数除法(在3.0版本之前的Python是这样的)。

>>> 1 / 2
0

从上面的例子可以看出,一个整数(无小数部分的数)被另一个整数除,计算结果的小数部分被截除了,只留下整数部分。有些时候,这个功能很有用,但通常人们只需要普通的除法。有两个有效的解决方案:要么用实数(包含小数点的数),而不是整数进行运算,要么让Python改变除法的执行方式。

实数在Python中被称为浮点数(Float,或者Float-point Number),如果参与除法的两个数中有一个数为浮点数,则运算结果亦为浮点数:

>>> 1.0 / 2.0
0.5
>>> 1 / 2.0
0.5
>>> 1 / 2.
0.5

如果希望Python只执行普通的除法,那么可以在程序前加上一下语句,或者直接在解释器里面执行它:

>>> from __future__ import division

还有另一个方法,如果通过命令行运行Python,可以使用命令开关-Qnew。使用上述两种方法,就可以只执行普通的除法运算:

>>> 1/2
0.5

当然,单斜线不再用作前面提到的整除了,但是Python提供了另外一个用于实现整除的操作符——双斜线:

>>> 1 // 2
0

就算是浮点数,双斜线也会执行整除:

>>> 1.0 // 2.0
0.0

现在,已经了解基本的算数运算符了(加、减、乘、除)。除此之外,还有一个非常有用的运算符:

>>> 1 % 2
1

这是取余(模除)运算符——x % y的结果为x除以y的余数。下面是另外一些例子:

>>> 10 / 3
3
>>> 10 % 3
1
>>> 9 / 3
3
>>> 9 % 3 0
>>> 2.75 % 0.5
0.25

这里10/33是因为结果被向下取整了。而3x3=9,所以相应的余数就是1了。在计算9/3时,结果就是3,没有小数部分可供截除,因此,余数就是0了。如果要进行一些类似文章前面菜谱所述“每10分钟”检查一次的操作,那么,取余运算就非常有用了,直接检查时间10%的结果是否为0即可。从上述最后一个例子可以看到,取余运算符对浮点数也同样适用。

最后一个运算符就是幂(乘方)运算符:

>>> 2 ** 3
8
>>> -3 ** 2
-9
>>> (-3) ** 2
9

注:幂运算符比取反(一元减运算符)的优先级要高,所以-3**2等同于-(3**2)。如果想计算(-3)**2,就需要显示说明。

1.4.1 长整数

Python可以处理非常大的整数:

>>> 100000000000000000000
100000000000000000000L

可以看到数字后面自动加上了一个L

普通的整数不能大于2 147 483 647(也不能小于-2 147 483 648),如果需要更大的数,可以使用长整数。长整数的书写方法和普通整数一样,但是结尾有个L。(理论上,用小写的l也可以,但是小写的l看起来太像1,所以建议不要用小写。)

在前面的例子中,Python把整数转换为了长整数,但是我们自己也可以完成:

>>> 100000000000000000000L
100000000000000000000L

当然,这只是在不能处理大数的旧版Python中很有用。

也可以对这些庞大的数字进行运算,例如:

>>> 165165846835413545L * 2654684351365435434L + 1846846746843
438463188973992663445213017233300373L

正如所看到的那样,长整数和普通整数可以混合使用。在绝大多数情况下,无需担心长整数和整数的区别,除非需要进行类型检查。

1.4.2 十六进制和八进制

在Python中,十六进制数应该像下面这样书写:

>>> 0xAF
175

而八进制数则是:

>>> 010
8

十六进制和八进制数的首位数字都是0

1.5 变量

变量(variable)是另外一个需要熟知的概念。Python中的变量很好理解。变量基本上就是代表(或者引用)某值的名字。举例来说,如果希望用名字x代表3,只需要执行下面的语句即可:

>>> x = 3

这样的操作成为赋值(assignment),数值3被赋值给了变量x。或者说:将变量x绑定到了值(或者对象)3上面。在变量被赋值之后,就可以在表达式中使用变量。

>>> x * 2
6

注意,在使用变量之前,需要对其赋值。毕竟不代表任何值的变量没有什么意义。

注:变量名可以包括字母、数字和下划线(`)。变量不能以数字开头,所以Plan9是合法变量名,而9Plan`不是。_

1.6 语句

到现在为止,我们一直都在讲述表达式,也就是“食谱”的“材料”。那么,语句(也就是指令)是什么呢?

刚才已经介绍了两类语句:print语句和赋值语句。那么语句和表达式之间有什么区别呢?表达式就是某件事情,而语句是做某件事情(即告诉计算机做什么)。比如2*24,而print 2*2则是打印4`。那么区别在哪呢?毕竟,它们的行为非常相似。请看下面的例子:

>>> 2 * 2
4
>>> print 2 * 2
4

如果在交互式解释器中执行上述两行代码,结果是一样的。但这只是因为交互式解释器总是把所有表达式的值打印出来而已(都使用了相同的repr函数对结果进行呈现,详细参见1.11.3节)。一般情况下,Python并不会那样做。在程序中编写类似2*2这样的表达式并不能做什么有趣的事情(它只计算了2*2的结果,但是结果并不会在某处保存或显示给用户,它对运算本身之外的东西没有任何的副作用)。另一方面,编写print 2*2则会打印出4

语句和表达式之间的区别在赋值时会表现的更加明显一些。因为语句不是表达式,所以没有值可供交互式解释器打印出来:

>>> x = 3
>>>

可以看到,下面立刻出现了新的提示符。但是,有些东西已经变化了,x现在绑定给了值3

这也是能定义语句的一般性特征:它们改变了事务。比如,赋值语句改变了变量,print语句改变了屏幕显示的内容。

赋值语句可能是任何计算机程序设计语言中最重要的语句类型,尽管现在还难以说清它们的重要性。变量就像临时的“存储器”(就像烹饪食谱中的锅碗瓢盆一样。但是值并没有保存在变量中——它们保存在计算机内存的深处,被变量引用。随着本书内容的深入,你会对此越来越清楚:多个变量可以引用同一个值。),它的强大之处就在于,在操作变量的时候并不需要知道它们存储了什么值。比如,即使不知道x和y的值到底是多少,也会知道x*y的结果就是xy的乘积。所以,可以在程序中通过多种方法来使用变量,而不需要知道在程序运行的时候,最终存储(或引用)的值到底是什么。

1.7 获取用户输入

我们在编写程序的时候,并不需要知道变量的具体值。当然,解释器最终还是得知道变量的值。可是,它怎么会知道我们都不知道的事呢?解释器只知道我们告诉它的内容,对吧?不一定。

事实上,我们通常编写程序让别人用,我们无法预测用户会给程序提供什么样的值。那么,看看非常有用的input函数吧:

>>> input("You this year many big?: ")
You this year many big?: 18
18

在这里,交互式解释器执行了第一行的input(...)语句。它打印出了字符串"You this year many big?:",并以此作为新的提示符,输入18然后按下回车。input语句的结果值就是我输入的数字,它自动在最后一行被打印出来。这个例子确实不太有用,但是请接着看下面的内容:

>>> x = input("x: ")
x: 16
>>> y = input("y: ")
y: 31
>>> print x * y
496

Python提示符(>>>)后面的语句可以算作一个完整程序的组成部分了,输入的值(1631)有用户提供,而程序就会打印出输入的两个数的乘积496。在编写程序的时候,并不需要知道用户输入的数是多少,对吧?

注:这种做法非常有用,因为你可以将程序存为单独的文件,以便让其他用户可以直接执行。

管窥:if语句

if语句可以让程序在给定条件为真的情况下执行某些操作(执行另外的语句)。一类条件是使用相等运算符==进行相等性测试。是两个等号,一个等号是用来赋值的。

可以简单地把这个条件放在if后面,然后用冒号将其和后面的语句隔开:

>>> if 1 == 2:
        print "One equals two"
        ...
>>> if 1 == 1:
        print "One equals one"
        ...
One equals one
>>>

可以看到,当条件为假(False)的时候,什么都没有发生;当条件为真(True)的时候,后面的语句(本例中为print语句)被执行。注意,如果在交互式解释器内使用if语句,需要按两次回车,if语句才能执行。(第五章会对其原因进行说明。)

所以,如果变量time绑定到当前时间的分钟数上,那么可以使用下面的语句检查是不是“到了整点”。

>>> if time % 60 == 0:
        print "On the hour!"

1.8 函数

在1.4节中曾经介绍过使用幂运算符(**)来计算乘方。事实上,可以用一个函数来代替这个运算符,这个函数就是pow:

>>> 2 ** 3
8
>>> pow(2, 3)
8

函数就像小型程序一样,可以用来实现特定的功能。Python有很多函数,它们能做很奇妙的事情。你也可以自己定义函数(后面会对此展开讲述)。因此,我们通常把pow等标准函数称为内建函数

上例中我使用函数的方式叫做调用函数。你可以给它提供参数(本例中的2和3)。它会返回值给用户。因为它返回了值,函数调用也可以简单看作另外一类表达式,就像在本章前面讨论的算数表达式一样(如果忽略了返回值,函数调用也可以看成语句)。事实上,可以结合使用函数调用和运算符来创建更复杂的表达式:

>>> 10 + pow(2, 3 * 5) / 3.0
10932.666666666666

还有很多像这样的内建函数可以用于数值表达式。比如使用abs函数可以得到数的绝对值,round函数则会把浮点数四舍五入为最接近的整数值:

>>> abs(-10) 10
>>> round(1.0 / 2.0)
1.0

注意最后两个表达式的区别。整数除法总是会截除结果的小数部分,而round函数则会将结果四舍五入为最接近的整数。但是如果想将给定的数值向下取整为某个特定的整数呢?比如一个人的年龄是32.9岁——但是想把它取整为32,因为她还没到33岁。Python有实现这样功能的函数(称为floor),但是不能直接使用它。与其他很多有用的函数一样,你可以在某个模块中找到floor函数。

1.9 模块

可以把模块想象成导入到Python以增强其功能的扩展。需要使用特殊的命令import来导入模块。前面内容提到floor函数就在名为math的模块中:

>>> import math
>>> math.floor(32.9)
32.0

注意它是怎么起作用的:用import导入了模块,然后按照“模块.函数”的格式使用这个模块的函数。

如果想把年龄转换为整数(32)而不是浮点数(32.0),可以使用int函数。(int函数/类型把参数转换成整数时会自动向下取整,所以在转换过程中,math.floor是多余的,可以直接使用int(32.9))

>>> int(math.floor(32.9))
32

注:还有类似的函数可以将输入数转换为其他类型(比如longfloat)。事实上,他并不完全是普通的函数——它们是类型对象(type object)。后面,我将会对类型进行详述。与floor相对的函数是ceil(ceiling的简写),可以将给定的数值转换成为大于或等于它的最小整数。

在确定自己不会导入多个同名函数(从不同模块导入)的情况下,你可能希望不要在每次调用函数的时候都写上模块的名字。那么,可以使用import命令的另外一种形式:

>>> from math import sqrt
>>> sqrt(9)
3.0

在使用了from 模块 import 函数这种形式的import命令之后,就可以直接使用函数,而不需要模块名作为前缀。

注:事实上,可以用变量来引用函数(或者Python之中大多数的对象)。比如,通过 foo = math.sqrt进行赋值,然后就可以使用foo来计算平方根了:foo(4)的结果为2.0

1.9.1 cmath和复数

sqrt函数用于计算一个数的平方根。看看如果给它一个负数作为参数会如何:

>>> from math import sqrt >>> sqrt(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ValueError: math domain error

或者,在其他平台会有以下结果:

>>> sqrt(-1)

nan

注:nan是一个特殊值的简写,意思是“not a number” (非数值)。

这也情有可原,不能求负数的平方根。真的不可以么?其实可以:负数的平方根是虚数(这是标准的数学概念,如果感觉有些绕不过弯来,跳过即可)。那么为什么不能使用sqrt?因为它只能处理浮点数,而虚数(以及复数,即实数和虚数之和)是完全不同的。因此,它们由另一个叫做cmath(即complex math,复数)的模块来处理。

>>> import cmath
>>> cmath.sqrt(-1)
1j

注意,我在这里并没有使用from...import...语句。因为一旦使用了这个语句,就没法使用普通的sqrt函数了。这类命名冲突可能很隐蔽,因此,除非真的需要from这个形式的模块导入语句,否则应该坚持使用普通的import

1j是个虚数,虚数均已j(或者J)结尾,就像长整数使用L一样。我们在这里不深究复数的理论,只举最后一个例子,来看一下如何使用复数:

>>> (1 + 3j) * (9 + 4j)
(-3+31j)

可以看到,Python语言本身就提供了对复数的支持。

注:Python中没有单独的虚数类型。它们被看做实数部分为0的复数。

1.9.2 回到 __future__

有传言说Guido van Rossum(Python之父)拥有一架时光机,因为在人们要求增加语言新特性的时候,这个特性通常都已经实现了。当然,我等凡夫俗子是不允许进入这架时光机的。但是Guido很善良,他将时光机的一部分以 __future__ 这个充满魔力的模块的形式融入了Python。通过它可以导入那些在未来会成为标准Python组成部分的新特性。你已经在1.4节见识过这个模块了,而在本书余下的部分,你还将与它不期而遇。

1.10 保存并执行程序

交互式解释器是Python的强项之一,它让人们能够实时检验解决方案并且用这门语言做一些实验。如果想知道如何使用某些语句,那么就试试看吧!但是,在交互式解释器里面输入的一切都会在它退出的时候丢失。而我们真正想要的是编写自己和他人都能运行的程序。在本节中,将会介绍如何实现这一点。

首先,需要一个文本编辑器,最好是专门用来编程的。如果使用Microsoft Word这样的编辑器(我并不推荐这么做),那么得保证代码是以纯文本形式保存的。如果已经在用IDLE,那么,很幸运:用File→New Windows方式创建一个新的编辑窗口即可。这样,另外一个窗口就出现了,没有交互式提示符,很好!

先输入以下内容:

print "Hello, world!"

现在选择File→Save保存程序(其实就是纯文本文件)。要确保将程序保存在一个以后能找到的地方。你应该专门建立一个存放Python项目的目录,还要为自己的程序文件起个有意义的名字。比如hello.py。文件名以.py结尾是很重要的。

然后就可以使用Edit→Run或者按下Ctrl+F5键来运行程序了(如果没有用IDLE,请查看下一节有关如何在命令提示符下运行程序的内容)。

你会发现"Hello, world!"在解释器窗口内打印出来了,这就是想要的结果。解释器提示符没了(不同的版本会有所差异),但是可以按下回车键将它找回了(在解释器窗口按回车键)。

接下来,我们对上述脚本进行扩展,如下例所示:

name = raw_input("What is your name? ")
print "Hello, " + name + "!"

注:不用管inputraw_input的区别,稍后,我会进行介绍的。

如果运行这个程序(记得先保存),应该会在解释器窗口中看到下面的提示:

What is your name?

输入你的名字(比如XuHoo),然后按下回车键。你将会看到如下内容:

Hello, XuHoo!

1.10.1 通过命令提示符运行Python脚本

事实上,运行程序的方法有很多。首先,假定打开了DOS窗口或者UNIX中的Shell提示符,并且进入了某个包含Python可执行文件(在Windows中是python.exe,而UNIX中则是python)的目录,或者包含了这个可执行文件的目录已经放置在环境变量PATH中了(仅适用于Windows)。同时假设,上一节的脚本文件(hello.py)也在当前目录中。那么,可以在Windows中使用以下命令执行来脚本:

C:\> python hello.py

或者在UNIX下:

$ python hello.py

可以看到,命令是一样的,仅仅是系统提示符不同。

注:如果不想跟什么环境变量打交道,可以直接指定Python解释器的完整路径。在Windows中,可以通过以下命令完成操作:

# 根据你的Python版本更改版本号
C:\> C:\Python27\python hello.py

1.10.2 让脚本像普通程序一样运行

有些时候希望像运行其他程序(比如Web浏览器、文本编辑器)一样运行Python程序(也叫做脚本),而不需要显式使用Python解释器。在UNIX中有个标准的实现方法:在脚本首行前面加上#!(叫做pound bang或者shebang),在其后加上用于解释脚本的程序的绝对路径(在这里,用于解释代码的程序是Python)。即使不太明白其中的原理,如果希望自己的代码能够在UNIX下顺利执行,那么只要把下面的内容放在脚本的首行即可:

#!/usr/bin/env python

不管Python的二进制文件在哪里,程序都会自动执行。

注:在某些操作系统中,如果安装了最新版的Python,同时旧版的Python仍然存在(因为某些系统程序需要它,所以不能把它卸载),那么在这种情况下,/usr/bin/env技巧就不好用了,因为旧版的Python可能会运行程序。因此需要找到新版本Python可执行文件(可能叫做python或python2)的具体位置,然后在pound bang行中使用完整的路径,如下例所示:

#!/usr/bin/python2

具体的路径会因系统而异。

在实际运行脚本之前,必须让脚本文件具有可执行的属性(UNIX系统):

$ chmod a+x hello.py

现在就能这样运行了(假设当前目录包含在路径中):

$ hello.py

注意如果上述操作不起作用的话,试试./hello.py。即当前的目录(.)并不是执行路径的一部分,这样的操作也能够成功。

在Windows系统中,让代码像普通程序一样运行的关键在于后缀名.py。加入双击上一节保存好的hello.py文件,如果Python安装正确,那么,一个DOS窗口就会出现,里面有"What is your name?"提示。

然而,像这样运行程序可能会碰到一个问题:程序运行完毕,窗口也跟着关闭了。也就是说,输入了名字以后,还没来得及看结果,程序窗口就已经关闭了。试着改改代码,在最后加上以下这行代码:

raw_input("Press <enter>")

这样,在运行程序并且输入名字之后,将会出现一个包含以下内容的DOS窗口:

What is your name? XuHoo
Hello, XuHoo!
Press <enter>

用户按下回车键以后,窗口就会关闭(因为程序运行结束了)。作为后面内容的预告,现在请你把文件名改为hello.pyw(这是Windows专用的文件类型),像刚才一样双击。你会发现什么都没有!怎么会这样?在本书后面的内容将会告诉你答案。

1.10.3 注释

井号(#)在Python中有些特殊。在代码中输入它的时候,它右边的一切内容都会被忽略(这也是之前Python解释器不会被/usr/bin/env行“卡住”的原因了)。比如:

# 打印圆的周长:
print 2 * pi * radius

这里的第一行称为注释。注释是非常有用的,即为了让别人能够更容易理解程序,也为了额你自己回头再看旧代码。据说程序员的第一条戒律就是“汝应注释”(Thou Shalt Comment)(尽管很多刻薄的程序员的座右铭是“如果难写,就该难读”)。程序员应该确保注释说的都是重要的事情,而不是重复代码中显而易见的内容。无用的、多余的注释还不如没有。例如,下例中的注释就不好:

# 获得用户名:
user_name = raw_input("What is your name? ")

即使没有注释,也应该让代码本身易于理解。幸好,Python是一门出色的语言,它能帮助程序员编写易于理解的程序。

1.11 字符串

那么,raw_input函数和"Hello, " + name + "!"这些内容到底是什么意思?放下raw_input函数暂且不表,先来说"Hello"这个部分。

本章的第一个程序是这样的,很简单:

print "Hello, world!"

在编程类图书中,习惯上都会以这样一个程序作为开篇——问题是我还没有真正解释它是怎么工作的。前面已经介绍了print语句的基本知识(随后我会介绍更多相关的内容),但是"Hello, world!"是什么呢?是字符串(即“一串字符”)。字符串在几乎所有真实可用的Python程序中都会存在,并且有多种用法,其实最主要的用法就是表示一些文本,比如这个感叹句"Hello, world!"

1.11.1 单引号字符串和转义引号

字符串是值,就像数字一样:

>>> "Hello, world!"
'Hello, world!'

但是,本例中有一个地方可能会让人觉得吃惊:当Python打印出字符串的时候,是用单引号括起来的,但是我们在程序中用的是双引号。这有什么却别吗?事实上,并没有区别。

>>> 'Hello, world!'
'Hello, world!'

这里也用了单引号,结果是一样的。那么,为什么两个都可以用呢?因为在某些情况下,它们会排上用场:

>>> "Let's go!"
"Let's go!"
>>> '"Hello, world!" she said'
'"Hello, world!" she said'

在上面的代码中,第一段字符串包含了单引号,这时候就不能用单引号将整个字符串括起来了。如果这么做,解释器会提示错误:

>>> 'Let's go!'
  File "<stdin>", line 1
    'Let's go!'
         ^ SyntaxError: invalid syntax

在这里字符串为'Let',Python并不知道如何处理后面的s(也就是该行余下的内容)。

在第二个字符串中,句子包含了双引号。所以,出于之前所述的原因,就需要用单引号把字符串括起来了。或者,并不一定要这样做,尽管这样做很直观。另外一个选择就是:使用反斜线(\)对字符串中的引号进行转义

>>> 'Let\'s go!'
"Let's go!"

Python会明白中间的单引号是字符串中的一个字符,而不是字符串的结束标记(即便如此,Python也会在打印字符串的时候在最外层使用双印号)。有的人可能已经猜到,对双引号也可以使用相同的方式转义:

>>> "\"Hello, world!\" she said"
'"Hello, world!" she said'

像这样转义引号十分有用,有些时候甚至还是必需的。例如,如果希望打印出一个包含单双引号的字符串,不用反斜线的话能怎么办呢?比如字符'Let\'s say "Hello, world!"'

注:在本章后面的内容中,将会介绍通过使用长字符串和原始字符串(两者可以联合使用)来减少绝大多数反斜线的使用。

1.11.2 拼接字符串

继续探究刚才的例子,我们可以通过另外一种方式输出同样的字符串:

>>> "Let's say" '"Hello, world!"'
'Let\'s say"Hello, world!"'

我只是用一个接着另一个的方式写了两个字符串,Python就会自动拼接它们(将它们合为一个字符串)。这种机制用得不多,有时却非常有用。不过,它们只是在同时写下两个字符串时才有效,而且要一个紧接着另一个。否则会出现下面的错误:

>>> x = "Hello, "
>>> y = "world!"
>>> x y
  File "<stdin>", line 1 x y
  ^ SyntaxError: invalid syntax

换句话说,这仅仅是书写字符串的一种特殊方法,并不是拼接字符串的一般方法。那么,该怎样拼接字符串呢?就像进行加法运算一样:

>>> "Hello, " + "world!"
'Hello, world!'
>>> x = "Hello, "
>>> y = "world!"
>>> x + y
'Hello, world!'

1.11.3 字符串表示,str和repr

通过前面的例子读者们可能注意到了,所有通过Python打印的字符串还是被引号括起来的。这是因为Python打印值的时候会保持该值在Python代码中的状态,而不是你希望用户所看到的状态。如果使用print语句,结果就不一样了:

>>> "Hello, world!"
'Hello, world!'
>>> 1000000L
1000000L
>>> print "Hello, world!"
Hello, world!
>>> print 1000000L
1000000

可以看到,长整型数1 000 000L被转换成了数字1 000 000,而且在显示给用户的时候也如此。但是当你想知道一个变量的值是多少时,可能会对它是整型还是长整型感兴趣。

我们在这里讨论的实际上是值被转换为字符串的两种机制。可以通过以下两个函数来使用这两种机制:一种是通过str函数,它会把值转换为合理形式的字符串,以便用户可以理解;另一种是通过repr函数,它会创建一个字符串,以合法的Python表达式的形式来表示值(事实上,strintlong一样,是一种类型。而repr仅仅是函数)。下面是一些例子:

>>> print repr("Hello, world!")
'Hello, world!'
>>> print repr(1000000L)
1000000L
>>> print str("Hello, world!")
Hello, world!
>>> print str(1000000L)
1000000

repr(x)也可以写作`x` 实现(注意,` 是反引号,而不是单引号)。如果希望打印出一个包含数字的句子,那么反引号就很有用了。比如:

>>> temp = 42
>>> print "The temperature is " + temp
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: cannot concatenate 'str' and 'int' objects
>>> print "The temperature is " + `temp`
The temperature is 42

注:在Python3.0中,已经不再使用反引号了。因此,即使在旧的代码中看到了反引号,你也应该坚持使用repr

第一个print语句并不能工作,那是因为不可以将字符串和数字进行相加。而第二个则可以正常工作,因为我已经通过反引号将temp的值转换为字符串"42"了。(当然,也可以通过repr,也可以得到同样的结果。但是,使用反引号可能更清楚一些。事实上,本例中也可以使用str。)

简而言之,strrepr和反引号是将Python值转换为字符串的三种方法。函数str让字符串更易于阅读,而repr(和反引号)则把结果字符串转换为合法的Python表达式。

1.11.4 input和raw_input的比较

相信读者已经知道"Hello, " + name + "!"是什么意思了,那么,raw_input函数怎么用呢?input函数不够好吗?让我们试一下。在另外一个脚本文件中输入下面的语句:

name = input("What is your name? ")
print "Hello, " + name + "!"

看起来这是一个完全合法的程序。但是马上你就会看到,这样是不可行的。尝试运行该程序:

What is your name? XuHoo
Traceback (most recent call last):
  File "p.py", line 2, in <module>
name = input("What is your name? ")
  File "<string>", line 1, in <module>
  NameError: name 'XuHoo' is not defined

问题在于input会假设用户输入的是合法的Python表达式(或多或少有些与repr函数相反的意思)。如果以字符串作为输入的名字,程序运行是没有问题的:

What is your name?
"XuHoo" Hello, XuHoo!

然而,要求用户带着引号输入他们的名字有点过分,因此,这就需要使用raw_input函数,它会把所有的输入当做原始数据(raw data),然后将其放入字符串中:

>>> input("Enter a number: ")
Enter a number: 3
3
>>> raw_input("Enter a number: ")
Enter a number: 3
'3'

除非对input有特别的需要,否则应该尽可能使用raw_input函数。

1.11.5 长字符串、原始字符串和Unicode

在结束本章之前,还会介绍另外两种书写字符串的方法。在需要长达多行的字符串或者包含多种特殊字符的字符串的时候,这些候选的字符串语法就会非常有用。

1.长字符串

如果需要写一个非常非常长的字符串,它需要跨多行,那么,可以使用三个引号代替普通引号:

print '''This is a very long string.
It continues here.
And it's not over yet.
"Hello, world!"
Still here.'''

也可以使用三个双引号,如"""This is a very long string"""。注意,因为这种与众不同的引用方式,你可以在字符串之中同时使用单引号和双引号,而不需要使用反斜线进行转义。

注:普通字符串也可以跨行。如果一行之中最后一个字符是反斜线,那么,换行符本身就“转义”了,也就是被忽略了,例如:

>>> print "Hello, \
... world!" Hello, world!

这个用法也适用于表达式和语句:

>>> 1 + 2 + \
... 4 + 5
12
>>> print \
... "Hello, world!"
Hello, world!

2.原始字符串

原始字符串对于反斜线并不会特殊对待。在某些情况下这个特性是很有用的(尤其是在书写正则表达式时候,原始字符串就会特别有用)。在普通字符串中,反斜线有特殊的作用:它会转义,让你在字符串中加入通常情况下不能直接加入的内容。例如,换行符可以写为\n,并可放于字符串中,如下所示:

>>> print "Hello, \nworld!"
Hello,
world!

这看起来不错,但是有时候,这并非是想要的结果。如果希望在字符串中包含反斜线再加上n怎么办呢?例如,可能需要像DOS路径"C:\nowhere"这样的字符:

>>> path = "C:\nowhere"
>>> path 'C:\nowhere'

这看起来是正确的,但是,在打印该字符串的时候就会发现问题了:

>>> print path
C:
owhere

这并不是期望的结果,那么该怎么办呢?我可以使用反斜线对其本身进行转义:

>>> print "C:\\nowhere"
C:\nowhere

这看起来不错,但是对于长路径,那么可能需要很多反斜线:

>>> path = "C:\\Program Files\\fnord\\foo\\bar\\frozz\\bozz"

在这样的情况下,原始字符串就派上用场了。原始字符串不会把反斜线当做特殊字符。在原始字符串中输入的每个字符都会与书写的方式保持一致:

>>> print r"C:\nowhere" C:\nowhere
>>> print r"C:\Program Files\fnord\foo\bar\frozz\bozz"
C:\Program Files\fnord\foo\bar\frozz\bozz

可以看到,原始字符串以r开头。看起来可以在原始字符串中放入任何字符,而这种说法也是基本正确的。当然,我们也要像平常一样对引号进行转义,但是,最后输出的字符串包含了转义所用的反斜线:

>>> print r'Let\'s go!'
Let\'s go!

不能在原始字符串结尾输入反斜线。换句话说,原始字符串最后的一个字符不能是反斜线,除非你对反斜线进行转义(用于转义的反斜线也会成为字符串的一部分)。参照上一个范例,这是一个显而易见的结论。如果最后一个字符(位于结束引号前的那个)是反斜线,Python就不清楚是否应该结束字符串:

>>> print r"This is illegal\"
  File "<stdin>", line 1
    print r"This is illegal\"
                            ^ SyntaxError: EOL while scanning string literal

好了,这样还是合理的,但是如果希望原始字符只以一个反斜线作为结尾符的话,那该怎么办呢?(例如,DOS路径的最后一个字符有可能是反斜线)好,本节已经告诉了你很多解决此问题的技巧,但本质上就是把反斜线单独作为一个字符串来处理。以下就是一种简单的做法:

>>> print r"C:\Program Files\foo\bar" "\\"
C:\Program Files\foo\bar\

注:你可以在原始字符串中同时使用单双引号,甚至三引号字符串也可以

3. Unicode字符串

字符串常量的最后一种类型就是Unicode字符串(或者称为Unicode对象,与字符串并不是同一个类型)。如果你不知道什么是Unicode,那么,可能不需要了解这些内容(如果希望了解更多的信息,可以访问Unicode的网站。Python中的普通字符串在内部是以18位的ASCII码形成存储的,而Unicode字符串则存储为16位的Unicode字符,这样就能够表示更多的字符集了,包括世界上大多数语言的特殊字符。本节不会详细讲述Unicode字符串,仅举一下的例子来说明:

>>> u"Hello, world!"
u'Hello, world!'

可以看到,Unicode字符串使用u前缀,就像原始字符串使用r一样。

注:在Python 3.0中,所有字符串都是Unicode字符串。

1.12 小结

本章讲了非常多的内容。在继续下一章之前,先来看一下本章都学到了什么。

√ 算法。算法是对如何完成一项任务的详尽描述。实际上,在编写程序的时候,就是要使用计算机能够理解的语言(如Python)来描述算法。这类对机器友好的描述就叫做程序,程序主要包含表达式和语句。

√ 表达式。表达式是计算机程序的组成部分,它用于表示值。距离来说,2+2是表达式,表示数值4。简单的表达式就是通过使用运算符(如+或%)和函数(如pow)对字面值(比如2或者"Hello")进行处理而构建起来的。通过把简单的表达式联合起来可以建立更加复杂的表达式(如(2+2)*(3-1))。表达式也可以包含变量

√ 变量。变量是一个名字,它表示某个值。通过x=2这样的赋值可以为变量赋予新的值。赋值也是一类语句

√ 语句。语句是告诉计算机做某些事情的指令。它可能涉及改变变量(通过赋值)、向屏幕打印内容(如print "Hello, world!")、导入模块或者许多其他操作。

√ 函数。Python中的函数就像数学中的函数:它们可以带有参数,并且返回值(第六章会介绍如何编写自定义函数)。

√ 模块。模块是一些对Python功能的扩展,它可以被导入到Python中。例如,math模块提供了很多有用的数学函数。

√ 程序。本章之前的内容已经介绍过编写、保存和运行Python程序的实际操作了。

√ 字符串。字符串非常简单——就是文本片段,不过,还有很多与字符串相关的知识需要了解。在本章中,你已经看到很多种书写字符串的方法。第三章将会介绍更多字符串的使用方式。

1.12.1 本章的新函数

abs(number)                        返回数字的绝对值
cmath.sqrt(number)                 返回平方根,也可以应用于负数
float(object)                      将字符串和数字转换为浮点数
help()                             提供交互式帮助
input(prompt)                      获取用户输入
int(object)                        将字符串和数字转换为整数
long(object)                       将字符串和数字转换为长整型数
math.ceil(number)                  返回数的上入整数,返回值的类型为浮点数
math.floor(number)                 返回数的下入整数,返回值的类型为浮点数
math.sqrt(number)                  返回平方根,不适用于负数
pow(x, y[, z])                     返回x的y次方幂(所得结果对z取模)
raw_input(prompt)                  获取用户输入,结果被看做原始字符
repr(object)                       返回值的字符串表示形式
round(number[, ndigits)            根据给定的精度对数字进行四舍五入
str(object)                        将值转换为字符串

1.12.2 接下来学什么

表达式的基础知识已经讲解完毕,接下来要探讨更高级一点的内容:数据结构。你将学习到如何不再直接和简单的值(如数字)打交道,而是把它们集中起来处理,存储在更加复杂的结构中,如列表(list)和字典(dictionary)。另外,我们还将深入了解字符串。在第五章中,将会介绍更多关于语句的知识。之后,编写漂亮的程序就手到擒来了。

results matching ""

    No results matching ""