3 Python非正式介绍
在以下的例子中,有提示符(>>>,…)的行表示输入,没有的行表示输出。为了重复示例,你需要输入提示符后所有的命令。没有提示符的行是解释器的输出。注意副提示符单独出现在一行表示你需要输入一个空行以结束一个多行命令。
Python手册中的很多示例,包括在交互模式下输入的命令都带有注释。Python中的注释以#开头,并一直延续到行末。一个注释会出现在一行的开始或者在空格或者代码之后,但不会在字符串中出现。字符串中的#只是一个#字符。
一些例子:
# this is the first comment
SPAM = 1 # and this is the second comment
# ... and now a third!
STRING = "# This is not a comment."
3.1把Python当作计算器
让我们尝试一些简单的Python命令。启动解释器并等待第一个提示符”>>>”出现。(不会花很长时间)。
3.1.1 数字
解释器就像一个简单的计算器:你输入表达式,解释器输出结果。表达式语法是很直观的:+,-,*,/的作用就和它们在绝大多数其它语言中一样(例如Pascal和C)。可以使用圆括号来分组。例如:
>>> 2+2
4
>>> # This is a comment
... 2+2
4
>>> 2+2 # and a comment on the same line as code
4
>>> (50-5*6)/4
5
>>> # Integer division returns the floor:
... 7/3
2
>>> 7/-3
-3
等号用来为变量赋值。因此,在下一个提示符前没有结果显示:
>>> width = 20
>>> height = 5*9
>>> width * height
900
一个值可以同时被赋给多个变量:
>>> x = y = z = 0 # Zero x, y and z
>>> x
0
>>> y
0
>>> z
0
Python有很好的浮点数支持:不同类型的操作数混合计算会把整数转换为浮点数:
>>> 3 * 3.75 / 1.5
7.5
>>> 7.0 / 2
3.5
Python也支持复数。虚部用后缀”j”或者”J”表示。实部非零的实数写作 “(实部+虚部j)”。也可以通过函数”complex(real, imag)”创建。
>>> 1j * 1J
(-1+0j)
>>> 1j * complex(0,1)
(-1+0j)
>>> 3+1j*3
(3+3j)
>>> (3+1j)*3
(9+3j)
>>> (1+2j)/(1+1j)
(1.5+0.5j)
复数总是以两个浮点数实部和虚部表示。用z.real和z.imag可以从复数Z中得到这两部分。
>>> a=1.5+0.5j
>>> a.real
1.5
>>> a.imag
0.5
浮点和整型转化函数(float(),int(),long())对复数无效—没有一种正确的办法可以把一个复数转化为实数。用abs(z)来获得z的模,一个浮点数。或者z.real来获得z的实部。
>>> a=3.0+4.0j
>>> float(a)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: can't convert complex to float; use abs(z)
>>> a.real
3.0
>>> a.imag
4.0
>>> abs(a) # sqrt(a.real**2 + a.imag**2)
5.0
>>>
在交互模式下,最后一个打印出的表达式赋给变量_。这有些时候会使你下面的计算变得简单。例如:
>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _
113.0625
>>> round(_, 2)
113.06
>>>
_应当被当作只读变量。不要明确的给它赋值。否则你会得到一个同名的局部变量,它将会屏蔽掉系统内置的变量。
3.1.2 字符串
Python除了数字还能操纵字符串。字符串有多种表示方式。它们可以被单引号或双引号引起来:
>>> 'spam eggs'
'spam eggs'
>>> 'doesn/'t'
"doesn't"
>>> "doesn't"
"doesn't"
>>> '"Yes," he said.'
'"Yes," he said.'
>>> "/"Yes,/" he said."
'"Yes," he said.'
>>> '"Isn/'t," she said.'
'"Isn/'t," she said.'
有几种方法可以让字符串跨越多行。可以在行尾加上反斜线表示下一行是当前行的继续
hello = "This is a rather long string containing/n/
several lines of text just as you would do in C./n/
Note that whitespace at the beginning of the line is/
significant."
print hello
请注意新行仍然需要用字符串中的换行符/n表示。行末反斜线后的换行会被忽略。上面的例子会打印出以下结果:
This is a rather long string containing
several lines of text just as you would do in C.
Note that whitespace at the beginning of the line is significant.
如果我们使用原生字符串(raw string),/n则不会被转化为换行,行末的反斜线和换行符都会成为字符串的一部分。因此下面的代码
hello = r"This is a rather long string containing/n/
several lines of text much as you would do in C."
print hello
会输出
This is a rather long string containing/n/
several lines of text much as you would do in C.
还有,字符串可以用匹配的三个引号包围('''或者""")。这时每行结尾不需要再加反斜线。但所有的换行都会出现在字符串中。
print """
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
"""
会输出:
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
解释器会像输入的格式一样打印出字符串操作的结果:包含引号和其它用反斜线转义的特殊字符来表示精确的值。如果字符串中有单引号而没有双引号输出会被双引号引起,否则会被单引号引起。(后面讨论的print语句会输出不含引号或转义符的结果)。
可以用+操作来连接字符串,用*表示重复。
>>> word = 'Help' + 'A'
>>> word
'HelpA'
>>> '<' + word*5 + '>'
'<HelpAHelpAHelpAHelpAHelpA>'
两个相邻的字符串会自动连接为一个。上面例子的第一行也可以写成word = 'help' 'A'。这只对字符串有效,对其它字符串表达式无效。
>>> 'str' 'ing' # <- This is ok
'string'
>>> 'str'.strip() + 'ing' # <- This is ok
'string'
>>> 'str'.strip() 'ing' # <- This is invalid
File "<stdin>", line 1, in ?
'str'.strip() 'ing'
^
SyntaxError: invalid syntax
字符串可以被索引。像C一样,第一个字符下标为0。没有独立的字符类型。一个字符就是一个长度为1的字符串。像Icon语言[U1] 中一样你可以用:来表示切片(Slice):两个用冒号隔开的序号。
>>> word[4]
'A'
>>> word[0:2]
'He'
>>> word[2:4]
'lp'
切片中的序号的缺省值很有用。第一个序号缺省为0,后一个序号缺省为字符串长度。
>>> word[:2] # The first two characters
'He'
>>> word[2:] # Everything except the first two characters
'lpA'
和C不同的是Python中的字符串是不可变的。为字符串中一个索引位置赋值会引发一个错误:
>>> word[0] = 'x'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment
>>> word[:1] = 'Splat'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesn't support slice assignment
但是通过合并内容创建新的字符串是简单而高效的:
>>> 'x' + word[1:]
'xelpA'
>>> 'Splat' + word[4]
'SplatA'
有一个有用的字符串恒等式:s[:i]+s[i:]等于s[U2]
>>> word[:2] + word[2:]
'HelpA'
>>> word[:3] + word[3:]
'HelpA'
退化的切片索引也能得到很好的处理:过大的索引会被字符串长度代替,上界比下界小的切片会返回一个空串。
>>> word[1:100]
'elpA'
>>> word[10:]
''
>>> word[2:1]
''
索引可以是负数,表示从右端开始计算:
>>> word[-1] # The last character
'A'
>>> word[-2] # The last-but-one character
'p'
>>> word[-2:] # The last two characters
'pA'
>>> word[:-2] # Everything except the last two characters
'Hel'
但请注意-0和0一样,不会从右端计算。
>>> word[-0] # (since -0 equals 0)
'H'
超出范围的负索引会被截断。但不要在非切片的索引上用越界的负数:
>>> word[-100:]
'HelpA'
>>> word[-10] # error
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IndexError: string index out of range
最好的记住切片工作原理的办法是把索引当作字符中的标点。最左侧标点序号为0,长度为n的串最右侧标点序号为n,例如:
+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1
第一行数字给出了索引0到5的位置;第二行给出了对应的负索引。从i到j的切片包含了标点i,j之间所有的字符。
对非负索引,切片的长度就是索引的差值,如果两个索引都没有越界的话。例如,word[1:3]的长度为2。
内置函数len()返回字符串长度。
>>> s = 'supercalifragilisticexpialidocious'
>>> len(s)
34
参见:
序列类型:
字符串和下一节中的Unicode类型的字符串都属于序列类型,支持序列类型支持的共同操作。
字符串方法:
字符串和Unicode字符串都支持大量基本的转换和搜索方法。
字符串格式化操作
当字符串或Unicode字符串在%操作符左侧时会调用格式化操作。
3.1.3 Unicode字符串
从Python2.0开始,为程序员引入一种新的可以存储文本数据的数据类型:Unicode对象。它可以用来操作Unicode数据(参见http://www.unicode.org/)并且和现有的字符串对象集成的很好,需要时可以进行自动转换。
Unicode能为以现代或者古代文本写成的每个脚本中的每个字符提供唯一的序号(ordinal)。以前脚本中的字符只有256个可用的序号。文本通常绑定到一个code page,再映射到脚本中的字符。这会引起严重的混乱,特别在处理软件国际化问题时(internationalization通常写作"i18n", "i" + 18字符 + "n")。Unicode通过为所有脚本定义一个code page来解决这些问题。
在Python中创建一个Unicode字符串就和创建一个普通字符串一样容易。
>>> u'Hello World !'
u'Hello World !'
引号前的小写"u"表示创建一个Unicode字符串。你可以用Python的Unicode转义编码来嵌入一些特殊字符。下面的例子演示了怎样做:
>>> u'Hello/u0020World !'
u'Hello World !'
转移序列/u0020表示在该位置插入序号为0x0020(空格)的字符。
其它的字符也可以用对应的转义字符来表示。如果你的字符串使用大多数西方国家使用的标准Latin-1编码,你会发现Unicode的前256个字符和Latin-1字符相同是一件很方便的事。
对专家而言,也有一种和普通字符串类似的原生模式。在引号前加ur能让Python使用原生Unicode转义编码。只对u前面有奇数个反斜线的/uxxxx进行转义。
>>>
ur
'Hello/u0020World !'
u'Hello World !'
>>>
ur
'Hello//u0020World !'
u'Hello////u0020World !'
大量输入反斜线的场合最能发挥原生模式作用,例如在正则表达式中。
除了这些标准编码以外,Python还提供一整套其它的方法来通过已知的编码创建Unicode字符串。
内置函数unicode()提供对所有已注册的Unicode译码器的访问(编码器和解码器)。其中一些著名的编码有Latin-1,ASCII,UTF-8和UTF-16。后两种编码是变长的,每个Unicode字符以一个或多个字节表示。缺省的ASCII编码只接受0到127的字符。当一个Unicode字符串被打印,写入文件或者用str()转换时,都会使用缺省编码。
>>> u"abc"
u'abc'
>>> str(u"abc")
'abc'
>>> u"äöü"
u'/xe4/xf6/xfc'
>>> str(u"äöü")
Traceback (most recent call last):
File "<stdin>", line 1, in ?
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
Unicode对象提供了encode()方法用以把Unicode字符串转化为特定编码的8比特字符串。该方法接受一个编码名参数。编码名鼓励用小写。
>>> u"äöü".encode('utf-8')
'/xc3/xa4/xc3/xb6/xc3/xbc'
如果你需要从特定编码的字符串产生对应的Unicode字符串,可以用unicode()函数并以编码名作为第二个参数。
>>> unicode('/xc3/xa4/xc3/xb6/xc3/xbc', 'utf-8')
u'/xe4/xf6/xfc'
3.1.4 列表
Python有很多用来组织其它数据的数据类型。功能最多的就是列表。列表可以写成用一系列用逗号分开的值(元素),最外层用方括号包围。列表的元素不需要都是同类型的。
>>> a = ['spam', 'eggs', 100, 1234]
>>> a
['spam', 'eggs', 100, 1234]
和字符串一样,列表的索引从0开始,支持切片,连接和其它操作:
>>> a[0]
'spam'
>>> a[3]
1234
>>> a[-2]
100
>>> a[1:-1]
['eggs', 100]
>>> a[:2] + ['bacon', 2*2]
['spam', 'eggs', 'bacon', 4]
>>> 3*a[:3] + ['Boo!']
['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boo!']
不一样的一点是,字符串是不可变的,列表的元素则是可以改变的:
>>> a
['spam', 'eggs', 100, 1234]
>>> a[2] = a[2] + 23
>>> a
['spam', 'eggs', 123, 1234]
为切片赋值也是合法的,这甚至能改变列表的长度或者清空列表:
>>> # Replace some items:
... a[0:2] = [1, 12]
>>> a
[1, 12, 123, 1234]
>>> # Remove some:
... a[0:2] = []
>>> a
[123, 1234]
>>> # Insert some:
... a[1:1] = ['bletch', 'xyzzy']
>>> a
[123, 'bletch', 'xyzzy', 1234]
>>> # Insert (a copy of) itself at the beginning
>>> a[:0] = a
>>> a
[123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234]
>>> # Clear the list: replace all items with an empty list
>>> a[:] = []
>>> a
[]
内置函数len()也能应用到列表上:
>>> len(a)
8
嵌套列表也是合法的(创建包含其它列表的列表),例如:
>>> q = [2, 3]
>>> p = [1, q, 4]
>>> len(p)
3
>>> p[1]
[2, 3]
>>> p[1][0]
2
>>> p[1].append('xtra') # See section 5.1
>>> p
[1, [2, 3, 'xtra'], 4]
>>> q
[2, 3, 'xtra']
注意在最后的例子里,p[1]和q指向同一个对象。我们稍后再讨论对象的含义。
3.2通向编程的第一步
当然,我们能用Python完成比2加2更复杂的任务。例如我们能得到Fibonacci数列的前面一部分:
>>> # Fibonacci series:
... # the sum of two elements defines the next
... a, b = 0, 1
>>> while b < 10:
... print b
... a, b = b, a+b
...
1
1
2
3
5
8
这个例子引入了一些新的特性:
第一行有一个多重赋值:变量a,b同时获得新值0和1。最后一行再次出现多重赋值。在复制操作之前右侧的表达式先被全部计算求值。右侧表达式从左到右被求值。
当判定条件(这里是b<10)为真时while循环一直执行。在Python中和C一样,任何非零整数都是真,0是假。判定条件也可是字符串或者列表乃至任何序列;任何长度非零的对象都是真,空序列是假。示例中使用了简单的比较。标准比较操作符和C中一样:<(小于),>(大于),==(相等),<=(小于等于),>=(大于等于)和!=(不等于)。
循环体是缩进的:缩进是Python组织复合语句的方法。Python暂时还没有提供输入行智能编辑的功能,你需要为每个缩进行键入一个tab或者几个空格。实际上在文本编辑器中你可以进行更复杂的输入。很多文本编辑器有自动缩进的功能。交互输入复合语句时必须输入一个空行表示结束(因为解释器不知道你输入到了最后一行)。请注意同一个基本块中的每一行必须有相同的缩进。
print语句输出它右边表达式的值。和直接输出表达式不同之处在于对多个表达式和字符串的处理。print输出字符串时不会加上引号,并且会在每个输出项之间加上空格,使你能更好的格式化字符串。例如:
· >>> i = 256*256
· >>> print 'The value of i is', i
· The value of i is 65536
末尾的逗号能取消输出后的换行:
>>> a, b = 0, 1
>>> while b < 1000:
... print b,
... a, b = b, a+b
...
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
请注意如果上一行没有结束,解释器会在打印下一个提示符前插入一个换行符。