💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
### 3. Python简介 以下的示例中,输入和输出通过是否存在提示符([*>>>*](#)和[*...*](#))来区分:如果要重复该示例,你必须在提示符出现后,输入提示符后面的所有内容;没有以提示符开头的行是解释器的输出。注意示例中出现从提示符意味着你一定要在最后加上一个空行;这用于结束一个多行命令。 本手册中的很多示例,甚至在交互方式下输入的示例,都带有注释。Python中的注释以哈希字符#开始,直至实际的行尾。注释可以从行首开始,也可以跟在空白或代码之后,但不能包含在字符串字面量中。字符串字面量中的#字符仅仅表示#。因为注释只是为了解释代码并且不会被Python解释器解释,所以敲入示例的时候可以忽略它们。 例如: ~~~ # this is the first comment spam = 1 # and this is the second comment # ... and now a third! text = "# This is not a comment because it's inside quotes." ~~~ ### 3.1. 用Python作为计算器 让我们尝试一些简单的Python命令。启动解释器然后等待主提示符 >>>。(应该不需要很久。) #### 3.1.1. 数字 解释器可作为一个简单的计算器:你可以向它输入一个表达式,它将返回其结果。表达式语法很直白:运算符+、-、*和/的用法就和其它大部分语言一样(例如Pascal或C);括号(())可以用来分组。例如: ~~~ >>> 2 + 2 4 >>> 50 - 5*6 20 >>> (50 - 5.0*6) / 4 5.0 >>> 8 / 5.0 1.6 ~~~ 整数(例如2,4,20)的类型是[int](# "int"),带有小数部分的数字(例如5.0, 1.6)的类型是[float](# "float")。在本教程的后面我们会看到更多关于数字类型的内容。 除法(/)返回的类型取决于它的操作数。如果两个操作数都是[int](# "int"),将采用[*floor除法(floor division)*](#)并返回一个[int](# "int")。如果两个操作数中有一个是[float](# "float"),将采用传统的除法并返回一个[float](# "float")。还提供//运算符用于floor division 而无论操作数是什么类型。余数可以用%操作符计算: ~~~ >>> 17 / 3 # int / int -> int 5 >>> 17 / 3.0 # int / float -> float 5.666666666666667 >>> 17 // 3.0 # explicit floor division discards the fractional part 5.0 >>> 17 % 3 # the % operator returns the remainder of the division 2 >>> 5 * 3 + 2 # result * divisor + remainder 17 ~~~ 通过Python,还可以使用**运算符计算幂乘方[[1]](#): ~~~ >>> 5 ** 2 # 5 squared 25 >>> 2 ** 7 # 2 to the power of 7 128 ~~~ 等号(=)用于给变量赋值。赋值之后,在下一个提示符之前不会有任何结果显示: ~~~ >>> width = 20 >>> height = 5*9 >>> width * height 900 ~~~ 如果变量没有“定义”(赋值),使用的时候将会报错: ~~~ >>> n # try to access an undefined variable Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'n' is not defined ~~~ Python中完全支持浮点数;整数和浮点数的混合计算中,整数会被转换为浮点数: ~~~ >>> 3 * 3.75 / 1.5 7.5 >>> 7.0 / 2 3.5 ~~~ 在交互模式下,最近一次表达式的值被赋给变量_。这意味着把Python当做桌面计算器使用的时候,可以方便的进行连续计算,例如: ~~~ >>> tax = 12.5 / 100 >>> price = 100.50 >>> price * tax 12.5625 >>> price + _ 113.0625 >>> round(_, 2) 113.06 ~~~ 用户应该将这个变量视为只读的。不要试图去给它赋值 — 你将会创建出一个独立的同名局部变量,并且屏蔽了内置变量的魔术效果。 除了[int](# "int")和[float](# "float"),Python还支持其它数字类型,例如[Decimal](# "decimal.Decimal")and[Fraction](# "fractions.Fraction")。Python还内建支持[*复数*](#),使用后缀j或J表示虚数部分(例如3+5j)。 #### 3.1.2. 字符串 除了数值,Python 还可以操作字符串,可以用几种方法来表示。它们可以用单引号('...')或双引号("...")括起来,效果是一样的[[2]](#)。\可以用来转义引号。 ~~~ >>> 'spam eggs' # single quotes 'spam eggs' >>> 'doesn\'t' # use \' to escape the single quote... "doesn't" >>> "doesn't" # ...or use double quotes instead "doesn't" >>> '"Yes," he said.' '"Yes," he said.' >>> "\"Yes,\" he said." '"Yes," he said.' >>> '"Isn\'t," she said.' '"Isn\'t," she said.' ~~~ 在交互式解释器中,输出的字符串会用引号引起来,特殊字符会用反斜杠转义。虽然可能和输入看上去不太一样,但是两个字符串是相等的。如果字符串中只有单引号而没有双引号,就用双引号引用,否则用单引号引用。 ~~~ >>> '"Isn\'t," she said.' '"Isn\'t," she said.' >>> print '"Isn\'t," she said.' "Isn't," she said. >>> s = 'First line.\nSecond line.' # \n means newline >>> s # without print(), \n is included in the output 'First line.\nSecond line.' >>> print s # with print, \n produces a new line First line. Second line. ~~~ 如果你前面带有\的字符被当作特殊字符,你可以使用*原始字符串*,方法是在第一个引号前面加上一个r: ~~~ >>> print 'C:\some\name' # here \n means newline! C:\some ame >>> print r'C:\some\name' # note the r before the quote C:\some\name ~~~ 字符串可以跨多行。一种方法是使用三引号:"""..."""或者'''...'''。行尾换行符会被自动包含到字符串中,但是可以在行尾加上\来避免这个行为。下面的示例: ~~~ 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 ~~~ 字符串可以用+操作符连接,也可以用*操作符重复多次: ~~~ >>> # 3 times 'un', followed by 'ium' >>> 3 * 'un' + 'ium' 'unununium' ~~~ 相邻的两个或多个*字符串字面量*(用引号引起来的)会自动连接。 ~~~ >>> 'Py' 'thon' 'Python' ~~~ 然而这种方式只对两个字面量有效,变量或者表达式是不行的。 ~~~ >>> prefix = 'Py' >>> prefix 'thon' # can't concatenate a variable and a string literal ... SyntaxError: invalid syntax >>> ('un' * 3) 'ium' ... SyntaxError: invalid syntax ~~~ 如果你想连接多个变量或者连接一个变量和一个字面量,使用+: ~~~ >>> prefix + 'thon' 'Python' ~~~ 这个功能在你想切分很长的字符串的时候特别有用: ~~~ >>> text = ('Put several strings within parentheses ' 'to have them joined together.') >>> text 'Put several strings within parentheses to have them joined together.' ~~~ 字符串可以*索引*,第一个字符的索引值为0。Python没有单独的字符类型;一个字符就是一个简单的长度为1的字符串。 ~~~ >>> word = 'Python' >>> word[0] # character in position 0 'P' >>> word[5] # character in position 5 'n' ~~~ 索引也可以是负值,此时从右侧开始计数: ~~~ >>> word[-1] # last character 'n' >>> word[-2] # second-last character 'o' >>> word[-6] 'P' ~~~ 注意,因为-0和0是一样的,负的索引从-1开始。 除了索引,还支持*切片*。索引用于获得单个字符,*切片*让你获得一个子字符串。 ~~~ >>> word[0:2] # characters from position 0 (included) to 2 (excluded) 'Py' >>> word[2:5] # characters from position 2 (included) to 5 (excluded) 'tho' ~~~ 注意,包含起始的字符,不包含末尾的字符。这使得s[:i]+s[i:]永远等于s: ~~~ >>> word[:2] + word[2:] 'Python' >>> word[:4] + word[4:] 'Python' ~~~ 切片的索引有非常有用的默认值;省略的第一个索引默认为零,省略的第二个索引默认为切片的字符串的大小。 ~~~ >>> word[:2] # character from the beginning to position 2 (excluded) 'Py' >>> word[4:] # characters from position 4 (included) to the end 'on' >>> word[-2:] # characters from the second-last (included) to the end 'on' ~~~ 有个方法可以记住切片的工作方式,把索引当做字符*之间*的点,第一个字符的左边是0。含有*n*个字符的字符串的最后一个字符的右边是索引*n*,例如: ~~~ +---+---+---+---+---+---+ | P | y | t | h | o | n | +---+---+---+---+---+---+ 0 1 2 3 4 5 6 -6 -5 -4 -3 -2 -1 ~~~ 第一行给出了字符串中0..6各索引的位置;第二行给出了相应的负索引。从*i*到*j*的切片由*i*和*j*之间的所有字符组成。 对于非负索引,如果上下都在边界内,切片长度就是两个索引之差。例如,word[1:3] 的长度是 2。 试图使用太大的索引会导致错误: ~~~ >>> word[42] # the word only has 7 characters Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: string index out of range ~~~ 但是,当用于切片时,超出范围的切片索引会被优雅地处理: ~~~ >>> word[4:42] 'on' >>> word[42:] '' ~~~ Python字符串不可以被更改 — 它们是[*不可变的*](#)。因此,赋值给字符串索引的位置会导致错误: ~~~ >>> word[0] = 'J' ... TypeError: 'str' object does not support item assignment >>> word[2:] = 'py' ... TypeError: 'str' object does not support item assignment ~~~ 如果你需要一个不同的字符串,你应该创建一个新的: ~~~ >>> 'J' + word[1:] 'Jython' >>> word[:2] + 'py' 'Pypy' ~~~ 内置函数[len()](# "len")返回字符串的长度: ~~~ >>> s = 'supercalifragilisticexpialidocious' >>> len(s) 34 ~~~ 请参阅 [*序列类型 — str, unicode, list, tuple, bytearray, buffer, xrange*](#)字符串和下节描述的Unicode字符串是*序列类型*的例子,它们支持这种类型共同的操作。[*字符串方法*](#)字符串和Unicode字符串都支持大量的方法用于基本的转换和查找。[*字符串格式化*](#)这里描述了使用[str.format()](# "str.format")进行字符串格式化的信息。[*字符串格式化操作*](#)这里描述了旧式的字符串格式化操作,它们在字符串和Unicode字符串是%操作符的左操作数时调用。 #### 3.1.3. Unicode 字符串 从Python2.0开始,程序员们有了一个新的用来存储文本数据的类型:Unicode对象。它可以用来存储和处理Unicode数据(见[http://www.unicode.org/](http://www.unicode.org/)),并与现有的字符串对象有良好的集成,必要时提供自动转换。 Unicode 的优点在于为现代和古代的每一种文字的每一个字符提供了统一的序号。以前,脚本只有256个可用的字符编码。通常,文本被绑定到映射字符编码的代码页上。这带来很多麻烦,尤其是软件国际化(通常写成i18n — 'i' + 18个字符 + 'n')。Unicode 为所有脚本定义一个代码页,从而解决了这些问题。 在Python中创建Unicode字符串和创建普通字符串一样简单: ~~~ >>> u'Hello World !' u'Hello World !' ~~~ 引号前面小写的'u'表示创建一个Unicode字符串。如果你想要在字符串中包含特殊字符,你可以通过使用Python的*Unicode转义*编码。下面的示例演示如何使用: ~~~ >>> u'Hello\u0020World !' u'Hello World !' ~~~ 转义序列u0020表示在给定位置插入序号值为0x0020(空格字符)的Unicode字符。 其他字符就像 Unicode 编码一样被直接解释为对应的编码值。如果你有使用在许多西方国家使用的标准Latin-1编码的字符串,你会发现编码小于256的Unicode字符和在Latin-1编码中的一样。 和普通字符串一样,Unicode字符串也有raw模式。要使用*Raw-Unicode-Escape*编码,必须在引号的前面加上'ur'。只有在小写的'u'前面有奇数个反斜杠,才会用上面的uXXXX 转换 ~~~ >>> ur'Hello\u0020World !' u'Hello World !' >>> ur'Hello\\u0020World !' u'Hello\\\\u0020World !' ~~~ 当你需要输入很多反斜杠时,raw 模式非常有用,这在正则表达式中几乎是必须的。 除了这些标准的编码,Python提供了基于已知编码来创建Unicode字符串的一整套方法。 内置函数[unicode()](# "unicode")提供对所有已注册的Unicode编解码器(编码和解码)的访问。这些编解码器可以转换的比较有名的编码有*Latin-1*、*ASCII*、*UTF-8*和*UTF-16*。后两个是可变长度编码,它们存储每个Unicode字符在一个或多个字节中。默认编码通常设置为ASCII,此编码接受0到127这个范围的编码,否则报错。当打印、向文件写入、或者用[str()](# "str")转换一个Unicode字符串时,转换将使用默认编码。 ~~~ >>> 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")函数并以编码名作为第二个参数。 ~~~ >>> unicode('\xc3\xa4\xc3\xb6\xc3\xbc', 'utf-8') u'\xe4\xf6\xfc' ~~~ #### 3.1.4. 列表 Python有几个*复合*数据类型,用来组合其他的值。最有用的是*列表*,可以写成中括号中的一列用逗号分隔的值。列表可以包含不同类型的元素,但是通常所有的元素都具有相同的类型。 ~~~ >>> squares = [1, 4, 9, 16, 25] >>> squares [1, 4, 9, 16, 25] ~~~ 和字符串(以及其它所有内建的[*序列*](#)类型)一样,列表可以索引和切片: ~~~ >>> squares[0] # indexing returns the item 1 >>> squares[-1] 25 >>> squares[-3:] # slicing returns a new list [9, 16, 25] ~~~ 所有的切片操作都会返回一个包含请求的元素的新列表。这意味着下面的切片操作返回列表一个新的(浅)拷贝副本。 ~~~ >>> squares[:] [1, 4, 9, 16, 25] ~~~ 列表也支持连接这样的操作: ~~~ >>> squares + [36, 49, 64, 81, 100] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] ~~~ 与字符串的[*不可变*](#)特性不同,列表是[*可变的*](#)类型,例如可以改变它们的内容: ~~~ >>> cubes = [1, 8, 27, 65, 125] # something's wrong here >>> 4 ** 3 # the cube of 4 is 64, not 65! 64 >>> cubes[3] = 64 # replace the wrong value >>> cubes [1, 8, 27, 64, 125] ~~~ 你还可以使用append()*方法*(后面我们会看到更多关于方法的内容)在列表的末尾添加新的元素: ~~~ >>> cubes.append(216) # add the cube of 6 >>> cubes.append(7 ** 3) # and the cube of 7 >>> cubes [1, 8, 27, 64, 125, 216, 343] ~~~ 给切片赋值也是可以的,此操作甚至可以改变列表的大小或者清空它:: ~~~ >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> letters ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> # replace some values >>> letters[2:5] = ['C', 'D', 'E'] >>> letters ['a', 'b', 'C', 'D', 'E', 'f', 'g'] >>> # now remove them >>> letters[2:5] = [] >>> letters ['a', 'b', 'f', 'g'] >>> # clear the list by replacing all the elements with an empty list >>> letters[:] = [] >>> letters [] ~~~ 内置函数[len()](# "len")也适用于列表: ~~~ >>> letters = ['a', 'b', 'c', 'd'] >>> len(letters) 4 ~~~ 列表可以嵌套(创建包含其他列表的列表),例如: ~~~ >>> a = ['a', 'b', 'c'] >>> n = [1, 2, 3] >>> x = [a, n] >>> x [['a', 'b', 'c'], [1, 2, 3]] >>> x[0] ['a', 'b', 'c'] >>> x[0][1] 'b' ~~~ ### 3.2. 编程第一步 当然,我们可以将Python用于比计算2加2更复杂的任务。例如,我们可以写一个生成*斐波那契*初始子序列的程序,如下所示: ~~~ >>> # 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一样,任何非零整数值都为真;零为假。循环条件也可以是一个字符串或者列表,实际上可以是任何序列;长度不为零的序列为真,空序列为假。示例中使用的测试是一个简单的比较。标准比较运算符与 C 的写法一样:<(小于),>(大于),==(等于),<=(小于或等于),>=(大于或等于)和!=(不等于)。 - 循环*体*是*缩进* 的:缩进是Python分组语句的方式。交互式输入时,你必须为每个缩进的行输入一个 tab 或(多个)空格。实践中你会用文本编辑器来编写复杂的 Python 程序;所有说得过去的文本编辑器都有自动缩进的功能。交互式输入复合语句时,最后必须在跟随一个空行来表示结束(因为解析器无法猜测你什么时候已经输入最后一行)。注意基本块内的每一行必须按相同的量缩进。 - [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 ~~~ 注意,如果最后一行没有结束,解释器会插入一个新行(在打印下一个提示符之前)。 脚注 | [[1]](#) | 因为**的优先级高于-,所以-3**2将解释为-(3**2)且结果为-9。为了避免这点并得到9,你可以使用(-3)**2。 | |-----|-----| | [[2]](#) | 与其它语言不同,特殊字符例如\n在单引号('...')和双引号("...")中具有相同的含义。两者唯一的区别是在单引号中,你不需要转义"(但你必须转义\'),反之亦然。 | |-----|-----|