合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
# 第一章 快速改造:基础知识 > 来源: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/3`得`3`是因为结果被向下取整了。而`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*2`是`4`,而`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`的结果就是`x`和`y`的乘积。所以,可以在程序中通过多种方法来使用变量,而不需要知道在程序运行的时候,最终存储(或引用)的值到底是什么。 ## 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提示符(`>>>`)后面的语句可以算作一个完整程序的组成部分了,输入的值(`16`和`31`)有用户提供,而程序就会打印出输入的两个数的乘积`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 ``` _注:还有类似的函数可以将输入数转换为其他类型(比如`long`和`float`)。事实上,他并不完全是普通的函数——它们是类型对象(`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 + "!" ``` _注:不用管`input`和`raw_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表达式的形式来表示值(事实上,`str`和`int`、`long`一样,是一种类型。而`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`。) 简而言之,`str`、`repr`和反引号是将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`的网站](http://www.unicode.org)。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)。另外,我们还将深入了解字符串。在第五章中,将会介绍更多关于语句的知识。之后,编写漂亮的程序就手到擒来了。