Python 基本元素:数字、字符串和变量

Published on 2017 - 01 - 20

这些类型包括:

  • 布尔型(表示真假的类型,仅包含 True 和 False 两种取值)
  • 整型(整数,例如 42、100000000)
  • 浮点型(小数,例如 3.14159,或用科学计数法表示的数字,例如 1.0e8,它表示 1 乘以 10 的 8 次方,也可写作 100000000.0)
  • 字符串型(字符组成的序列)

变量、名字和对象

Python 里所有数据——布尔值、整数、浮点数、字符串,甚至大型数据结构、函数以及程序——都是以对象(object)的形式存在的。这使得 Python 语言具有很强的统一性(还有许多其他有用的特性),而这恰恰是许多其他语言所缺少的。

对象就像一个塑料盒子,里面装的是数据。对象有不同类型,例如布尔型和整型,类型决定了可以对它进行的操作。现实生活中的“陶器”会暗含一些信息(例如它可能很重,注意不要掉到地上,等等)。类似地,Python 中一个类型为 int 的对象会告诉你:可以把它与另一个 int 对象相加。

对象的类型还决定了它装着的数据是允许被修改的变量(可变的)还是不可被修改的常量(不可变的)。你可以把不可变对象想象成一个透明但封闭的盒子:你可以看到里面装的数据,但是无法改变它。类似地,可变对象就像一个开着口的盒子,你不仅可以看到里面的数据,还可以拿出来修改它,但你无法改变这个盒子本身,即你无法改变对象的类型。

Python 是强类型的(strongly typed),你永远无法修改一个已有对象的类型,即使它包含的值是可变的

编程语言允许你定义变量(variable)。所谓变量就是在程序中为了方便地引用内存中的值而为它取的名称。在 Python 中,我们用 = 来给一个变量赋值。

在 Python 中,如果想知道一个对象(例如一个变量或者一个字面值)的类型,可以使用语句:type( thing )。试试对不同的字面值(58、99.9、abc)以及不同的变量(a、b)执行 type 操作:

>>> type(a)
<class 'int'>
>>> type(b)
<class 'int'>
>>> type(58)
<class 'int'>
>>> type(99.9)
<class 'float'>
>>> type('abc')
<class 'str'>

类(class)是对象的定义,在 Python 中,“类”和“类型”一般不加区分。

变量名只能包含以下字符:

  • 小写字母(a~z)
  • 大写字母(A~Z)
  • 数字(0~9)
  • 下划线(_)

名字不允许以数字开头。此外,Python 中以下划线开头的名字有特殊的含义。下面是一些合法的名字:

  • a
  • a1
  • a_b_c___95
  • _abc
  • _1a

下面这些名字则是非法的:

  • 1
  • 1a
  • 1_

最后要注意的是,不要使用下面这些词作为变量名,它们是 Python 保留的关键字:

False      class      finally    is         return
None       continue   for        lambda     try
True       def        from       nonlocal   while
and        del        global     not        with
as         elif       if         or         yield
assert     else       import     pass
break      except     in         raise

这些关键字以及其他的一些标点符号是用于描述 Python 语法的。

数字

Python 本身支持整数(比如 5 和 1000000000)以及浮点数(比如 3.1416、14.99 和 1.87e4)。你可以对这些数字进行下表中的计算。

运算符 描述 示例 运算结果
+ 加法 5 + 8 13
- 减法 90 - 10 80
* 乘法 4 * 7 28
/ 浮点数除法 7 / 2 3.5
// 整数除法 7 // 2 3
% 模(求余) 7 % 3 1
** 3 ** 4 81

接下来会给你展示一些示例,这些示例体现了 Python 作为一个计算机器的非凡特性。

整数

任何仅含数字的序列在 Python 中都被认为是整数:

>>> 5
5

基数

在 Python 中,整数默认使用十进制数(以 10 为底),除非你在数字前添加前缀,显式地指定使用其他基数(base)。也许你永远都不会在自己的代码中用到其他基数,但你很有可能在其他人编写的 Python 代码里见到它们。

基数指的是在必须进位前可以使用的数字的最大数量。以 2 为底(二进制)时,可以使用的数字只有 0 和 1。这里的 0 和十进制的 0 代表的意义相同,1 和十进制的 1 所代表的意义也相同。然而以 2 为底时,1 与 1 相加得到的将是 10(1 个二加 0 个一)。

在 Python 中,除十进制外你还可以使用其他三种进制的数字:

  • 0b 或 0B 代表二进制(以 2 为底)
  • 0o 或 0O 代表八进制(以 8 为底)
  • 0x 或 0X 代表十六进制(以 16 为底)

类型转换

我们可以方便地使用 int() 函数将其他的 Python 数据类型转换为整型。它会保留传入数据的整数部分并舍去小数部分。

Python 里最简单的数据类型是布尔型,它只有两个可选值:True 和 False。当转换为整数时,它们分别代表 1 和 0:

>>> int(True)
1
>>> int(False)
0

当将浮点数转换为整数时,所有小数点后面的部分会被舍去:

>>> int(98.6)
98
>>> int(1.0e4)
10000

也可以将仅包含数字和正负号的字符串转换为整数,下面有几个例子:

>>> int('99')
99
>>> int('-23')
-23
>>> int('+12')
12

如果你试图将一个与数字无关的类型转化为整数,会得到一个异常:

>>> int('99 bottles of beer on the wall')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '99 bottles of beer on the wall'
>>> int('')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: ''

尽管上面例子中的字符串的确是以有效数字(99)开头的,但它没有就此截止,后面的内容不是纯数字,无法被 int() 函数识别,因此抛出异常。

int() 可以接受浮点数或由数字组成的字符串,但无法接受包含小数点或指数的字符串:

>>> int('98.6')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '98.6'
>>> int('1.0e4')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '1.0e4'

一个int型有多大

在 Python 2 里,一个 int 型包含 32 位,可以存储从 -2 147 483 648 到 2 147 483 647 的整数。

一个 long 型会占用更多的空间:64 位,可以存储从 -9 223 372 036 854 775 808 到 9 223 372 036 854 775 807 的整数。

到了 Python 3,long 类型已不复存在,而 int 类型变为可以存储任意大小的整数,甚至超过 64 位。

在许多其他编程语言中,进行类似上面的计算会造成整数溢出,这是因为计算中的数字或结果需要的存储空间超过了计算机所提供的(例如 32 位或 64 位)。在程序编写中,溢出会产生许多负面影响。而 Python 在处理超大数计算方面不会产生任何错误,这也是它的一个加分点。

浮点数

整数全部由数字组成,而浮点数(在 Python 里称为 float)包含非数字的小数点。浮点数与整数很像:你可以使用运算符(+、-、*、/、//、** 和 %)以及 divmod() 函数进行计算。

使用 float() 函数可以将其他数字类型转换为浮点型。与之前一样,布尔型在计算中等价于 1.0 和 0.0:

>>> float(True)
1.0
>>> float(False)
0.0

将整数转换为浮点数仅仅需要添加一个小数点:

>>> float(98)
98.0
>>> float('99')
99.0

此外,也可以将包含有效浮点数(数字、正负号、小数点、指数及指数的前缀 e)的字符串转换为真正的浮点型数字:

>>> float('98.6')
98.6
>>> float('-1.5')
-1.5
>>> float('1.0e4')
10000.0

字符串

对 Unicode 的支持使得 Python 3 可以包含世界上任何书面语言以及许多特殊符号。对于 Unicode 的支持是 Python 3 从 Python 2 分离出来的重要原因之一,也正是这一重要特性促使人们转向使用 Python 3。

字符串型是我们学习的第一个 Python 序列类型,它的本质是字符序列。

与其他语言不同的是,Python 字符串是不可变的。你无法对原字符串进行修改,但可以将字符串的一部分复制到新字符串,来达到相同的修改效果。很快你就会学到如何实现。

使用引号创建

将一系列字符包裹在一对单引号或一对双引号中即可创建字符串,就像下面这样:

>>> 'Snap'
'Snap'
>>> "Crackle"
'Crackle'

交互式解释器输出的字符串永远是用单引号包裹的,但无论使用哪种引号,Python 对字符串的处理方式都是一样的,没有任何区别。

既然如此,为什么要使用两种引号?这么做的好处是可以创建本身就包含引号的字符串,而不用使用转义符。可以在双引号包裹的字符串中使用单引号,或者在单引号包裹的字符串中使用双引号:

>>> "'Nay,' said the naysayer."
"'Nay,' said the naysayer."
>>> 'The rare double quote in captivity: ".'
'The rare double quote in captivity: ".'
>>> 'A "two by four" is actually 1 1/2" × 3 1/2".'
'A "two by four is" actually 1 1/2" × 3 1/2".'
>>> "'There's the man that shot my paw!' cried the limping hound."
"'There's the man that shot my paw!' cried the limping hound."

你还可以使用连续三个单引号 ''',或者三个双引号 """ 创建字符串:

>>> '''Boom!'''
'Boom'
>>> """Eek!"""
'Eek!'

三元引号在创建短字符串时没有什么特殊用处。它多用于创建多行字符串。

使用str()进行类型转换

使用 str() 可以将其他 Python 数据类型转换为字符串:

>>> str(98.6)
'98.6'
>>> str(1.0e4)
'10000.0'
>>> str(True)
'True'

当你调用 print() 函数或者进行字符串差值(string interpolation)时,Python 内部会自动使用 str() 将非字符串对象转换为字符串。

使用\转义

Python 允许你对某些字符进行转义操作,以此来实现一些难以单纯用字符描述的效果。在字符的前面添加反斜线符号 \ 会使该字符的意义发生改变。最常见的转义符是 \n,它代表换行符,便于你在一行内创建多行字符串。

>>> palindrome = 'A man,\nA plan,\nA canal:\nPanama.'
>>> print(palindrome)
A man,
A plan,
A canal:
Panama.

使用+拼接

在 Python 中,你可以使用 + 将多个字符串或字符串变量拼接起来,就像下面这样:

>>> 'Release the kraken! ' + 'At once!'
'Release the kraken! At once!'

也可以直接将一个字面字符串(非字符串变量)放到另一个的后面直接实现拼接:

>>> "My word! " "A gentleman caller!"
'My word! A gentleman caller!'

进行字符串拼接时,Python 并不会自动为你添加空格,需要显示定义。但当我们调用 print() 进行打印时,Python 会在各个参数之间自动添加空格并在结尾添加换行符:

>>> a = 'Duck.'
>>> b = a
>>> c = 'Grey Duck!'
>>> a + b + c
'Duck.Duck.Grey Duck!'
>>> print(a, b, c)
Duck. Duck. Grey Duck!

使用*复制

使用 * 可以进行字符串复制。试着把下面这几行输入到交互式解释器里,看看结果是什么:

>>> start = 'Na ' * 4 + '\n'
>>> middle = 'Hey ' * 3 + '\n'
>>> end = 'Goodbye.'
>>> print(start + start + middle + end)

使用[]提取字符

在字符串名后面添加 [],并在括号里指定偏移量可以提取该位置的单个字符。第一个字符(最左侧)的偏移量为 0,下一个是 1,以此类推。最后一个字符(最右侧)的偏移量也可以用 -1 表示,这样就不必从头数到尾。偏移量从右到左紧接着为 -2、-3,以此类推。

>>> letters = 'abcdefghijklmnopqrstuvwxyz'
>>> letters[0]
'a'
>>> letters[1]
'b'
>>> letters[-1]
'z'
>>> letters[-2]
'y'
>>> letters[25]
'z'
>>> letters[5]
'f'

如果指定的偏移量超过了字符串的长度(记住,偏移量从 0 开始增加到字符串长度 -1),会得到一个异常提醒:

>>> letters[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

使用[start:end:step]分片

分片操作(slice)可以从一个字符串中抽取子字符串(字符串的一部分)。我们使用一对方括号、起始偏移量 start、终止偏移量 end 以及可选的步长 step 来定义一个分片。其中一些可以省略。分片得到的子串包含从 start 开始到 end 之前的全部字符。

  • [:] 提取从开头到结尾的整个字符串
  • [start:] 从 start 提取到结尾
  • [:end] 从开头提取到 end - 1
  • [start:end] 从 start 提取到 end - 1
  • [start:end:step] 从 start 提取到 end - 1,每 step 个字符提取一个

与之前一样,偏移量从左至右从 0、1 开始,依次增加;从右至左从 -1、-2 开始,依次减小。如果省略 start,分片会默认使用偏移量 0(开头);如果省略 end,分片会默认使用偏移量 -1(结尾)。

我们来创建一个由小写字母组成的字符串:

>>> letters = 'abcdefghijklmnopqrstuvwxyz'

仅仅使用 : 分片等价于使用 0 : -1(也就是提取整个字符串):

>>> letters[:]
'abcdefghijklmnopqrstuvwxyz'

下面是一个从偏移量 20 提取到字符串结尾的例子:

>>> letters[20:]
'uvwxyz'

下一个例子提取了偏移量从 12 到 14 的字符(Python 的提取操作不包含最后一个偏移量对应的字符):

>>> letters[12:15]
'mno'

提取最后三个字符:

>>> letters[-3:]
'xyz'

下面一个例子提取了从偏移量为 18 的字符到倒数第 4 个字符。注意与上一个例子的区别:当偏移量 -3 作为开始位置时,将获得字符 x;而当它作为终止位置时,分片实际上会在偏移量 -4 处停止,也就是提取到字符 w:

>>> letters[18:-3]
'stuvw'

接下来,试着提取从倒数第 6 个字符到倒数第 3 个字符:

>>> letters[-6:-2]
'uvwx'

如果你需要的步长不是默认的 1,可以在第二个冒号后面进行指定,就像下面几个例子所示。

从开头提取到结尾,步长设为 7:

>>> letters[::7]
'ahov'

从偏移量 4 提取到偏移量 19,步长设为 3:

>>> letters[4:20:3]
'ehknqt'

如果指定的步长为负数,机智的 Python 还会从右到左反向进行提取操作。下面这个例子便从右到左以步长为 1 进行提取:

>>> letters[-1::-1]
'zyxwvutsrqponmlkjihgfedcba'

事实上,你可以将上面的例子简化为下面这种形式,结果完全一致:

>>> letters[::-1]
'zyxwvutsrqponmlkjihgfedcba'

分片操作对于无效偏移量的容忍程度要远大于单字符提取操作。在分片中,小于起始位置的偏移量会被当作 0,大于终止位置的偏移量会被当作 -1,就像接下来几个例子展示的一样。

提取倒数 50 个字符:

>>> letters[-50:]
'abcdefghijklmnopqrstuvwxyz'

提取从倒数第 51 到倒数第 50 个字符:

>>> letters[-51:-50]
''

从开头提取到偏移量为 69 的字符:

>>> letters[:70]
'abcdefghijklmnopqrstuvwxyz'

从偏移量为 70 的字符提取到偏移量为 71 的字符:

>>> letters[70:71]
''

使用len()获得长度

到目前为止,我们已经学会了使用许多特殊的标点符号(例如 +)对字符串进行相应操作。但标点符号只有有限的几种。从现在开始,我们将学习使用 Python 的内置函数。所谓函数指的是可以执行某些特定操作的有名字的代码。

len() 函数可用于计算字符串包含的字符数:

>>> len(letters)
26
>>> empty = ""
>>> len(empty)
0

使用split()分割

与广义函数 len() 不同,有些函数只适用于字符串类型。为了调用字符串函数,你需要输入字符串的名称、一个点号,接着是需要调用的函数名,以及需要传入的参数:string.function(arguments)。

使用内置的字符串函数 split() 可以基于分隔符将字符串分割成由若干子串组成的列表。所谓列表(list)是由一系列值组成的序列,值与值之间由逗号隔开,整个列表被方括号所包裹。

>>> todos = 'get gloves,get mask,give cat vitamins,call ambulance'
>>> todos.split(',')
['get gloves', 'get mask', 'give cat vitamins', 'call ambulance']

上面例子中,字符串名为 todos,函数名为 split(),传入的参数为单一的分隔符 ','。如果不指定分隔符,那么 split() 将默认使用空白字符——换行符、空格、制表符。

>>> todos.split()
['get', 'gloves,get', 'mask,give', 'cat', 'vitamins,call', 'ambulance']

即使不传入参数,调用 split() 函数时仍需要带着括号,这样 Python 才能知道你想要进行函数调用。

使用join()合并

可能你已经猜到了,join() 函数与 split() 函数正好相反:它将包含若干子串的列表分解,并将这些子串合成一个完整的大的字符串。join() 的调用顺序看起来有点别扭,与 split() 相反,你需要首先指定粘合用的字符串,然后再指定需要合并的列表:string.join(list)。因此,为了将列表 lines 中的多个子串合并成完整的字符串,我们应该使用语句:'\n'.join(lines)。下面的例子将列表中的名字通过逗号及空格粘合在一起:

>>> crypto_list = ['Yeti', 'Bigfoot', 'Loch Ness Monster']
>>> crypto_string = ', '.join(crypto_list)
>>> print('Found and signing book deals:', crypto_string)
Found and signing book deals: Yeti, Bigfoot, Loch Ness Monster

熟悉字符串

Python 拥有非常多的字符串函数。这一节将探索其中最常用的一些。我们的测试对象是下面的字符串,它源自纽卡斯尔伯爵 Margaret Cavendish 的不朽名篇 What Is Liquid?:

>>> poem = '''All that doth flow we cannot liquid name
Or else would fire and water be the same;
But that is liquid which is moist and wet
Fire that property can never get.
Then 'tis not cold that doth the fire put out
But 'tis the wet that makes it die, no doubt.'''

先做个小热身,试着提取开头的 13 个字符(偏移量为 0 到 12):

>>> poem[:13]
'All that doth'

这首诗有多少个字符呢?(计入空格和换行符。)

>>> len(poem)
250

这首诗是不是以 All 开头呢?

>>> poem.startswith('All')
True

它是否以 That's all, folks!? 结尾?

>>> poem.endswith('That\'s all, folks!')
False

接下来,查一查诗中第一次出现单词 the 的位置(偏移量):

>>> word = 'the'
>>> poem.find(word)
73

以及最后一次出现 the 的偏移量 :

>>> poem.rfind(word)
214

the 在这首诗中出现了多少次?

>>> poem.count(word)
3

诗中出现的所有字符都是字母或数字吗?

>>> poem.isalnum()
False

并非如此,诗中还包括标点符号。

大小写与对齐方式

在这一节,我们将介绍一些不那么常用的字符串函数。我们的测试字符串如下所示:

>>> setup = 'a duck goes into a bar...'

将字符串收尾的 . 都删除掉:

>>> setup.strip('.')
'a duck goes into a bar'

让字符串首字母变成大写:

>>> setup.capitalize()
'A duck goes into a bar...'

让所有单词的开头字母变成大写:

>>> setup.title()
'A Duck Goes Into A Bar...'

让所有字母都变成大写:

>>> setup.upper()
'A DUCK GOES INTO A BAR...'

将所有字母转换成小写:

>>> setup.lower()
'a duck goes into a bar...'

将所有字母的大小写转换:

>>> setup.swapcase()
'a DUCK GOES INTO A BAR...'

再来看看与格式排版相关的函数。这里,我们假设例子中的字符串被排版在指定长度(这里是 30 个字符)的空间里。

在 30 个字符位居中:

>>> setup.center(30)
'  a duck goes into a bar...   '

左对齐:

>>> setup.ljust(30)
'a duck goes into a bar...     '

右对齐:

>>> setup.rjust(30)
'     a duck goes into a bar...'

使用replace()替换

使用 replace() 函数可以进行简单的子串替换。你需要传入的参数包括:需要被替换的子串,用于替换的新子串,以及需要替换多少处。最后一个参数如果省略则默认只替换第一次出现的位置:

>>> setup.replace('duck', 'marmoset')
'a marmoset goes into a bar...'

修改最多 100 处:

>>> setup.replace('a ', 'a famous ', 100)
'a famous duck goes into a famous bar...'

参考文档