骑麦兜看落日

[Code]Python学习手册_第二部分_类型和运算

字数统计: 38.3k阅读时长: 171 min
2018/07/24 Share

第四章 介绍Python对象类型

  • 介绍Python核心对象类型,以及可以对它们进行的一些操作

  • 介绍一些能够用于许多对象类型的一般操作(例如索引和切片的序列操作)

  • 介绍可以作为方法调用的特定类型操作(字符串分隔和列表增加)


为什么使用内置类型

  • 内置对象使程序更容易编写
  • 内置对象是拓展的组件
  • 内置对象往往比定制的数据结构更有效率
  • 内置对象是语言的标准的一部分

Python的核心数据类型

对象类型 例子
数字 1234,3.1415,3+4j,Decimal,Fraction
字符串 ‘spam’,”guido’s”,b’a\xolc’
列表 [1,[2,’three’],4]
字典 {‘food’:’spam’,’taste’:’yum’}
元组 (1,’spam’,4,’U’)
文件 myfile = open(‘eggs’,’r’)
集合 set(‘abc’),{‘a’,’b’,’c’}
其他类型 类型、None、布尔型
编程单元类型 函数、模块、类
与实现相关的类型 编译的代码堆栈跟踪

Python中没有类型声明,运行的表达式的语法决定了创建和使用的对象的类型,一旦创建了一个对象,它就和操作集合绑定了

Python是动态类型的(它自动地跟踪你的类型而不是要求声明代码),但是它也是强类型语言(你只能对一个对象进行适合该类型的有效操作)

Python变量不需要提前声明,当给一个变量赋值的时候就创建了它,可能赋的是任何类型的对象,在使用变量的值之前必须对其赋值


数字

Python的核心对象集合包括常规的类型:整数(没有小数部分的数字)、浮点数(有小数部分的数字)以及更为少见的类型(有虚部的复数、固定精度的十进制数、带分子和分母的有理分数、集合、布尔值等)

python中的数字支持一般的数学运算,+代表加法,*代表乘法,**表示乘方

浮点数

1
2
3
4
>>> 3.1415 * 2			# repr:as code
6.2830000000000004
>>> print(3.1415 * 2) # str:user-friendly
6.283

数学模块

1
2
3
4
5
>>> import math
>>> math.pi
3.141592653589793
>>> math.sqrt(85)
9.219544457292887

random模块

1
2
3
4
5
>>> import random
>>> random.random()
0.22545967255559085
>>> random.choice([1,2,3,4])
3

字符串

序列包含字符串、列表和元组,是一个包含其他对象的有序集合

序列中的元素根据它们的相对位置进行存储和读取

字符串是单个字符的字符串的序列

序列的操作

序列的操作对于所有的序列都会工作,包括字符串、列表和元组

索引

1
2
3
4
5
6
7
8
9
10
11
>>> S = 'Spam'
>>> len(S) # Length
4
>>> S[0] # The first item in S,indexing by zero-based position
'S'
>>> S[1] # The second item from the left
'p'
>>> S[-1] # The last item from the end in S
'm'
>>> S[len(S)-1] # Negative indexing,the hard way
'm'

序列支持简单地从位置进行索引

索引是按照从最前面的偏移量进行编码的,第一项索引为0

索引能够反向索引,从最后一个开始,负的索引号会简单地与字符串的长度相加

索引能够在方括号中使用任意表达式

分片

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> S = 'Spam'	# A 4-character string
>>> S[1:3] # Slice of S from offsets 1 through 2(not 3)
'pa'
>>> S[1:] # Everything past the first(1:len(S))
'pam'
>>> S[:3] # Same as S[0:3]
'Spa'
>>> S[:-1] # Everything but the last again,but simpler(0:-1)
'Spa'
>>> S[:] # All of S as a top-level copy(0:len(S))
'Spam'
>>> S # S itself hasn't changed
'Spam'

序列支持分片操作

一般形式为X[L:J],表示取出在X中从偏移量为I,直到但不包括偏移量为J的内容

在一个分片中,左边界默认为0,右边界默认为分片序列的长度

负偏移量为与字符串的长度相加

结果是返回一个新的对象

合并与重复

1
2
3
4
5
6
7
>>> S = 'Spam'
>>> S + 'xyz' # concatenation
'Spamxyz'
>>> S # S is unchanged
'Spam'
>>> S * 8 # Repetition
'SpamSpamSpamSpamSpamSpamSpamSpam'

序列支持使用+进行合并,使用*进行重复

不可变性

在Python中每一个对象都可以分为不可变性或者可变性

在核心类型中,数字、字符串和元组是不可变的,列表和字典是可变的

1
2
3
4
5
6
7
8
>>> S = 'Spam'
>>> S[0] = 'z' # Immutable objects cannot be changed
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> S = 'z' + S[1:] # But we can run expressions to make new objects
>>> S
'zpam'

字符串在Python中具有不可变性,在创建后不能改变

可以通过建立一个新的字符串并以同一个变量名对其进行复制

类型特定的方法

字符串有独有的一些操作作为方法存在(对象的函数,将会通过一个调用表达式触发)

可作用于多种类型的通用型操作都是以内置函数或表达式的形式出现的

类型特定的操作都是以方法调用的形式出现的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> S = 'Spam'
>>> S.find('pa') # Find the offset of a substring
1
>>> S.replace('pa','XYZ') # Replace occurrences of a substring with another
'SXYZm'
>>> S.upper() # Upper and lowercase conversions
'SPAM'
>>> S.isalpha() # Content tests:isalpha,isdigit,etc.
True
>>> S
'Spam'
>>> line = 'aaa,bbb,ccccc,dd\n'
>>> line.rstrip() # Remove whitespace characters on the right side
'aaa,bbb,ccccc,dd'
>>> line.split(',') # Split on a delimiter into a list of substrings
['aaa', 'bbb', 'cccc', 'dd\n']

find方法是一个基本的子字符串查找的操作(返回一个传入子字符串的偏移量,没有找到的情况下返回-1)

replace方法将会对全局进行搜索和替换

upper方法进行大写变换

isalpha测试字符串的内容是否为字母

rstrip方法去掉字符串后的空格字符

split方法通过分隔符将字符串拆分为子字符串

1
2
3
4
>>> '%s,eggs,and %s' % ('spam','SPAM!')			# Formatting expression(all)
'spam,eggs,and SPAM!'
>>> '{0},eggs,and {1}'.format('spam','SPAM!') # Formatting method
'spam,eggs,and SPAM!'

字符串支持格式化的高级替代操作

可以以一个表达式的形式和一个字符串方法调用形式使用

寻求帮助

1
2
3
>>> S = 'Spam'
>>> dir(S)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

对于对象方法的更多细节,调用内置的dir函数,将会返回一个列表,其中包含了对象的所有属性

以双下划线开头并结尾的变量名是用来表示Python实现细节的命名模式

1
2
3
4
5
6
7
8
9
10
11
>>> help(S.replace)

Help on built-in function replace:

replace(...) method of builtins.str instance
S.replace(old, new[, count]) -> str

Return a copy of S with all occurrences of substring
old replaced by new. If the optional argument count is
given, only the first count occurrences are replaced.
(END)

将方法的名称传递给help函数查询它们是做什么的

也能够对整个字符串提交帮助查询,将得到关于每一个字符串方法的详细信息

编写字符串的其他方法

1
2
3
4
5
6
7
8
>>> S = 'A\nB\tC'	# \n is end-of-line,\t is tab
>>> len(S) # Each stands for just one character
5
>>> ord('\n') # \n is a byte with the binary value 10 in ASCII
10
>>> S = 'A\0B\0C' # \0,a binary zero byte,does not terminate string
>>> len(S)
5

反斜线转义序列表示特殊的字符

1
2
3
4
5
>>> msg = """ aaaaaaaaaaaaa
... bbb'''bbbbbbbbbb""bbbbbbb'bbbb
... cccccccccccccc"""
>>> msg
' aaaaaaaaaaaaa\nbbb\'\'\'bbbbbbbbbb""bbbbbbb\'bbbb\ncccccccccccccc'

Python允许字符串包括在单引号或双引号中

Python允许在三个引号(单引号或双引号)中包括多行字符串常量,这种形式中所有的行都合并在一起,并在每一行的末尾增加换行符

Python允许原始字符串常量,即去掉反斜线转义机制(以字母r开头)

Python允许Unicode字符串形式,并且用bytes类型表示原始字节字符串

模式匹配

字符串对象的方法能够支持基于模式的文本处理

1
2
3
4
>>> import re
>>> match = re.match('Hello[ \t]*(.*)world','Hello Python world')
>>> match.group(1)
'Python '

搜索子字符串,这个子字符串以Hello,开始,后面跟着零个或几个制表符或空格,接着有任意字符并将其保存至匹配的group中,最后以world.结尾

找到子字符串与模式中括号包含的部分匹配的子字符串的对应部分保存为组


列表

列表是一个任意类型的对象的位置相关的有序集合,它没有固定的大小

序列操作

列表是序列的一种,支持所有的序列操作,其结果是列表

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> L = [123,'spam',1.23]	# A list of three different-type objects
>>> len(L) # Number of items in the list
3
>>> L[0] # Indexing by position
123
>>> L[:-1] # Slicing a list returns a new list
[123, 'spam']
>>> L + [4,5,6] # Concatenation makes a new list too
[123, 'spam', 1.23, 4, 5, 6]
>>> L * 4
[123, 'spam', 1.23, 123, 'spam', 1.23, 123, 'spam', 1.23, 123, 'spam', 1.23]
>>> L # We're not changing the original list
[123, 'spam', 1.23]

能够对列表进行索引、切片、合并、重复等操作

类型特定的操作

Python的列表与其他语言中的数组有些类似

列表没有固定类型的约束,没有固定大小

因为列表是可变的,大多数列表的方法都会就地改变列表对象,而不是创建一个新的列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> L = [123, 'spam', 1.23]
>>> L.append('NI') # Growing:add object at end of list
>>> L
[123, 'spam', 1.23, 'NI']
>>> L.pop(2) # Shrinking:delete an item in the middle
1.23
>>> L # "del L[2]" deletes from a list too
[123, 'spam', 'NI']
>>> L.insert(2,123)
>>> L
[123, 'spam', 123, 'NI']
>>> L.remove(123)
>>> L
['spam', 123, 'NI']
>>> M = ['bb','aa','cc']
>>> M.sort()
>>> M
['aa', 'bb', 'cc']
>>> M.reverse()
>>> M
['cc', 'bb', 'aa']

append方法扩充了列表的大小并在列表的尾部插入一项

pop方法(或等效的del语句)移除给定偏移量的一项,从而让列表减小

insert方法可以在任意位置插入元素

remove方法按照值移除第一个匹配元素

sort方法,默认按照升序对列表进行排序

severse方法对列表进行翻转

边界检查

1
2
3
4
5
6
7
8
9
>>> L = [123,'spam','NI']
>>> L[99]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> L[99] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range

超出列表末尾之外的索引会导致错误

对列表末尾范围之外赋值会导致错误

嵌套

1
2
3
4
5
6
7
8
9
>>> M = [[1,2,3],	# A 3 x 3 matrix,as nested lists
... [4,5,6], # Code can spam lines if bracketed
... [7,8,9]]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> M[1] # Get row 2
[4, 5, 6]
>>> M[1][2] # Get row 2,then get item 3 within the row
6

能够以任何的组合对其进行嵌套,并可以对多个层次进行嵌套

列表解析

列表解析表达式提供一种处理像矩阵这样结构的工具

1
2
3
4
5
6
7
8
9
10
11
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> col2 = [row[1] for row in M] # Collect the items in column 2
>>> col2
[2, 5, 8]
>>> M # The matrix is unchanged
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [row[1] + 1 for row in M] # Add 1 to each item in columb 2
[3, 6, 9]
>>> [row[1] for row in M if row[1] % 2 == 0] # Filter out odd items
[2, 8]

通过对序列中的每一项运行一个表达式来创建一个新列表的方法,每次一个,从左至右

列表解析是编写在方括号中的,由使用了同一个变量名的表达式循环结构组成

1
2
3
4
5
6
7
8
9
10
>>> diag = [M[i][i] for i in [0,1,2]]	# Collect a diagonal from matrix
>>> diag
[1, 5, 9]
>>> doubles = [c * 2 for c in 'spam'] # Repeat characters in a string
>>> doubles
['ss', 'pp', 'aa', 'mm']
>>> {sum(row) for row in M} # Create a set of row sums
{24, 6, 15}
>>> {i : sum(M[i]) for i in range(3)} # Creates key/value table of row sums
{0: 6, 1: 15, 2: 24}

列表解析创建了新的列表作为结果,但是能够在任何可迭代的对象上进行迭代

解析语法可以用来创建列表、集合和字典

1
2
3
4
5
6
>>> M = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> G = (sum(row) for row in M) # Create a generator of row sums
>>> next(G)
6
>>> next(G) # Run the iteration protocol
15

括号中的解析语法可以用来创建产生所需结果的生成器

1
2
3
>>> M = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> list(map(sum,M)) # Map sum over items in M
[6, 15, 24]

map函数产生对各项运行一个函数的结果


字典

字典不是序列,而是一种映射,映射通过键而不是相对位置来存储

字典具有可变性

字典编写在{}中,并包含一系列的key:value

映射操作

1
2
3
4
5
6
>>> D = {'food':'Spam','quantity':4,'color':'pink'}
>>> D['food'] # Fetch value of key 'food'
'Spam'
>>> D['quantity'] += 1 # Add 1 to 'quantity' value
>>> D
{'food': 'Spam', 'quantity': 5, 'color': 'pink'}

通过键对这个字典进行索引来读取或改变键所关联的值

字典的索引操作与序列具有相同的语法,但是在方括号中的元素是键

1
2
3
4
5
6
7
8
>>> D = {}
>>> D['name'] = 'Bob' # Create keys by assignment
>>> D['job'] = 'dev'
>>> D['age'] = 40
>>> D
{'name': 'Bob', 'job': 'dev', 'age': 40}
>>> D['name']
'Bob'

字典可以每次以一个键来填写它,对一个新的字典的键赋值会创建该键

字典可以用来执行搜索

重访嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> rec = {'name':{'first':'Bob','last':'Smith'},
... 'job':['dev','mgr'],
... 'age':40.5}
>>> rec['name'] # 'name' is a nested dictionary
{'first': 'Bob', 'last': 'Smith'}
>>> rec['name']['last'] # index the nested dictionary
'Smith'
>>> rec['job'] # 'job' is a nested list
['dev', 'mgr']
>>> rec['job'][-1] # Index the nested list
'mgr'
>>> rec['job'].append('janitor') # Expand Bob's job description in-place
>>> rec
{'name': {'first': 'Bob', 'last': 'Smith'}, 'job': ['dev', 'mgr', 'janitor'], 'age': 40.5}
>>> rec = 0 # Now the object's space is reclaimed

可以通过字典的键索引这个嵌套结构的组件

当列表作为字典所包含的一部分时,可以自由地增加或减少

当最后一次引用对象后,对象锁占用的内存空间将会自动清理掉

键的排序:for循环

键的排序

1
2
3
>>> D = {'a': 1, 'b': 2, 'c': 3}
>>> D
{'a': 1, 'c': 3, 'b': 2}

字典作为映射,仅支持通过键获取元素

字典作为映射,不包含任何可靠的从左至右的顺序,如果建立一个字典,并将它打印出来,它的键与我们输入时的顺序可能不同

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> D = {'a': 1, 'c': 3, 'b': 2}
>>> Ks = list(D.keys())
>>> Ks
['a', 'c', 'b']
>>> Ks.sort()
>>> Ks
['a', 'b', 'c']
>>> for key in Ks:
... print(key,'=>',D[key])
...
a => 1
b => 2
c => 3

当需要强调某种顺序时

  • 通过字典的keys方法收集一个键的列表
  • 使用列表的sort方法进行排序
  • 使用Python的for循环逐个显示结果
1
2
3
4
5
6
7
>>> D = {'a': 1, 'c': 3, 'b': 2}
>>> for key in sorted(D):
... print(key,'=>',D[key])
...
a => 1
b => 2
c => 3

通过使用sorted内置函数可以一步完成

sorted调用返回结果并对各种对象类型进行排序

for循环和while循环

for循环以及while循环,是在脚本中编写重复性任务语句的主要方法

for循环是一个序列操作,可以使用任意一个序列对象,甚至可以用在一些不是序列的对象中

1
2
3
4
5
6
7
>>> for c in 'spam':
... print(c.upper())
...
S
P
A
M

for循环可以步进循环字符串中的字符

1
2
3
4
5
6
7
8
9
>>> x = 4
>>> while x > 0:
... print('spam!' * x)
... x -= 1
...
spam!spam!spam!spam!
spam!spam!spam!
spam!spam!
spam!

while循环为常见的循环工具,不仅限于遍历序列

迭代和优化

迭代协议表示在内存中物理存储的序列,或一个在迭代操作情况下每次产生一个元素的对象

for循环和列表解析表达式都能够工作于遵守迭代协议的任意对象

1
2
3
4
5
6
7
8
9
>>> squares = [x ** 2 for x in [1, 2, 3, 4, 5]]
>>> squares
[1, 4, 9, 16, 25]
>>> squares = []
>>> for x in [1, 2, 3, 4, 5]: # This is what a list comprahension does
... squares.append(x ** 2) # Both run the iteration protocol internally
...
>>> squares
[1, 4, 9, 16, 25]

列表解析表达式能够编写成一个等效的for循环

列表解析和相关的函数编程工具(mapfilter)通常运行得比for循环快

不存在的键:if测试

不存在的键

1
2
3
4
5
6
7
8
>>> D = {'a': 1, 'c': 3, 'b': 2}
>>> D['e'] = 99 # Assigning new keys gorws dictionaries
>>> D
{'a': 1, 'c': 3, 'b': 2, 'e': 99}
>>> D['f'] # Referencing a nonexistent key is an error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'f'

获取一个不存在的键值是一个程序错误

测试

获取不存在的键可以通过if/else语句、get方法、try语句

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> D = {'a': 1, 'c': 3, 'b': 2, 'e': 99}
>>> 'f' in D
False
>>> if not 'f' in D:
... print('missing')
...
missing
>>> value = D.get('x',0) # Index but with a default
>>> value
0
>>> value = D['x'] if 'x' in D else 0 # if\else expression form
>>> value
0

in关系表达式允许我们查询字典中一个键是否存在,并可以通过使用Python的if语句对结果进行分支处理

if语句

包含关键字if,紧跟着一个结果为的表达式,测试结果为真的话将于宁一些代码

if语句可以有else分句,以及一个或多个elif分句进行其他的测试


元组

元组对象是序列,但是具有不可变性

元组对象基本上是一个不可以改变的列表

元组编写在()

1
2
3
4
5
6
7
>>> T = (1, 2, 3, 4)	# A 4-item tuple
>>> len(T) # Length
4
>>> T + (5,6) # Concatenation
(1, 2, 3, 4, 5, 6)
>>> T[0] # Indexing,slicing,and more
1

元组支持任意类型、任意嵌套以及常见的序列操作

1
2
3
4
5
>>> T = (1, 2, 3, 4)
>>> T.index(4) # Tuple methods:4 appears at offset 3
3
>>> T.count(4) # 4 appears once
1

index方法返回元素的偏移

count方法返回元素出现的次数

1
2
3
4
5
>>> T = (1, 2, 3, 4)
>>> T[0] = 2 # Tuples are immutable
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

元组是不可变的序列

1
2
3
4
5
6
7
8
9
>>> T = ('spam', 3.0, [11, 22, 33])
>>> T[1]
3.0
>>> T[2][1]
22
>>> T.append(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'

元组支持混合的类型和嵌套,但是不能增长或缩短

为什么要用元组

元组提供了一种完整性的约束,这对于更大型的程序来说是方便的


文件

文件对象是Python代码对电脑上外部文件的主要接口

文件没有特定的常量语法创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> f = open('data.txt','w')				# Make a new file in output mode
>>> f.write('Hello\n') # Write strings of bytes to it
6
>>> f.write('world\n') # Returns number of bytes written in Python 3.0
6
>>> f.close() # Close to flush output buffers to disk
>>> f = open('data.txt') # 'r' is the default processing mode
>>> text = f.read() # Read entire file into a string
>>> text
'Hello\nworld\n'
>>> print(text) # print interprets control characters
Hello
world

>>> text.split() # File content is always a string
['Hello', 'world']
>>> data = open('data.bin', 'rb').read() # Open binary file
>>> data # bytes string holds binary data
b'\x00\x00\x00\x07spam\x00\x08'
>>> data[4:8]
b'spam'

创建一个文本输出文件,需要调用内置的open函数传递给它一个外部的文件名的字符串以及一个处理模式的字符串

文本文件把内容显示为字符串,并且自动执行Unicode编码和解码

  • w处理模式以文本形式写入数据
  • r处理模式以文本形式读出数据(如果在调用时忽略模式的话,这将是默认的)

二进制文件把内容显示为一个特定的字节字符串类型,并且不允许修改地访问文件内容

  • wb处理模式以二进制形式写入数据
  • rb处理模式以二进制形式读出数据

对于脚本而言,文件的内容总是字符串,无论文件包含的数据是什么类型

文件对象的方法

read接受一个字节大小的选项

readline每次读一行

seek移动到一个新的文件位置

文件提供了一个迭代器,在for循环或其他环境中自动地一行一行地读取

其他文件类工具

类文件工具:管道、先进先出队列(FIFO)、套接字、通过键访问文件、对象持久、基于描述符的文件、关系数据库和面向对象数据库接口等


其他核心类型

1
2
3
4
5
6
7
8
9
10
11
12
>>> X = set('spam')						# Make a set out of a squence in 2.6 and 3.0
>>> Y = {'h', 'a', 'm'} # Make a set with new 3.0 set literals
>>> X,Y
({'p', 'a', 's', 'm'}, {'h', 'a', 'm'})
>>> X & Y # Intersection
{'a', 'm'}
>>> X | Y # Union
{'p', 'h', 'a', 's', 'm'}
>>> X - Y # Difference
{'p', 's'}
>>> {x ** 2 for x in [1, 2, 3, 4]} # Set comprehensions in 3.0
{16, 1, 4, 9}

集合不是映射也不是序列

集合是不可变的对象的无序集合

集合可以通过调用内置set函数而创建,或使用集合常量和表达式{}创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> 1 / 3							# Floating-point(use .0 in Python 2.6)
0.33333333333333331
>>> (2/3) + (1/2)
1.1666666666666665
>>> import decimal # Decimals:fixed precision
>>> d = decimal.Decimal('3.141')
>>> d + 1
Decimal('4.141')
>>> decimal.getcontext().prec = 2
>>> decimal.Decimal('1.00') / decimal.Decimal('3.00')
Decimal('0.33')
>>> from fractions import Fraction # Fractions:numerator + denominator
>>> f = Fraction(2, 3)
>>> f + 1
Fraction(5, 3)
>>> f + Fraction(1, 2)
Fraction(7, 6)

十进制数(固定精度浮点数)和分数(有一个分子和一个分母的有理数)用来解决浮点数学的局限性和内在的不精确性

1
2
3
4
5
6
7
8
9
10
>>> 1 > 2,1 < 2
(False, True)
>>> bool('spam')
True
>>> X = None
>>> print(X)
None
>>> L = [None] * 100
>>> L
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]

布尔值以及特殊的占位符对象None(用来初始化名字和对象)

如何破坏代码的灵活性

在代码中检验特定的类型,实际上破坏了代码的灵活性,即限制了它只能使用一种类型工作,没有这样的检测,代码也许能够使用整个范围的类型工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
>>> L = [1, 2, 3]

# In Python 2.6:

>>> type(L) # Types:type of L is list type object
<type 'list'>
>>> type(type(L)) # Even types are objects
<type 'type'>

# In Python 3.0:

>>> type(L) # 3.0:types are classes,and vice versa
<class 'list'>
>>> type(type(L)) # See Chapter 31 for more on class types
<class 'type'>

>>> if type(L) == type([]): # Type testing,if you must...
... print('yes')
...
yes
>>> if type(L) == list: # Using the type name
... print('yes')
...
yes
>>> if isinstance(L,list): # Object-oriented tests
... print('yes')
...
yes

内置函数type返回的类型对象是赋给该类型的另一个对象的一个对象

内置函数type允许编写代码来检查他所处理的对象的类型

用户定义的类

类定义了新的对象类型,拓展了核心类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> class Worker:
... def __init__(self, name, pay): # Initialize when created
... self.name = name # self is the new object
... self.pay = pay
... def lastName(self):
... return self.name.split()[-1] # Split string on blanks
... def giveRaise(self, percent):
... self.pay *= (1.0 + percent) # Update pay in-place
...
>>> bob = Worker('Bob Smith', 50000) # Make two instances
>>> sue = Worker('Sue Jones', 60000) # Each has name and pay attrs
>>> bob.lastName() # Call method:bob is self
'Smith'
>>> sue.lastName() # sue is the self subject
'Jones'
>>> sue.giveRaise(.10) # Updates sue's pay
>>> sue.pay
66000.0

调用类会生成新类型的实例,并且类的方法调用时,类的方法自动获取被处理的实例

隐含的self对象是将其叫做面向对象模型的原因,即一个类中的函数总有一个隐含的对象

基于类的类型是基于并使用了核心类型的

通过编写新的类来拓展软件,而不是改变目前工作的类

剩余的内容

Python脚本中能够处理的所有的事情都是某种类型的对象

在Python中的每样东西都是一个对象

对象不是面向对象,面向对象是一种要求有继承和Python类声明的概念


本章习题

  1. 列举4个Python核心数据类型的名称

    数字、字符串、列表、字典、元组、文件和集合一般被认为是核心对象(数据)类型

    类型、None和布尔型有时也被定义在这样的分类中

    还有多种数字类型(整数、浮点数、复数、分数和十进制数)和多种字符串类型(Python 2.X中的一般字符串和Unicode字符串,以及Python 3.X中的文本字符串和字节字符串)

  2. 为什么我们把它们称作是”核心”数据类型

    它们被认作是”核心”类型是因为它们是Python语言自身的一部分,并且总是有效的

    为了建立其他的对象,通常必须调用被导入模块的函数

    大多数核心类型都有特定的语法去生成其对象:例如,’spam’ 是一个创建字符串的表达式,而且决定了可以被应用的操作的集合,正是因为这一点,核心类型与Python的语法紧密地结合在一起

    与之相比较,必须调用内置的open函数去创建一个文件对象

  3. “不可变性”代表了什么,哪三种Python的核心类型被认为是具有不可变性的

    一个具有”不可变性”的对象是一个在其创建以后不能够被改变的对象

    Python中的数字、字符串和元组都属于这个分类

    尽管无法就地改变一个不可变的对象,但是可以通过运行一个表达式创建一个新的对象

  4. “序列”是什么意思,哪三种Python的核心类型被认为是这个分类中的

    一个”序列”是一个对位置进行排序的对象的集合

    字符串、列表和元组是Python中所有的序列

    它们共同拥有一般的序列操作,例如,索引、合并以及分片,但又各自有自己的类型特定的方法调用

  5. “映射”是什么意,,哪种Python的核心类型是映射

    术语”映射”,表示将键与相关值相互关联映射的对象

    Python的字典是其核心类型集中唯一的映射类型

    映射没有从左至右的位置顺序;它们支持通过键获取数据,并包含了类型特定的方法调用

  6. 什么是”多态”,为什么我们要关心多态?

    “多态”意味着一个操作符(如+)的意义取决于被操作的对象

    这将变成使用好Python的关键思想之一:不要把代码限制在特定的类型上,使代码自动适用于多种类型


第五章 数字

学习Python数字对象类型和能够应用于它们的操作

学习标准的正数和浮点数类型,以及复数、分数和集合

学习Python的表达式语法、类型转换、位操作以及各种在脚本中编写数字的常量的形式


Python的数字类型

在Python中,数字并不是一个真正的对象类型,而是一组类似类型的分类

Python不仅支持通常的数字类型(整数和浮点数),而且能够通过常量去直接创建数字以及处理数字的表达式

Python数字类型的完整工具

  • 整数和浮点数
  • 复数
  • 固定精度的十进制数
  • 有理分数
  • 集合
  • 布尔类型
  • 无穷的整数精度
  • 各种数字内置函数和模块

数字常量

在基本类型中,Python提供了整数(正整数和负整数)和浮点数(带有小数部分的数字)

Python允许整数具有无穷的精度

数字 常量
整数(无穷大小) 1234,-24,0,99999999999999
浮点数 1.23,1.,3.14e-10,4E210,4.0e+210
Python 3.0中的八进制、十六进制和二进制常量 0o177,0x9ff,0b101010
复数常量 3+4j,3.0+4.0j,3J

Python数字类型在程序中的显示方式

十六进制数、八进制和二进制常量

整数可以编写为

  • 十进制
  • 十六进制(0x或0X开头,后接十六进制数字09和AF,十六进制数字编写成大写或小写都可以)
  • 八进制(0o或0O开头,后接八进制数字0~7)
  • 二进制(以0b或0B开头,后接二进制数字0~1)

所有这些常量在程序代码中都产生一个整数对象,它们仅仅是特定值的不同语法表示而已

内置函数hex(I)oct(I)bin(I)把一个整数转换为这3种进制表示的字符串

内置函数int(str,base)根据给定的进制把一个字符串转换为一个整数

复数

Python的复数常量写成实部+虚部的写法,虚部以jJ结尾

实部从技术上讲可有可无,所以可能会单独表示虚部

从内部看来,复数是通过一对浮点数来表示的,但是对复数的所有的数字操作都会按照复数的运算法则进行

可以通过内置函数complex(real,imag)来创建复数

编辑其他的数字类型

其他的、更高级的数字类型有一些通过调用导入的模块中的函数来创建(例如,十进制数和分数),另一些拥有它们自己的常量语法(例如,集合)

内置数学工具和拓展

表达式操作符

+-*/>>**&

内置数学函数

powabsroundinthexbin

公用模块

randommath

特定于类型的方法

浮点数拥有as_integer_ratio方法,对于分数数字类型很有用

is_integer方法测试数字是否是一个整数

bit_length方法给出表示对象的值所需要的位数

Python表达式操作符

表达式是处理数字的最基本的工具

表达式是使用通常的数学符号和操作符号写出来的

操作符 描述
yield x 生成器函数发送协议
lambda args: expression 生成匿名函数
x if y else z 三元选择表达式
x or y 逻辑或(只有x为假,才会计算y)
x and y 逻辑与(只有x为真,才会计算y)
not x 逻辑非
x in y, x not in y 成员关系(可迭代对象、集合)
x is y, x is not y 对象实体测试
x < y, x <= y, x > y, x >= y, x == y, x != y 大小比较,集合子集和超集值相等性操作符
x | y 位或,集合并集
x ^ y 位异或,集合对称差
x & y 位与,集合交集
x << y, x >> y 左移或右移y位
x + y, x - y 加法/合并,减法,集合差集
x * y, x % y, x / y, x // y 乘法/重复,余数/格式化,除法:真除法或floor除法
-x, +x 一元减法,识别
~x 按位求补(取反)
x ** y 幂运算
x[i] 索引(序列、映射及其他)点号取属性运算,函数调用
x[i:j:k] 分片
x(…) 调用(函数、方法、类及其他可调用的)
x.attr 属性引用
(…) 元组、表达式、生成器表达式
[…] 列表、列表解析
{…} 字典、集合、集合和字典解析

Python表达式操作符及程序

混合操作所遵循的操作优先级

当编写含有一个以上操作符的表达式时,Python将按照所谓的优先级法则对其进行分组,这个分组决定了表达式中各部分的计算顺序

  • 表中越靠后的优先级越高
  • 表中位于同一行的表达式在组合的时候通常从左到右组合(幂运算从右向左组合,比较运算是从左到右连接的)

括号分组的子表达式

如果用括号将表达式各部分进行分组的话,就会超越Python的优先级规则,先行计算括号中的表达式

混合类型自动升级

在混合类型的表达式中,Python首先将被操作的对象转换成其中最复杂的操作对象的类型,然后再对相同类型的操作对象进行数学运算

Python数字类型复杂度:整数比浮点数简单,浮点数比复数简单

1
2
3
4
>>> int(3.1415)	# Truncates filoat to integer
3
>>> float(3) # Converts integer to float
3.0

内置函数intfloat可以强制转换类型

预习:运算符重载

所有的Python操作符可以通过Python的类或C拓展类型被重载,让它工作于自己创建的对象中

Python自身自动重载了某些操作符,能够根据所处理的内置对象的类型而执行不同的操作


在实际应用中的数字

变量和基本的表达式

变量

  • 变量在它第一次赋值时创建
  • 变量在表达式中使用将被替换为它们的值
  • 变量在表达式中使用以前必须已赋值
  • 变量像对象一样不需要在一开始进行声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> a = 3					# Name created
>>> b = 4
>>> a + 1, a - 1 # Addition(3 + 1),subtraction(3 - 1)
(4, 2)
>>> b * 3, b / 2 # Multiplication(4 * 3),division(4 / 2)
(12, 2.0)
>>> a % 2, b ** 2 # Modulus(remainder),power(4 ** 2)
(1, 16)
>>> 2 + 4.0, 2.0 ** b # Mixed-type conversions
(6.0, 16.0)
>>> c * 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'c' is not defined
>>> b / 2 + a # Same as((4/3) + 3)
5.0
>>> print(b / (2.0 + a)) # Same as(4/(2.0 + 3))
0.8

变量不需要预声明,而是在使用前,至少赋一次值

如果使用从未被赋值的不同的变量,Python将会报告有错误而不是赋给默认的值

没有括号时,Python自动根据运算符的优先级法则将各部分分组

整数相除时,/执行带有余数的真除法,//执行整数除法

注释

在#标记后直到本行末尾的文本会认作是一个注释并忽略

注释是为代码编写可读文档的方法

数字显示的格式

1
2
3
4
5
6
7
8
>>> a = 3
>>> b = 4
>>> b / (2.0 + a) # Auto echo output:more digits
0.800000000000000004
>>> print(b / (2.0 + a)) # print rounds off digits
0.8
>>> 1 / 2.0
0.5

浮点数除法由于浮点数的硬件限制,以及无法精确地表现一些值会出现更多的位数

在交互提示模式下结果显示计算机的浮点数硬件中所有数字

并不是所有的值都有更多的数字位数需要显示

1
2
3
4
5
6
7
8
9
10
11
>>> num = 1 / 3.0
>>> num # Echoes
0.33333333333333331
>>> print(num) # print rounds
0.3333333333333333
>>> '%e' % num # String formatting expression
'3.333333e-01'
>>> '%4.2f' % num # Alternative floating-point format
'0.33'
>>> '{0:4.2f}'.format(num) # String formatting methon
'0.33'

显示数字位数的方法有自动回显、打印、字符串格式化

比较:一般的和连续的

一般的

1
2
3
4
5
6
7
8
>>> 1 < 2		# Less than
True
>>> 2.0 >= 1 # Greater than or equal:mixed-type 1 converted to 1.0
True
>>> 2.0 == 2.0 # Equal value
True
>>> 2.0 != 2.0 # Not equal value
False

一般的比较会比较操作数的相对大小,并且返回一个布尔类型的结果

连续的

Python允许把大小比较测试连接起来,成为连续比较`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> X = 2
>>> Y = 4
>>> Z = 6
>>> X < Y < Z # Chained comparisons:range tests
True
>>> X < Y and Y < Z
True
>>> X < Y < Z
True
>>> X < Y and Y < Z
True
>>> X < Y > Z
False
>>> X < Y and Y > Z
False
>>> 1 < 2 < 3.0 < 4
True
>>> 1 > 2 > 3.0 > 4
False
>>> 1 == 2 < 3 # Same as:1 == 2 and 2 < 3
False # Not same as:Flase < 3(which means 0 < 3,which is true)

表达式(A < B < C)等同于布尔测试`(A < B and B < C),但第一个表达式简单便于录入,并且运行起来可能略快

允许任意的连续长度

可以在连续测试中使用其他的比较,但是最终表达式可能会变的很晦涩

str和repr显示格式

默认的交互模式回显打印的区别相当于内置reprstr函数的区别

1
2
3
4
5
>>> num = 1 / 3
>>> repr(num) # Used by echoes:as-code form
'0.33333333333333331'
>>> str(num) # Used by print:user-friendly form
'0.333333333333'

两个函数都会把任意对象变换成字符串表示

repr产生的结果像是代码

str转变为一种对用户更友好的格式

除法:传统除法、Floor除法和真除法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Python 3.0

>>> 10 / 4 # Differs in 3.0:keeps reaminder
2.5
>>> 10 // 4 # Same in 3.0:truncates remainder
2
>>> 10 / 4.0 # Same in 3.0:keeps remainder
2.5
>>> 10 // 4.0 # Same in 3.0:truncates to floor
2.0

# Python 2.6

>>> 10 / 4
2
>>> 10 // 4
2
>>> 10 / 4.0
2.5
>>> 10 // 4.0
2.0

真除法

X / Y

不管操作数的类型

返回包含任何余数的浮点结果

Floor除法

X // Y

截除掉余数

针对整数操作数返回一个整数,如果有任何一个操作数是浮点类型,则返回一个浮点数

传统除法

在Python 2.6中,/表示传统除法

如果两个操作数都是整数的话,执行截断的整数除法,否则执行浮点除法

支持两个Python版本

1
2
3
4
5
>>> X = 2
>>> Y = 4
>>> Z = 6
>>> X = Y // Z # Always truncates,always an int result for ints in 2.6 and 3.0
>>> X = Y / float(Z) # Guaranrees float division with remainder in either 2.6 or 3.0

如果依赖于截断整数除法,Python 2.6和Python 3.0中都使用//

如果对于整数需要带有余数的浮点数结果,使用/并使用浮点数

1
2
3
4
5
>>> from __future__ import division
>>> 10 / 4
2.5
>>> 10 // 4
2

使用__furure__``import在Python 2.6中打开Python 3.0的/

Floor除法VS截断除法

Floor除法把结果向下截断到它的下层,即小于真正结果的最近整数,这对负数也有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> import math
>>> math.floor(2.5)
2
>>> math.floor(-2.5)
-3
>>> math.trunc(2.5)
2
>>> math.trunc(-2.5)
-2
>>> 5 / 2
2.5
>>> 5 / 2, 5 / -2
(2.5, -2.5)
>>> 5 // 2, 5 // -2 # Truncates to floor:rounds to first lower integer
(2, -3) # 2.5 becomes 2, -2.5 becomes -3
>>> 5 / 2.0, 5 / -2.0
(2.5, -2.5)
>>> 5 // 2.0, 5 // -2.0 # Ditto for floats,though result is float too
(2.0, -3.0)

对于正数,截断除法和Floor除法是相同的

对于负数,截断除法直接舍弃余数,Floor除法截断到小于结果的最大整数

1
2
3
4
5
6
7
>>> import math
>>> 5 / -2 # Keep remainder
-2.5
>>> 5 // -2 # Floor below result
-3
>>> math.trunc(5 / -2) # Truncate instead of floor
-2

通过math.trunc得到截断除法结果

为什么Floor除法很重要

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Python 3.0

>>> (5 / 2), (5 / 2.0), (5 / -2.0), (5 / -2) # 3.0 true division
(2.5, 2.5, -2.5, -2.5)
>>> (5 // 2), (5 // 2.0), (5 // -2.0), (5 // -2) # 3.0 floor division
(2, 2.0, -3.0, -3)
>>> (9 / 3), (9.0 / 3), (9 // 3), (9 // 3.0) # Both
(3.0, 3.0, 3, 3.0)

# Python 2.6

>>> (5 / 2), (5 / 2.0), (5 / -2.0), (5 / -2) # 2.6 classic division
(2, 2.5, -2.5, -3)
>>> (5 // 2), (5 // 2.0), (5 //-2.0), (5 // -2) # 2.6 floor division(same)
(2, 2.0, -3.0, -3)
>>> (9 / 3), (9.0 / 3), (9 // 3), (9 // 3.0) # Both
(3, 3.0, 3, 3.0)

Python 3.0中/的非截断行为可能会影响到大量的程序

整数精度

1
2
3
4
>>> 999999999999999999999999999999 + 1
1000000000000000000000000000000
>>> 2 ** 200
1606938044258990275541962092341162602522202993782792835301376

Python 3.0整数支持无穷的大小

长整型数的数学运算通常比正常的整数运算更慢

复数

1
2
3
4
5
6
7
8
9
10
>>> 1j * 1J
(-1+0j)
>>> 2 + 2j * 3
(2+6j)
>>> 1j * 1J
(-1+0j)
>>> 2 + 1j * 3
(2+3j)
>>> (2 + 1j) * 3
(6+3j)

复数表示为两个浮点数(实部和虚部),并在虚部增加jJ的后缀

可以把非零实部的复数写成由+连接起来的两部分

复数允许分解出它的实部和虚部作为属性,并支持所有一般的数学表达式,并且可以通过标准的cmath模块中的工具进行处理

十六进制、八进制和二进制记数

Python整数能够以十六进制、八进制和二进制计数法来编写,作为一般的以10位基数的十进制计数法的补充

1
2
3
4
5
6
>>> 0o1, 0o20, 0o377			# Octal literals
(1, 16, 255)
>>> 0x01, 0x10, 0xFF # Hex literals
(1, 16, 255)
>>> 0b1, 0b10000, 0b11111111 # Binary literals
(1, 16, 255)

Python默认地使用十进制值显示

整数转换字符串

1
2
>>> oct(64), hex(64), bin(64)
('0o100', '0x40', '0b1000000')

Python提供了内置函数,把整数转换为其他进制的数字字符串

oct函数将十进制数转换为八进制数的字符串

hex函数将十进制数转换为十六进制数的字符串

bin函数将十进制数转换为二进制数的字符串

1
2
3
4
>>> '{0:o}, {1:x}, {2:b}'.format(64, 64, 64)
'100, 40, 1000000'
>>> '%o, %x, %X' % (64, 255, 255)
'100, ff, FF'

使用字符串格式化方法将一个整数转换成八进制数和十六进制数的字符串

字符串转换整数

1
2
3
4
>>> int('64'), int('100', 8), int('40', 16), int('1000000', 2)
(64, 64, 64, 64)
>>> int('0x40', 16), int('0b1000000', 2) # Literals okay too
(64, 64)

内置的int函数会将一个数字的字符串变换为一个整数

第二个参数确定变换后的数字的进制

1
2
>>> eval('64'), eval('0o100'), eval('0x40'), eval('0b1000000')
(64, 64, 64, 64)

eval函数会把字符串作为Python代码,因此也可以将一个数字的字符串转换为一个整数

位操作

Python可以把整数当做二进制位串操作

Python中有比位字符串更好的编码信息的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>>> x = 1				# 0001
>>> x << 2 # Shift left 2 bit:0100
4
>>> x | 2 # Bitwise OR:0011
3
>>> x & 1 # Bitwise AND:0001
1
>>> X = 0b0001 # Binary literals
>>> X << 2 # Shift left
4
>>> bin(X << 2) # Binaryy digits string
'0b100'
>>> bin(X | 0b010) # Bitwise OR
'0b11'
>>> bin(X & 0b1) # Bitwise AND
'0b1'
>>> X = 0xFF # Hex literals
>>> bin(X)
'0b11111111'
>>> X ^ 0b10101010 # Bitwise XOR
85
>>> bin(X ^ 0b10101010)
'0b1010101'
>>> int('1010101', 2) # String to int per base
85
>>> hex(85) # Hex digit string
'0x55'
  • <<位左移
  • |按位或
  • &按位与
  • ^按位异或
1
2
3
4
5
6
7
>>> X = 99
>>> bin(X), X.bit_length()
('0b1100011', 7)
>>> bin(256), (256).bit_length()
('0b100000000', 9)
>>> len(bin(256))-2
9

bit_length方法允许查询以二进制表示一个数字的值所需要的位数

其他的内置数学工具

Python支持用于数字处理的内置函数内置模块

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> import math
>>> math.pi, math.e # Common constants
(3.141592653589793, 2.718281828459045)
>>> math.sin(2 * math.pi / 180) # Sine,tangent,cosine
0.03489949670250097
>>> math.sqrt(144), math.sqrt(2) # Square root
(12.0, 1.4142135623730951)
>>> pow(2, 4), 2 ** 4 # Exponentiation(power)
(16, 16)
>>> abs(-42.0), sum((1, 2, 3, 4)) # Absolute value,summation
(42.0, 10)
>>> min(3, 1, 2, 4), max(3, 1, 2, 4) # Minimum,maximum
(1, 4)

sum函数作用于数字的一个序列进行求和

minmax函数接受一个参数序列或者单个的参数

1
2
3
4
5
6
7
8
9
10
11
12
>>> math.floor(2.567), math.floor(-2.567)		# Floor(next-lower integer)
(2, -3)
>>> math.trunc(2.567), math.trunc(-2.567) # Truncate(drop decimal digits)
(2, -2)
>>> int(2.567), int(-2.567) # Truncate(integer conversion)
(2, -2)
>>> round(2.567), round(2.456), round(2.567,2) # Round(Python 3.0 version)
(3, 2, 2.5699999999999998)
>>> '%.1f' % 2.567, '{0:.2f}'.format(2.567) # Round for display
('2.6', '2.57')
>>> (1 / 3), round(1 / 3, 2),('%.2f' % (1 / 3))
(0.33333333333333331, 0.3300000000000002, '0.33')

通过截断、floor、round删除一个浮点数的小数位

round舍入一个浮点数但是仍然在内存中产生一个浮点数

字符串格式化产生一个字符串并且不会得到一个修改后的数字

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> import math
>>> math.sqrt(144) # Module
12.0
>>> 144 ** .5 # Expression
12.0
>>> pow(144, .5) # Built-in
12.0
>>> math.sqrt(1234567890) # Larger numbers
35136.41828644462
>>> 1234567890 ** .5
35136.41828644462
>>> pow(1234567890, .5)
35136.41828644462

Python有3种方法计算平方根:使用一个模块函数,一个表达式或一个内置函数

模块是外部的组件,必须先导入

内置函数位于一个隐性的命名空间(builtins)内,Python自动搜索程序的变量名,不需要导入就可以直接使用

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> import random
>>> random.random()
0.6387170104190479
>>> random.random()
0.48633074825407063
>>> random.randint(1, 10)
5
>>> random.randint(1, 10)
4
>>> random.choice(['life of Brian', 'Holly Grail', 'Meaning of Life'])
'Holly Grail'
>>> random.choice(['life of Brian', 'Holly Grail', 'Meaning of Life'])
'life of Brian'

random模块

  • 选出一个在0和1之间的任意浮点数
  • 选择在两个数字之间的任意整数
  • 选择在一个序列中任意挑选一项

其他数字类型

小数数字

通过调用decimal模块中的Decimal构造函数创建一个小数对象

通过导入decimal模块调用declmal.Decimal.from_float(num)形式创建

不能通过运行常量表达式创建的

小数是有固定的精度的浮点值

基础知识

1
2
3
4
>>> 0.1 + 0.1 + 0.1 - 0.3
5.551115123125783e-17
>>> print(0.1 + 0.1 + 0.1 - 0.3)
5.551115123125783e-17

浮点数学缺乏精确性,因为用来存储数值的空间有限,没有足够的位数去实现这样的精度

打印结果将会产生一个用户友好的显示格式但并不能完全解决问题

1
2
3
4
>>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') - Decimal('0.3')
Decimal('0.0')
>>> Decimal('0.1') + Decimal('0.10') + Decimal('0.10') - Decimal('0.30')
Decimal('0.00')

创建一个小数对象,并传入一个字符串,这个字符串有我们希望在结果中显示的小数位数

当不同精度的小数在表达式中混编时,Python自动升级为小数位数最多的

设置全局精度

1
2
3
4
5
6
7
8
9
10
11
12
>>> import decimal
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.1428571428571428571428571429')
>>> decimal.getcontext().prec = 4
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.1429')
>>> 1999 + 1.33
2000.33
>>> decimal.getcontext().prec = 2
>>> pay = decimal.Decimal(str(199 + 1.33))
>>> pay
Decimal('200.33')

上下文对象允许指定精度(小数位数)和舍入模式(舍去、进位)等

该精度全局性地适用于调用线程中创建的所有小数

小数上下文管理器

1
2
3
4
5
6
7
8
9
10
>>> import decimal
>>> decimal.Decimal('1.00') / decimal.Decimal('3.00')
Decimal('0.3333333333333333333333333333')
>>> with decimal.localcontext() as ctx:
... ctx.prec = 2
... decimal.Decimal('1.00') / decimal.Decimal('3.00')
...
Decimal('0.33')
>>> decimal.Decimal('1.00') / decimal.Decimal('3.00')
Decimal('0.3333333333333333333333333333')

使用上下文管理器语句来重新设置临时精度,在语句退出后,精度又重新设置为初始值

分数类型

实现了一个有理数对象

明确地保留一个分子和一个分母,从而避免了浮点数学的某些不准确性和局限性

通过调用fractions模块中的Fraction构造函数并传递一个分子和一个分母创建一个分数对象

基本知识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> from fractions import Fraction
>>> x = Fraction(1, 3) # Numerator,denominator
>>> y = Fraction(4, 6) # Simplified to 2,3 by gcd
>>> x
Fraction(1, 3)
>>> y
Fraction(2, 3)
>>> print(y)
2/3
>>> x + y
Fraction(1, 1)
>>> x - y # Results are exact:numerator,denominator
Fraction(-1, 3)
>>> x * y
Fraction(2, 9)

分数可以像平常一样用于数学表达式中

1
2
3
4
5
6
>>> Fraction('.25')
Fraction(1, 4)
>>> Fraction('1.25')
Fraction(5, 4)
>>> Fraction('.25') + Fraction('1.25')
Fraction(3, 2)

分数对象也可以从浮点数字符串来创建

数值精度

1
2
3
4
5
6
>>> (1 / 3) + (6 / 12)		# Use".0" in Python 2.6 for true "/"
0.833333333333333326
>>> Fraction(6, 12) # Automatically simplified
Fraction(1, 2)
>>> Fraction(1, 3) + Fraction(6, 12)
Fraction(5, 6)

分数保持精确性,并且自动简化结果

转换和混合类型

float -> fraction
1
2
3
4
5
6
7
8
9
10
>>> (2.5).as_integer_ratio()						# float object method
(5, 2)
>>> f = 2.5
>>> z = Fraction(*f.as_integer_ratio()) # Convert float -> fraction:two args
>>> z # Same as Fraction(5, 2)
Fraction(5, 2)
>>> Fraction.from_float(1.75) # Convert float -> fraction:other way
Fraction(7, 4)
>>> Fraction(*(1.75).as_integer_ratio())
Fraction(7, 4)
  • 浮点数对象的方法.as_integer_ratio()将浮点数转换为分子和分母比
  • 分数的方法from_float接受一个浮点数得到一个分数结果

*是一种特殊的语法,把一个元组拓展到单个的参数中

fraction -> float
1
2
3
4
5
6
7
8
9
10
11
12
>>> x = Fraction(1, 3)								# x from prior interaction
>>> z = Fraction(5, 2) # Same as Fraction(5, 2)
>>> x + z
Fraction(17, 6) # 5/2 + 1/3 = 15/6 + 2/6
>>> float(x) # Convert fraction -> float
0.33333333333333331
>>> float(z)
2.5
>>> float(x + z)
2.8333333333333335
>>> 17 / 6
2.8333333333333335
  • float接受一个Fraction作为参数,转换为浮点数
混合类型
1
2
3
4
5
6
7
8
9
10
11
12
>>> x
Fraction(1, 3)
>>> x + 2 # Fraction + int -> Fraction
Fraction(7, 3)
>>> x + 2.0 # Fraction + float -> float
2.3333333333333335
>>> x + (1./3) # Fraction + float -> float
0.6666666666666666
>>> x + (4./3)
1.6666666666666665
>>> x + Fraction(4, 3) # Fraction + Fraction -> Fraction
Fraction(5, 3)
  • Fraction + int -> Fraction
  • Fraction + float -> float
  • Fraction + fraction -> Fraction
精度

把浮点数转换为分数在某些情况下会有不可避免的精度损失

1
2
3
4
5
6
7
8
9
10
11
12
>>> 4.0 / 3
1.3333333333333333
>>> (4.0 / 3).as_integer_ratio()
(6004799503160661, 4503599627370496)
>>> x = Fraction(1, 3)
>>> a = x + Fraction(*(4.0 / 3).as_integer_ratio()) # Precision loss from float
>>> a
Fraction(22517998136852479, 13510798882111488)
>>> 22517998136852479 / 13510798882111488. # 5 / 3(or close to it!)
1.6666666666666667
>>> a.limit_denominator(10) # SiMplify to closet fraction
Fraction(5, 3)

分数的limit_denominator方法通过限制最大分母值来简化结果

集合

唯一的、不可变的对象的无序集合

支持与数学集合理论相对应的操作]

通过向内置的set函数传递一个序列或其他的可迭代的对象创建集合对象

通过使用{}创建集合常量

Python 2.6中的集合基础知识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> x = set('abcde')
>>> y = set('bdxyz')
>>> x
set(['a', 'c', 'b', 'e', 'd']) # 2.6 display format
>>> 'e' in x # Membership
True
>>> x - y # Difference
set(['a', 'c', 'e'])
>>> x | y # Union
set(['a', 'c', 'b', 'e', 'd', 'y', 'x', 'z'])
>>> x & y # Intersection
set(['b', 'd'])
>>> x ^ y # Symmetric difference(XOR)
set(['a', 'c', 'e', 'y', 'x', 'z'])
>>> x > y, x < y # Superset,subset
(False, False)

集合通过表达式操作符支持一般的数学集合运算in-|&^><

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>>> x = set(['a', 'c', 'b', 'e', 'd'])
>>> y = set(['y', 'x', 'b', 'd', 'z'])
>>> z = x.intersection(y) # Same as x & y
>>> z
set(['b', 'd'])
>>> z.add('SPAM') # Insert one item
>>> z
set(['b', 'd', 'SPAM'])
>>> z.update(set(['X', 'Y'])) # Merge:in-place union
>>> z
set(['Y', 'X', 'b', 'd', 'SPAM'])
>>> z.remove('b') # Delete one item
>>> z
set(['Y', 'X', 'd', 'SPAM'])
>>> S = set([1, 2, 3])
>>> S | set([3, 4]) # Expressions require both to be sets
set([1, 2, 3, 4])
>>> S | [3, 4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'list'
>>> S.union([3, 4]) # But their methods allow any iterable
set([1, 2, 3, 4])
>>> S.intersection((1, 3, 5))
set([1, 3])
>>> S.issubset(range(-5, 5))
True
  • intersection方法求交集
  • union方法求并集
  • issubset判断子集
  • add方法插入一个项目
  • update方法按位置求并集
  • remove方法根据值删除一个项目

表达式通常需要两个集合,但是基于方法的对应形式往往对任何可迭代类型也有效

1
2
3
4
5
>>> for item in set('abc'):print(item * 3)
...
aaa
ccc
bbb

集合支持lenfor循环和列表解析操作

不支持索引和分片这样的操作

Python 3.0中的集合常量

1
2
>>> set([1, 2, 3, 4])	# Built-in call
{1, 2, 3, 4} # 3.0 set literals

Python 3.0添加了新的集合常量形式,使用为字典所保留的花括号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> set([1, 2, 3, 4])		# Built-in:same as in 2.6
{1, 2, 3, 4}
>>> set('spam') # Add all items in an iterable
{'m', 'a', 's', 'p'}
>>> {1, 2, 3, 4} # Set literals:new in 3.0
{1, 2, 3, 4}
>>> S - {1, 2, 3, 4} # Empty sets print differently
set()
>>> type({}) # Because {} is an empty dictionary
<class 'dict'>
>>> S = set() # Initialize an empty set
>>> S.add(1.23)
>>> S
{1.23}
>>> S = {'s', 'p', 'a', 'm'}
>>> S.add('alot')
>>> S
{'a', 'm', 's', 'p', 'alot'}

创建空的集合从已有的可迭代对象构建集合还是需要内置的set函数

1
2
3
4
5
6
7
8
9
>>> S = {1, 2, 3, 4}
>>> S & {1, 3} # Intersection
{1, 3}
>>> {1, 5, 3, 6} | S # Union
{1, 2, 3, 4, 5, 6}
>>> S - {1, 3, 4} # Difference
{2}
>>> S > {1, 3} # Superset
True

Python 2.6所有的集合处理操作在Python 3.0中同样有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> {1, 2, 3} | {3, 4}
{1, 2, 3, 4}
>>> {1, 2, 3} | [3, 4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'list'
>>> {1, 2, 3}.union([3, 4])
{1, 2, 3, 4}
>>> {1, 2, 3}.union({3, 4})
{1, 2, 3, 4}
>>> {1, 2, 3}.union(set([3, 4]))
{1, 2, 3, 4}
>>> {1, 2, 3}.intersection((1, 3, 5))
{1, 3}
>>> {1, 2, 3}.issubset(range(-5, 5))
True

Python 2.6集合支持的方法在Python 3.0中同样支持,其中的一些支持表达式所不支持的通用可迭代操作数

不可变限制和冻结集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> S = {1.23}
>>> S.add([1, 2, 3]) # Only mutable objects work in a set
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> S.add({'a':1})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> S.add((1, 2, 3))
>>> S # Not list or dict,but tuple okay
{1.23, (1, 2, 3)}
>>> S | {(4, 5, 6), (1, 2, 3)} # Union:same as S.union(...)
{1.23, (4, 5, 6), (1, 2, 3)}
>>> (1, 2, 3) in S # Membership:by complete values
True
>>> (1, 3, 4) in S
False

集合只能包含不可变(即可散列的)的对象类型,列表和字典不能嵌入到集合中,元组可以嵌入到集合中

集合不能直接嵌入到其他集合中,需要调用frozenset创建一个不可变的集合

Python 3.0中的集合解析

集合解析运行一个循环并在每次迭代时收集一个表达式的结果,通过一个循环变量来访问当前的迭代值以用于集合表达式中

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> {x ** 2 for x in [1, 2, 3, 4]}	# 3.0 set comprehension
{16, 1, 4, 9}
>>> {x for x in 'spam'} # Same as:set('spam')
{'m', 'a', 's', 'p'}
>>> {c * 4 for c in 'spam'} # Set of collected expression results
{'aaaa', 'ssss', 'pppp', 'mmmm'}
>>> {c * 4 for c in 'spamham'}
{'aaaa', 'mmmm', 'pppp', 'hhhh', 'ssss'}
>>> S = {c * 4 for c in 'spam'}
>>> S | {'mmmm','xxxx'}
{'pppp', 'aaaa', 'ssss', 'xxxx', 'mmmm'}
>>> S & {'mmmm', 'xxxx'}
{'mmmm'}

循环部分编写在右边,集合表达式编写在左边

解析可以迭代序列、字符串或其他类型的对象

为什么使用集合

1
2
3
4
5
6
>>> L = [1, 2, 1, 3, 2, 4 ,5]
>>> set(L)
{1, 2, 3, 4, 5}
>>> L = list(set(L)) # Remove duplicates
>>> L
[1, 2, 3, 4, 5]
  • 集合用来过滤掉重复项
  • 集合用来记录已经访问过的位置
  • 两个集合的交集包含了共有的对象,并集包含了两个集合中的所有对象

布尔型

布尔型数据类型的值为TrueFalse,是整数类型int的子类,其行为和整数10相同

1
2
3
4
5
6
7
8
9
10
11
12
>>> type(True)
<class 'bool'>
>>> isinstance(True,int)
True
>>> True == 1 # Same value
True
>>> True is 1 # But different object:see the next chapter
False
>>> True or False # Same as:1 or 0
True
>>> True + 4 # (Hmmm)
5

可以将TrueFlase看做是预定义的设置为整数10


数字拓展

可选的Python拓展NumPy提供了高级的数字编程工具,例如矩阵数据类型、向量处理和高级的计算库


本章习题

  1. Python中表达式2 * (3 + 4)的值是多少

    结果的值将会是14,即2*7的结果,因为括号强制让加法在乘法前进行运算

  2. Python中表达式2 * 3 + 4的值是多少

    这里结果会是10,即6 + 4的结果

    Python的操作符优先级法则应用在没有括号存在的场合,乘法的优先级要比加法的优先级高(先进行运算)

  3. Python中表达式2 + 3 * 4的值是多少

    表达式将得到14,即2 + 12的结果,正如前一个问题一样是优先级的原因

  4. 通过什么工具你可以找到一个数字的平方根以及它的平方

    求平方根、pi以及正切等等函数,在导入math模块后即可使用

    为了找到一个数字的平方根,import math后调用math. sqrt(N)

    为了得到一个数字的平方,使用指数表达式X **2,或者内置函数pow(X, 2)

    上述两种方式的任何一种也可以用来计算一个数的0.5次方(例如,X ** .5)

  5. 表达式1+2.0+3的结果是什么类型

    结果将是一个浮点数:整数将会变换升级成浮点数,这个表达式中最复杂的类型,然后使用浮点数的运算法则进行计算

  6. 怎样能够截断或舍去浮点数的小数部分

    int(N)函数和math. trunc(N)函数会省略小数部分,而round(N, digit)函数做四舍五人

    可以使用math. floor(N)来计算floor,并且使用字符串格式化操作来舍入以便于显示

  7. 怎样将-一个整数转换为浮点数

    float(I)将整数转换为浮点数

    在表达式中混合整数和浮点数也会实现转换

    在某种意义上,Python 3.0的/除法也会转换,它总是返回一个包含余数的浮点数结果,即便两个操作数都是整数

  8. 如何将一个整数显示成八进制、十六进制或二进制的形式

    内置函数oct(I)hex(I)bin(I)会将整数以八进制数、十六进制数和二进制数字符串的形式返回,%字符串格式化表达式和字符串格式化方法也为这样的转换提供方法

  9. 如何将一个八进制、十六进制或二进制数的字符串转换成平常的整数

    int(S,base)函数能够用来让一个八进制和十六进制数的字符串转换为正常的整数(传入8、16或2作为base的参数)

    eval(S)函数也能够用作这个目的,但是运行起来开销更大也有可能导致安全问题

    注意整数总是在计算机内存中以二进制保存的,这些只不过是显示的字符串格式的转换而已


第六章 动态类型简介

本章对动态类型进行了深入的学习

  • 学习了Python中变量和对象是如何通过引用关联在一起的
  • 探索了垃圾收集的概念
  • 学到了对象共享引用是如何影响多个变量的
  • 看到了Python中引用是如何影响相等的概念

缺少类型声明语句的情况

在Python中,类型是在运行过程中自动决定的,而不是通过代码声明

变量、对象和引用

变量创建

当代码第一次给一个变量赋值时就创建了它

之后的赋值将会改变已创建的变量名的值

变量类型

变量永远不会有任何的和它关联的类型信息或约束

类型的概念是存在于对象中而不是变量名中

变量使用

当变量出现在表达式中时,它会马上被当前引用的对象所代替,无论这个对象是什么类型

所有的变量必须在使用前明确地赋值,使用未赋值的变量会产生错误

对象

对象有两个标准的头部信息:

  • 一个类型标志符去标识这个对象的类型
  • 一个引用的计数器,用来决定是不是可以回收这个对象

引用

从变量到对象的连接称作引用

  • 变量是一个系统表的元素,拥有指向对象的连接的空间
  • 对象是分配的一块内存,有足够的空间去表示它们所代表的值
  • 引用是自动形成的从变量到对象的指针

类型属于对象,而不是变量

1
2
3
>>> a = 3		# It's an integer
>>> a = 'spam' # Now it's a string
>>> a = 1.23 # Now it's a floating point

变量名没有类型,修改变量只是修改为对不同的对象的引用

类型属于对象,对象的头部信息标记了对象的类型

对象的垃圾收集

当一个变量名被赋予了一个新的对象时,如果之前的对象没有被其他的变量名或对象引用,就会被回收

回收的对象的空间自动放入自由内存空间池,等待后来的对象使用

每个对象都保持了一个计数器,计数器记录了当前指向该对象的引用的数目,一旦这个计数器被设置为零,这个对象的内存空间就会自动回收

垃圾收集使脚本任意使用对象而不需要考虑释放内存空间


共享引用

一个变量赋值为另一个变量后,实际的效果是两个变量引用相同的对象,即共享引用

当其中一个变量引用了新的对象后,另一个变量并不会被改变,仍然引用原始的对象

共享引用和在原处修改

1
2
3
4
5
6
7
>>> L1 = [2, 3, 4]	# A mutable object
>>> L2 = L1 # Make a reference to the same object
>>> L1[0] = 24 # An in-place change
>>> L1
[24, 3, 4] # L1 is different
>>> L2
[24, 3, 4] # But so is L2!

对于支持在原处修改的对象,共享引用时对一个变量名的修改会影响其他的变量

1
2
3
4
5
6
7
8
>>> L1 = [2 , 3, 4]
>>> L2 = L1[:] # Make a copy of L1
>>> L1[0] = 24
>>> L1
[24, 3, 4]
>>> L2 # L2 is not changed
[2, 3, 4]
>>>

如果修改不想影响到另一个变量,需要Python拷贝对象,而不是创建引用

拷贝列表的方法

  • 内置列表函数

  • 标注库的copy模块

    适用于复制任意对象类型的调用

    拷贝嵌套对象结构的调用

  • 从头到尾切片

共享引用和相等

1
2
3
4
5
6
7
8
9
10
11
12
>>> L = [1, 2, 3]
>>> M = L # M and L reference the same object
>>> L == M # Same value
True
>>> L is M # Same object
True
>>> L = [1, 2, 3]
>>> M = [1, 2, 3] # M and L reference different objects
>>> L == M # Same values
True
>>> L is M # Different objects
False

==操作符测试两个被引用的对象是否有相同的值

is操作符检查对象的同一性,是检测共享引用的一种方法

1
2
3
4
5
6
>>> X = 42
>>> Y = 42 # Should be two different objects
>>> X == Y
True
>>> X is Y # Same object anyhow:caching at work!
True

Python缓存并复用了小的整数和小的字符串,不会被回收

1
2
3
>>> import sys
>>> sys.getrefcount(1) # 749 pointers to this shared piece of memory
749

sys模块中的getrefcount函数会返回对象的引用次数


动态类型随处可见

Python中任何东西都是通过赋值和引用工作的


本章习题

  1. 思考下面三条语句,它们会改变A打印出的值吗

    1
    2
    3
    A ="spam"
    B =A
    B ="shrubbery"

    不:

    A仍会作为spam进行打印

    当B赋值为字符串shrubbery时,所发生的只是变量B被重新设置为指向了新的字符串对象,A和B最初共享(即引用或指向)了同一个字符串对象spam,但是在Python中这两个变量名从未连接在一起,因此,设置B为另一个不同的对象对A没有影响

    如果这里最后的语句变为B=B+'shrubbery',也会发生同样的事情
    另外,合并操作创建了一个新的对象作为其结果,并将这个值只赋值给了B,我们永远都不会在原处覆盖一个字符串(数字或元组),因为字符串是不可变的

  2. 思考下面三条语句,它们会改变A的值吗

    1
    2
    3
    A =["spam" ]
    B =A
    B[0] = "shrubbery"

    是:

    A现在打印为["shrubbery"]

    从技术上讲,我们既没有改变A也没有改变B,我们改变的是这两个变量共同引用(指向)的对象的一部分

    通过变量B在原处覆盖了这个对象的一部分内容,因为A像B一样引用了同一个对象,这个改变也会对A产生影响

  3. 这样如何,A会改变吗

    1
    2
    3
    ["spam"]
    B = A[:]
    B[0] = "shrubbery"

    不会:

    A仍然会打印为["spam"]

    由于分片表达式语句会在被赋值给B前创建一个拷贝,这次对B在原处赋值就不会有影响了

    在第二个赋值语句后,就有了两个拥有相同值的不同列表对象了(在Python中, 我们说它们是==的,却不是is的)
    第三条赋值语句会改变指向B的列表对象,而不会改变指向A的列表对象


第七章 字符串

本章深入学习字符串这个对象类型

  • 学习如何编写字符串常量
  • 探索字符串操作,包括序列表达式、字符串格式化以及字符串方法调用
    • 学习各种概念,例如,分片、方法调用、三重引号字符串
    • 定义一些关于变量类型的核心概念,例如,序列会共享整个操作的集合

常见字符串常量和操作

操作 解释
S = ‘’ 空字符串
S = “spam’s” 双引号和单引号相同
S = ‘s\np\ta\x00m’ 转义序列
S = “””…””” 三重引号字符串块
S = r’\temp\spam’ Raw字符串
S = b’spam’ Python 3.0中的字节字符串
S = u’spam’ 仅在Python 2.6中使用的Unicode字符串
S1 + S2 合并
S * 3 重复
S[i] 索引
S[i:j] 分片
len(S) 求长度
“a %s parrot” % kind 字符串格式化表达式
“a {0} parrot”.format(kind) python 2.6和Python 3.0中的字符串格式化方法
S.find(‘pa’) 字符串方法调用:搜索
S.rstrip() 移除空格
S.replace(‘pa’,’xx’) 替换
S.split(‘,’) 用占位符分割
S.isdigit() 内容测试
S.lower() 短信息转换
S.endswith(‘spam’) 结束测试
‘spam’.join(strlist) 插入分隔符
S.encode(‘latin-1’) Unicode编码
for x in S:print(x) 迭代
‘spam’ in S 成员关系
[c * 2 for c in S] 列表解析表达式
map(ord, S)

字符串常量

编写

  • 单引号:'spa''m'
  • 双引号:"spa'm"
  • 三引号:’’’…spam…’’’,”””…spam…”””
  • 转义字符:”s\tp\na\0m”
  • Raw字符串:r”C:\new\test.spm”
  • Byte字符串:b’sp\x01am’
  • 仅在Python 2.6中使用的Unicode字符串:u’eggs\u0020spam’

单双引号字符串是一样的

在Python字符串中,单引号和双引号字符是可以互换的,两种形式同样有效并返回相同类型的对象

1
2
3
4
>>> 'kight"s', "knight's"
('kight"s', "knight's")
>>> 'knight\'s', "knight\"s"
("knight's", 'knight"s')

两种形式可以不用\转义字符就实现在一个字符串中包含另一种引号

可以通过反斜杠转义字符嵌入引号

1
2
3
>>> title = "Meaning " 'of' " Life"
>>> title
'Meaning of Life'

Python自动在任意的表达式中合并相邻的字符串常量

可以在字符串之间增加+操作符进行合并

用转义序列代表特殊字节

\用来引入特殊的字符编码,即转义序列

字符串常量中字符\及它后边的一个或多个字符会被一个单个字符所替代,这个字符通过转义序列定义了一个二进制值

\n被替换为一个换行字符(ASCII编码为10)

转义 意义
\newline 忽视(连续)
\ 反斜杠(保留\)
\‘ 单引号(保留’)
\‘’ 双引号(保留”)
\a 响铃
\b 倒退
\f 换页
\n 新行
\r 返回
\t 水平制表符
\v 垂直制表符
\N{id} Unicode数据库ID
\uhhhh Unicode 16位的十六进制值
\xhhhhhhhh Unicode 32位的十六进制值
\xhh 十六进制值
\000 八进制值
\0 Null
\other 不转义(保留)

转义字符列表

Python允许嵌入绝对的二进制值(以八进制编码嵌入)

Python没有字符串结尾标志符

没有合法的转义编码识别出现在\后时会保留反斜杠

1
2
3
4
5
6
>>> s = 'a\nb\tc'
>>> s
'a\nb\tc'
>>> print(s)
a
b c

交互模式下以转义字符形式回显,print将其解释出来

1
2
3
>>> s = 'a\nb\tc'
>>> len(s)
5

内置len函数返回一个字符串字节数而非显示的字符数

raw字符串抑制转义

在字符串的引号前输入r会关闭转义机制,\作为常量保持

raw字符串也可用于正则表达式

在Windows下使用/\表示路径同样有效

1
2
3
4
5
6
7
>>> path = r'C:\new\text.dat'
>>> path # Show as Python code
'C:\\new\\text.dat'
>>> print(path) # User-friendly format
C:\new\text.dat
>>> len(path) # String length
15

交互提示模式下Python会显示转义序列

打印语句提供了对用户友好的格式

1
2
3
4
5
6
7
8
9
>>> r"...\"
File "<stdin>", line 1
r"...\"
^
SyntaxError: EOL while scanning string literal
>>> r'1\nb\tc\\'[:-1]
'1\\nb\\tc\\'
>>> r'1\nb\tc' + '\\'
'1\\nb\\tc\\'

raw字符串不能以单个反斜杠结尾

可以使用两个反斜杠分片掉第二个反斜杠或手动添加一个反斜杠

三重引号编写多行字符串块

以三重引号(单引号或双引号)开始,紧跟任意行数的文本,以开始时的同样的三重引号结尾

  • 三重引号可以输入多行文本
  • 三重引号可用作多行注释
  • 三重引号可以在开发过程中废除一些代码
1
2
3
4
5
6
7
8
9
>>> mantra = """Always look
... on the bright
... side of life."""
>>> mantra
'Always look\non the bright\nside of life.'
>>> print(mantra)
Always look
on the bright
side of life.

嵌入在这个字符串文本中的单引号和双引号可以转义也可以不转义

代码折行处会被替换为\n


实际应用中的字符串

基本操作

1
2
3
4
5
6
>>> len('abc')		# Length:number of items
3
>>> 'abc' + 'def' # Concatenation:a new string
'abcdef'
>>> 'Ni!' * 4 # Repetition:like "Ni!" + "Ni!" + ...
'Ni!Ni!Ni!Ni!'

+操作符进行合并

*操作符进行重复

len函数返回一个字符串的长度

结果是创建了一个新的字符串对象

1
2
3
4
5
6
7
8
9
10
>>> myjob = "hacker"
>>> for c in myjob:print(c, end=' ') # Step through items
...
h a c k e r
>>> "k" in myjob # Found
True
>>> "z" in myjob # Not found
False
>>> 'spam' in 'abcspamdef' # Substring saerch,no position returned
True

for语句可以在字符串中进行循环迭代

in表达式操作符对字符和子字符串进行成员关系测试,返回布尔结果

索引和切片

字符串中的字符通过索引提取

  • 第一个元素的偏移量为0
  • 负偏移索引意味着从右边反向计数

分片是索引的一种通用形式,返回部分字符串而不是单个字符

  • 以冒号分割上下边界
  • 上边界不包含在内
  • 没有给出时,下边界默认为0,上边界默认为序列长度
1
2
3
4
5
>>> S = 'spam'
>>> S[0], S[-2] # Indexing from front or end
('s', 'a')
>>> S[1:3], S[1:], S[:-1] # Slicing:extract a section
('pa', 'pam', 'spa')

负偏移+字符串长度=正偏移值

拓展分片:第三个限制值

X[I:J:K]

第三个索引用作步进,表示索引X对象中从偏移为I到偏移为J-1,每隔K元素索引一次,K默认为

负值表示从右到左步进

1
2
3
4
5
6
7
8
>>> 'spam'[1:3]
'pa'
>>> 'spam'[slice(1,3)] # Slicing syntax
'pa'
>>> 'spam'[::-1] # Slice objects
'maps'
>>> 'spam'[slice(None,None,-1)]
'maps'

分片等同于用一个分片对象进行索引

为什么要在意:分片

  • 分片可以仅返回需要的项
  • 分片可以清除每行字符的换行符,但是采用line.rstrip()更好,因为可以留下没有换行符的行的最后一个字符

字符串转换工具

1
2
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not int

Python中不能让数字与字符串相加

1
2
3
4
5
6
>>> int("42"),str(42)	# Convert from/to string
(42, '42')
>>> repr(42) # Convert to as-code string
'42'
>>> print(str('spam'),repr('spam'))
spam 'spam'

int函数将字符串转换为数字

str函数将数字转换为字符串表达式

repr函数将一个对象转换为字符串形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> S = "42"
>>> I = 1
>>> S + I
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not int
>>> int(S) + I # Force addition
43
>>> S + str(I) # Force concatenation
'421'
>>> str(3.1415),float("1.5")
('3.1415', 1.5)
>>> text = "1.234E-10"
>>> float(text)
1.234e-10

对字符串和数字类型使用+运算时可以手动转换

str函数可以把浮点数转换成字符串

int函数可以把字符串转换成整数

float函数可以把字符串转换成浮点数

eval将会运行一个包含了Python表达式代码的字符串,并能够将字符串转换为任意类型的对象

字符串代码转换

1
2
3
4
5
6
7
8
9
10
11
>>> ord('s')
115
>>> chr(115)
's'
>>> S = '5'
>>> S = chr(ord(S) + 1)
>>> S
'6'
>>> S = chr(ord(S) + 1)
>>> S
'7'

ord函数将单个字符转换为对应的ASCII

chr函数获取ASCII码并将其转换为对应的字符

配合使用可以生成下一个字符

1
2
3
4
5
6
7
8
9
10
11
12
>>> B = '1101'		# Convert binary digits to integer with ord
>>> I = 0
>>> while B != '':
... I = I * 2 + (ord(B[0]) - ord('0'))
... B = B[1:]
...
>>> I
13
>>> int('1101', 2) # Convert binary to integer:built-in
13
>>> bin(13) # Convert integer to binary
'0b1101'

与循环语句一起配合使用,可以将一个表示二进制数的字符串转化为等值的整数

修改字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> S = 'spam'
>>> S[0] = "x"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> S = S + "SPAM!" # To change a string,make a new one
>>> S
'spamSPAM!'
>>> S = S[:4] + 'Burger' + S[-1]
>>> S
'spamBurger!'
>>> 'spamBurger!'
'spamBurger!'
>>> S = 'splot'
>>> S = S.replace('pl','pamal')
>>> S
'spamalot'

字符串不能在原处修改,需要利用合并、分片这样的工具来建立并赋值给一个新的字符串

字符串方法每次都生成新的字符串对象

str.replace(arg1,arg2)方法将指定字符串进行替换并生成新的字符串对象

1
2
3
4
>>> 'That is %d %s bird!' % (1, 'dead')			# Format expression
'That is 1 dead bird!'
>>> 'That is {0} {1} bird!'.format(1, 'dead') # Format method in 2.6 and 3.0
'That is 1 dead bird!'

可以通过字符串格式化表达式来创建新的文本值

格式化的结果是根据指定的格式创建新的字符串对象


字符串方法

表达式和内置函数可能在不同范围的类型有效,方法特定于对象类型

方法调用同时进行了两次操作:获取属性和函数调用

  • 属性读取

    object.attribute格式的表达式可以理解为读取object对象的attribute的值

  • 函数调用表达式

    具有函数(参数)格式的表达式意味着调用函数代码,传递0或更多用都好隔开的参数对象,最后返回函数的返回值

Python 3.0中的字符串方法调用

方法 作用
S.capitalize()
S.ljust(width [, fill])
S.center(width [, fill])
S.lower()
S.count(sub [, start [, end]])
S.lstrip([chars])
S.encode([encoding [, errors]])
S.maketrans(x[, y[, z]])
S.endswith()
S.partition(sep)
S.expandtabs([tabsize])
S.replace(old, new [, count])
S.find(sub [, start [, end]])
S.rfind(sub [,start [, end]])
S.format(fmtstr, args, *kwargs)
S.rindex(sub [, start [, end]])
S.index(sub [, start [, end]])
S.rjust(width [, fill])
S.isalnum()
S.isalpha()
S.isdecimai()
S.isdigit()
S.isidentifier()
S.islower()
S.isnumeric()
S.isprintable()
S.isspace()
S.istitle()
S.isupper()
S.join(iterable)
S.rpartition(sep)
S.rsplit([sep[, maxsplit]])
S.rstrip([chars])
S.split([sep [,maxsplit]])
S.splitlines([keepends])
S.startswith(prefix [. start [. end]])
S.strip([chars])
S.swapcase()
S.title()
S.translate(map)
S.upper()
S.zfill(width)

字符串方法实例:修改字符串

1
2
3
4
5
6
7
8
9
10
>>> S = 'spammy'
>>> S = S[:3] + 'xx' + S[5:]
>>> S
'spaxxy'
>>> S = 'spammy'
>>> S = S.replace('mm', 'xx')
>>> S
'spaxxy'
>>> 'aa$bb$cc$dd'.replace('$', 'SPAM')
'aaSPAMbbSPAMccSPAMdd'

replace方法的参数是原始子字符串和替换原始子字符串的字符串,之后进行全局搜索并替换

1
2
3
4
5
>>> S = 'xxxxSPAMxxxxSPAMxxxx'
>>> S.replace('SPAM', 'EGGS') # Replace all
'xxxxEGGSxxxxEGGSxxxx'
>>> S.replace('SPAM', 'EGGS', 1) # Replace one
'xxxxEGGSxxxxSPAMxxxx'

第三个参数可以只替换溢出

1
2
3
4
5
6
7
>>> S = 'xxxxSPAMxxxxSPAMxxxx'
>>> where = S.find('SPAM') # Search for position
>>> where # Occurs at offset 4
4
>>> S = S[:where] + 'EGGS' + S[(where+4):]
>>> S
'xxxxEGGSxxxxSPAMxxxx'

find方法返回子字符串出现的偏移,未找到时返回-1

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> S = 'spammy'
>>> L = list(S)
>>> L
['s', 'p', 'a', 'm', 'm', 'y']
>>> L[3] = 'x' # Works for lists, not strings
>>> L[4] = 'x'
>>> L
['s', 'p', 'a', 'x', 'x', 'y']
>>> S = ''.join(L)
>>> S
'spaxxy'
>>> 'SPAM'.join(['eggs', 'sausage', 'ham', 'toast'])
'eggsSPAMsausageSPAMhamSPAMtoast'

当对一个超长字符串进行修改较多时,可能需要将字符串转换为一个支持原处修改的对象

list函数以任意序列中的元素创立一个新的列表

str.join()方法将列表字符串连在一起并用分隔符隔开

字符串方法实例:文本解析

文本解析:分析结构并提取子串

1
2
3
4
5
6
7
8
9
10
>>> line = 'aaa bbb ccc'
>>> cols = line.split()
>>> cols
['aaa', 'bbb', 'ccc']
>>> line = 'bob,hacker,40'
>>> line.split(',')
['bob', 'hacker', '40']
>> line = "i'mSPAMaSPAMlumberjack"
>>> line.split("SPAM")
["i'm", 'a', 'lumberjack']

str.split()方法将一个字符串分割为一个子字符串的列表,以分隔符字符串为标准

分隔符默认为空格(空格、制表符、换行符)

分隔符可以是多个字符的字符串

实际应用中的其他常见字符串方法

1
2
3
4
5
6
7
8
9
10
11
>>> line = "The knights who say Ni!\n"
>>> line.rstrip()
'The knights who say Ni!'
>>> line.upper()
'THE KNIGHTS WHO SAY NI!\n'
>>> line.isalpha()
False
>>> line.endswith('Ni!\n')
True
>>> line.startswith('The')
True

str.strip()方法清除每行末尾的空格(空格、换行符、制表符)

str.upper()将字母转换为大写

str.isalpha()测试是否所有字符都为字母

str.endswith()测试末尾的子字符串

str.startswith()测试起始的子字符串

1
2
3
4
5
6
7
8
9
10
11
>>> line = 'The knights who say Ni!\n'
>>> line.find('Ni') != -1 # Search via method call or expression
True
>>> 'Ni' in line
True
>>> sub = 'Ni!\n'
>>> line.endswith(sub) # End test via method call or slice
True
>>> line[-len(sub):] == sub
True
>>>

成员操作符in能够用来检测一个子字符串是否存在

len和分片操作能够用来做字符串末尾的检测

最初的字符串模块(在Python 3.0中删除)

Python出现的前十年,只提供string标准库模块处理字符串,其中包含的函数大约相当于目前的字符串对象方法集

Python 2.0时,增加字符串对象方法,为了保持兼容性仍保留string模块

Python 3.0中已删除string模块中同等的字符串方法,只保留了预定义的字符串常数以及模板对象系统

Python 2.6中有两种方法启用高级字符串操作

  • 调用对象方法

    str.method(arguments)

  • 调用string模块,把对象当成自变量传递进去

    string.method(str,arguments)

使用方法调用而不是模块调用的理由

  • 模块调用已从Python 3.0版删除
  • 模块调用法需要导入string模块
  • 模块调用需要多打几个字符(以import加载模块而不是from时)
  • 模块运行速度比方法慢
1
2
3
4
5
6
7
8
>>> S = 'a+b+c+'
>>> x = S.replace('+', 'spam')
>>> x
'aspambspamcspam'
>>> import string
>>> y = string.replace(S, '+', 'spam')
>>> y
'aspambspamcspam'

要通过string模块获取相同的操作,需要先导入该模块并传入对象


字符串格式化表达式

字符串格式化允许在一个单个的步骤中对一个字符串执行多个特定类型的替换

格式化会返回新的字符串作为结果而不是对原始的格式化字符串进行修改

字符串格式化实现形式

  • 字符串格式化表达式
  • 字符串格式化方法调用

字符串格式化表达式

%提供了简单的方法对字符串的值进行格式化,这一操作取决于格式化定义的字符串

格式化字符串

  • %操作符左侧放置一个需要进行格式化的字符串,这个字符串带有一个或多个嵌入的转换目标,都以%开头
  • %操作符右侧放置一个对象,这个对象将会插入到左侧想让Python进行格式化字符串的一个(或多个)转换目标的位置上去
1
2
3
4
5
6
7
8
9
>>> 'That is %d %s bird!' % (1, 'dead')		# Format expression
'That is 1 dead bird!'
>>> exclamation = "Ni"
>>> "The knights who say %s!" % exclamation
'The knights who say Ni!'
>>> "%d %s %d you" % (1, 'spam', 4)
'1 spam 4 you'
>>> "%s -- %s -- %s" % (42, 3.14159, [1, 2, 3])
'42 -- 3.14159 -- [1, 2, 3]'

当不止一个值待插入时,%右侧应放置包含多个值的元组对象

%s将其对应的不同类型的对象转换为字符串类型打印

更高级的字符串格式化表达式

字符串格式化代码

代码 意义
s 字符串(或任何对象)
r s,但是用repr,而不是str
c 字符
d 十进制整数
i 整数
u 无符号整数
o 八进制整数
x 十六进制整数
X x,但打印大写
e 浮点指数
E e,但打印大写
f 浮点十进制
F 浮点十进制
g 浮点e或f
G 浮点E或F
% 常量%

转换目标的通用结构

%[(name)][flags][width][.precision]typecode

  • width

    字符最小宽度

  • .precision

    字符最大宽度

  • typecode

    字符串格式化代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> x = 1234
>>> res = "integers:...%d...%-6d...%06d" % (x, x, x)
>>> res
'integers:...1234...1234 ...001234'
>>> x = 1.23456789
>>> x
1.2345678899999999
>>> '%e | %f | %g' % (x, x, x)
'1.234568e+00 | 1.234568 | 1.23457'
>>> '%E' % x
'1.234568E+00'
>>> '%-6.2f | %05.2f | %+6.1f' % (x, x, x)
'1.23 | 01.23 | +1.2'
>>> "%s" % x, str(x)
('1.23456789', '1.23456789')
  • -左对齐
  • +正负号
  • 0补零
  • 数字为位数(浮点数包括小数点及小数点后的位数)
  • 小数点后的数字为小数点后的位数
1
2
>>> '%f, %.2f, %.*f' % (1/3.0, 1/3.0, 4, 1/3.0)
'0.333333, 0.33, 0.3333'

使用*指定通过计算得出的width.precision,其对应值为%运算符右边输出的下一项

基于字典的字符串格式化

字符串格式化允许左边的转换目标来引用右边字典中的键来提取对应的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>> "%(n)d %(x)s" % {"n":1, "x":"spam"}
'1 spam'
>>> "%(n)d %(x)s" % {"n":1, "x":"spam"}
'1 spam'
>>> reply = """ # Template with substitution targets
... Greetings...
... Hello %(name)s!
... Your age squared is %(age)s
... """
>>> values = {'name': 'Bob', 'age': 40} # Build up values to substitute
>>> print(reply % values) # Preform substitutions

Greetings...
Hello Bob!
Your age squared is 40

格式化字符串%(key)括号引用%操作符右边字典中的键,并提取出它们相应的值

1
2
3
4
5
6
>>> food = 'spam'
>>> age = 40
>>> vars()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'food': 'spam', 'age': 40}
>>> "%(age)d %(food)s" % vars()
'40 spam'

内置函数`vars返回所有在本函数调用时存在的变量的字典对象,可以让格式化字符串通过变量名来访问变量


字符串格式化调用方法

基础知识

字符串对象的format方法使用主体字符串作为模板,接受任意多个表示将要根据模板替换的值的参数

主体字符串中,{}通过positionkeyword指出替换目标及将要插入的参数

1
2
3
4
5
6
7
8
9
10
11
>>> template = '{0}, {1} and {2}'				# By position
>>> template.format('spam', 'ham', 'eggs')
'spam, ham and eggs'
>>> template = '{motto}, {pork} and {food}' # By keyword
>>> template.format(motto='spam', pork='ham', food='eggs')
'spam, ham and eggs'
>>> template = '{motto}, {0} and {food}' # By both
>>> template.format('ham', motto='spam', food='eggs')
'spam, ham and eggs'
>>> '{motto}, {0} and {food}'.format(42, motto=3.14, food=[1,2])
'3.14, 42 and [1, 2]'

函数和方法的参数可以使用positionkeyword来传递

1
2
3
4
5
6
7
8
9
10
>>> somelist = list('SPAM')
>>> somelist
['S', 'P', 'A', 'M']
>>> 'first={0[0]}, third={0[2]}'.format(somelist)
'first=S, third=A'
>>> 'first={0}, last={1}'.format(somelist[0], somelist[-1]) # [-1] fails in fmt
'first=S, last=M'
>>> parts = somelist[0], somelist[-1], somelist[1:3] # [1:3] fails in fmt
>>> 'first={0}, last={1}, middle={2}'.format(*parts)
"first=S, last=M, middle=['P', 'A']"

format创建并返回一个新的字符串对象

添加键、属性和偏移量

格式化字符串可以指定对象属性和字典键

  • 方括号指定字典键或序列偏移量
  • 点表示’position'或keyword`所引用对象的对象属性
1
2
3
4
5
>>> import sys
>>> 'My {1[spam]} runs {0.platform}'.format(sys, {'spam':'laptop'})
'My laptop runs darwin'
>>> 'My {config[spam]} runs {sys.platform}'.format(sys=sys, config={'spam': 'laptop'})
'My laptop runs darwin'

只有单个的正的偏移才能在格式化字符串的语法中生效

必须在格式化字符串之外才能指定负的偏移或分片

添加具体格式化

替换目标的标识之后使用一个冒号,后面跟着可以指定字段大小、对齐方式和一个特定类型编码的格式化声明

格式化字符串形式

{fieldname!conversionflag:formatspec}

其中formatspec组成形式(方括号表示可选的组成,并且不能编写为常量)

[[fill]align][sign][#][0][width][/precision][typecode]

  • fieldname

    指定参数的一个数字或关键字,后面跟着可选的.name[index]

  • conversionflag

    可以是rsa分别是在该值上对reprstrascii内置函数的一次调用

  • Formatspec

    指定如何表示该值,包括字段宽度、对齐方式、补零、小数点精度等

    可以包含嵌套的、只带有{}的格式化字符串,它从参数列表动态地获取值

    • align

      可以是<>=或’^`,表示左对齐、右对齐、一个标记字符后的补充或居中对齐’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> import sys
>>> '{0:10} = {1:10}'.format('spam', 123.4567)
'spam = 123.4567'
>>> '{0:>10} = {1:<10}'.format('spam', 123.4567)
' spam = 123.4567 '
>>> '{0.platform:>10} = {1[item]:<10}'.format(sys, dict(item='laptop'))
' darwin = laptop '
>>> '{0:e}, {1:.3}, {2:g}'.format(3.14159,3.14159,3.14159)
'3.141590e+00, 3.14, 3.14159'
>>> '{0:e}, {1:.3e}, {2:8}'.format(3.14159, 3.14159, 3.14159)
'3.141590e+00, 3.142e+00, 3.14159'
>>> '{0:f}, {1:.2f}, {2:06.2f}'.format(3.14159, 3.14159, 3.14159)
'3.141590, 3.14, 003.14'
>>> '{0:X}, {1:o}, {2:b}'.format(255, 255, 255) # Hex,octal,binary
'FF, 377, 11111111'
>>> bin(255), int('11111111', 2), 0b11111111 # Other to/from binary
('0b11111111', 255, 255)
>>> hex(255), int('FF',16), 0xFF # Other to/from hex
('0xff', 255, 255)
>>> oct(255), int('377', 8), 0o377 # Other to/from octal
('0o377', 255, 255) # 0377 works in 2.6, not 3.0!

%类型编码显示百分比

b类型编码用来以二进制格式显示整数

d唯一表示十进制整数而不是iu

浮点数支持与%表达式中相同的类型代码和格式化声明

格式化方法支持十六进制、八进制值和二进制格式

1
2
3
4
5
6
7
8
>>> '{0:.2f}'.format(1 / 3.0)		# Paramenters hardcoded
'0.33'
>>> '%.2f' % (1 / 3.0)
'0.33'
>>> '{0:.{1}f}'.format(1 / 3.0, 4) # Take value from arguments
'0.3333'
>>> '%.*f' % (4, 1 / 3.0) # Ditto for expression
'0.3333'

格式化参数可以通过嵌套的格式化语法从参数列表动态获取

1
2
3
4
5
6
>>> '{0:.2f}',format(1.2345)	# String method
('{0:.2f}', '1.2345')
>>> format(1.2345, '.2f') # Built-in function
'1.23'
>>> '%.2f' % 1.2345 # Expression
'1.23'

内置format函数可以用来格式化一个单独的项

与%格式化表达式比较

  • 字符串格式化方法与%格式化表达式很像
1
2
3
4
>>> print('%s=%s' % ('spam', 42))
spam=42
>>> print('{0}={1}'.format('spam', 42))
spam=42
  • 通常情况下格式化表达式比格式化方法调用更容易编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Hardcoded references in both

>>> 'My {1[spam]:<8} runs {0.platform:>8}'.format(sys, {'spam': 'laptop'})
'My laptop runs darwin'
>>> 'My %(spam)-8s runs %(plat)8s' % dict(spam='laptop', plat=sys.platform)
'My laptop runs darwin'

# Building data ahead of time in both

>>> data = dict(platform=sys.platform, spam='laptop')
>>> 'My {spam:<8} runs {platform:>8}'.format(**data)
'My laptop runs darwin'
>>> 'My %(spam)-8s runs %(platform)8s' % data
'My laptop runs darwin'
  • 格式化方法拥有%表达式所没有的很多高级功能,更复杂的格式化也能降低复杂度
1
2
3
4
5
6
7
8
9
10
>>> '{0:d}'.format(999999999999)
'999999999999'
>>> '{0:,d}'.format(999999999999)
'999,999,999,999'
>>> '{:,d}'.format(999999999999)
'999,999,999,999'
>>> '{:,d} {:,d}'.format(9999999,8888888)
'9,999,999 8,888,888'
>>> '{:,.2f}'.format(296999.2567)
'296,999.26'

字符串格式化方法支持针对数字的千分位隔位法

为什么用新的格式化方法

格式化方法

  • 拥有%表达式所没有的一些额外功能
  • 可以更明确地进行替代值引用
  • 考虑到操作符会有一个更容易记住的方法名
  • 不支持用于单个和多个替代之大小写的不同语法

额外功能

方法调用支持表达式所没有的一些额外功能,例如二进制类型编码千分位分组

方法调用支持直接的键和属性引用,格式化表达式以其他方法实现同样效果

显示值引用

当很多值需要替换到格式化字符串中时,方法的position{}比表达式的%s更易读

当省略方法’position’的’{}’中的替换值时,可读性同样会变差

1
2
3
4
5
6
>>> '{0:f}, {1:.2f}, {2:05.2f}'.format(3.14159, 3.14159, 3.14159)
'3.141590, 3.14, 03.14'
>>> '{:f}, {:.2f}, {:06.2f}'.format(3.14159, 3.14159, 3.14159)
'3.141590, 3.14, 003.14'
>>> '%f, %.2f, %06.2f' % (3.14159, 3.14159, 3.14159)
'3.141590, 3.14, 003.14'

在浮点数格式化上,格式化表达式更为精准且更为整齐

方法名和通用参数

格式化方法用一个更加方便于记忆的格式化方法名format替代了%操作符

1
2
3
4
5
6
7
8
9
10
11
12
13
'1.23'
>>> '%s' % (1.23,)
'1.23'
>>> '%s' % ((1.23,),)
'(1.23,)'
>>> '{0:.2f}'.format(1.2345)
'1.23'
>>> '{0:.2f} {1}'.format(1.2345,99)
'1.23 99'
>>> '{0}'.format(1.2345)
'1.2345'
>>> '{0}'.format((1.2345,))
'(1.2345,)'

使用格式化表达式单个值可以独自给定,但多个值必须收入一个元组中,而格式化方法不区分单个和多个替代值

格式化表达式单个值可以在元组中给定,格式化的元组必须作为嵌套的元组提供

将来可能废弃

Python开发者可能在将来废弃%表达式而使用format方法

在可以预见的未来,任何一种都不太可能废弃


通常意义下的类型分类

同样分类的类型共享其操作集合

三个主要类型的分类

  • 数字(整数、浮点数、二进制、分数)

    支持加法和乘法等

  • 序列(字符串、列表、元组)

    支持索引、分片合并等

  • 映射(字典)

    支持通过键的索引等

集合是自成一体的一个分类,集合不会把键映射到值,没有逐位的排序顺序

可变类型能够在原处修改

  • 不可变类型(数字、字符串、元组、不可变集合)

    不可变的分类中的对象不支持原处修改,可以运行表达式来创建新的对象并将其结果分配给变量

  • 可变类型(列表、字典、可变集合)

    可变的类型可以通过操作原处修改,而不需要创建新的对


本章习题

  1. 字符串find方法能用于搜索列表吗

    不行
    因为方法是类型特定的,只能用于单一数据类型上

    X+Y这样的表达式和len(X)这样的内置函数是通用的,可以用于多种类型上

    在这个例子中,in关系表达式和字符串查找具有类似的效果,但它可以用来查找字符串和列表

    在Python 3.0中,有一些对方法分组的尝试(例如,不可变序列类型list和bytearray具有类似的方法集合),但方法仍然比其他的操作集更特定于类型

  2. 字符串切片表达式能用于列表吗

    可以

    和方法不同的是,表达式是通用的,可用于多种类型

    就这一点来说,切片表达式其实是序列运算,可用于任何类型的序列对象上,包括字符串、列表以及元

    唯一的差别就是当你对列表进行切片时,你得到的是新列表

  3. 如何将字符转成其ASCII码,如何反向转换,从整数转换成字符

    内置的ord(S)函数可将单个字符的字符串转换成整数字符编码

    chr(I)则是从整数代码转换回字符串

  4. 在Python中,怎么修改字符串

    字符串无法被修改,字符串是不可变的

    尽管这样,可以通过合并、切片运算、执行格式化表达式、方法调用(例如,replace)创建新的字符串,再将结果赋值给最初的变量名,从而达到相似的效果

  5. 已知字符串S的值为”s ,pa,m”,提出两种从中间抽取两个字符的方式

    使用S[2:4]对字符串进行切片

    使用S.split(',')[1]以逗号分隔字符串,再进行索引运算

  6. 字符串”a\nb\x1f\o00d”之中有多少字符

    6个

    字符串a\nb\x1f\000d包含一些字节a、新行\nb、二进制值31(十六进制转义\x1f) 、二进制值0 (八进制转义\000)以及d

    把字符串传给内置的1en函数可以验证它,然后印出每个字符的ord结果,从而查看实际的字节值

  7. 你为什么要使用string模块,而不使用字符串方法调用

    如今不应该使用string模块,而应该使用字符串对象方法调用

    string模块已经弃用,Python 3.0完全删除其调用

    使用string模块的唯一原因就是可以使用其他工具,例如,预定义的常数

    现在,在非常陈旧的Python代码中,它才会出现


第八章 列表和字典

本章探讨了列表和字典类型

  • 列表类型支持任意对象和以位置排序的集合体,可以任意嵌套,按需要增长和缩短
  • 字典类型是以键来存储元素,不会保持元素之间的由左至右的顺序

列表和字典都是可变的,列表通过append调用进行增长,字典通过赋值给新键的方法实现


列表

列表的主要特性

  • 任意对象的有序集合

    列表是收集其他对象的地方

    列表保持了每一项从左到右的位置顺序

  • 通过偏移读取

    通过列表对象的偏移对其进行索引

    可以执行分片和合并之类的任务

  • 可变长度、异构以及任意嵌套

    • 长度可变

      列表可以在原处增长或缩短

    • 异构

      列表可以包含任何类型的对象

    • 任意嵌套

      列表可以支持任意深度的嵌套

  • 属于可变序列的分类

    列表支持在原处的修改

    列表在应用合并和分片操作时返回新的列表

  • 对象引用数组

    列表是支持位置读取的对象引用数组

    列表包含了零个或多个其他对象的引用

常用列表常量和操作

操作 解释
L = [] 一个空的列表
L = [0, 1, 2, 3] 四项,索引为0到3
L = [‘abc’, [‘def’, ‘ghi’]] 嵌套的子列表
L = list(‘spam’) 可迭代项目的列表
L = list(range(-4, 4)) 连续整数的列表
L[i] 索引
L[i][j] 索引的索引
L[i:j] 分片
len(L) 求长度
L1 + L2 合并
L * 3 重复
for x in L: print(x) 迭代
3 in L 成员关系
L.append(4) 增长
L.extend([5, 6, 7]) 添加迭代
L.insert(I,X) 插入
L.index(1) 搜索
L.count(X) 统计
L.sort() 排序
L.reverse() 反转
del L[k] 移除元素
del L[i:j] 移除片段
L.pop() 移除最后一项
L.remove(2) 移除元素
L[i:j] = [] 移除片段
L[i] = 1 索引赋值
L[i:j = [4, 5, 6] 分片赋值
L = [x**2 for x in range(5)] 列表解析
list(map(ord, ‘spam’))

作为常量表达式编写时返回列表对象


实际应用中的列表

基本列表操作

列表是序列,支持所有的操作

1
2
3
4
5
6
7
8
9
10
>>> len([1, 2, 3])				# Length
3
>>> [1, 2, 3] + [4, 5, 6] # Concatenation
[1, 2, 3, 4, 5, 6]
>>> ['Ni!'] * 4 # Repetition
['Ni!', 'Ni!', 'Ni!', 'Ni!']
>>> str([1, 2]) + "34"
'[1, 2]34'
>>> [1, 2] + list("34")
[1, 2, '3', '4']

+的操作是合并

*的操作是重复

结果是一个新的列表

+两边必须是相同类型的对象

列表迭代和解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> 3 in [1, 2, 3]						# Membership
True
>>> for x in [1, 2, 3]:
... print(x, end=' ') # Iteration
...
1 2 3
>>> res = [c * 4 for c in 'SPAM'] # List comprehensions
>>> res
['SSSS', 'PPPP', 'AAAA', 'MMMM']
>>> res = []
>>> for c in 'SPAM': # List comprehension equivalent
... res.append(c * 4)
...
>>> res
['SSSS', 'PPPP', 'AAAA', 'MMMM']
>>> list(map(abs,[-1, -2, 0, 1, 2])) # map function across sequence
[1, 2, 0, 1, 2]

序列能够对迭代工具做出响应

for循环从左到右遍历任何虚列中的项

列表解析是通过对序列中的每一项应用一个表达式来构建一个新的列表的方式

map函数对序列中的各项应用一个函数并把结果收集到一个新的列表中

索引、分片和矩阵

1
2
3
4
5
6
7
>>> L = ['spam', 'Spam', 'SPAM!']
>>> L[2] # Offsets start at zero
'SPAM!'
>>> L[-2] # Negative:count from the right
'Spam'
>>> L[1:] # Slicing fetches sections
['Spam', 'SPAM!']

对列表索引返回指定偏移处对象

对列表分片返回新的列表

1
2
3
4
5
6
7
8
9
10
11
12
>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> matrix[1]
[4, 5, 6]
>>> matrix[1][1]
5
>>> matrix[2][0]
7
>>> matrix = [[1, 2, 3],
... [4, 5, 6],
... [7, 8, 9]]
>>> matrix[1][1]
5

对于嵌套列表,使用一次索引会得到嵌套的一个子列表,多次索引才会深入到深入到数据结构中

原处修改列表

列表是可变的,支持原处改变列表对象的操作

需要将原处修改一个对象与生成一个新对象区分开,否则可能同时影响一个以上指向它的引用

索引与分片的赋值

1
2
3
4
5
6
7
>>> L = ['spam', 'Spam', 'SPAM!']
>>> L[1] = 'eggs' # Index assignment
>>> L
['spam', 'eggs', 'SPAM!']
>>> L[0:2] = ['eat', 'more'] # Slice assignment:delete+insert
>>> L # Replaces items 0,1
['eat', 'more', 'SPAM!']

可以通过特定性(偏移)或整个片段(分片)对列表进行赋值

当赋值的值与分片重叠时,需要分析是否可行

分片赋值操作

  • 删除

    删除等号左边指定的分片

  • 插入

    将包含在等号左边对象中的片段插入旧分片被删除的位置

列表方法调用

方法是附属于特定对象的函数.提供特定类型的工具

列表对象支持特定类型方法调用,其中很多调用可以在原处修改主体列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
>>> L = []
>>> L.append(1) # Append method call:add item at end
>>> L.append(2) # Push onto stack
>>> L
[1, 2]
>>> L.pop() # Pop off stack
2
>>> L
[1]
>>> L = [1, 2]
>>> L.extend([3, 4, 5]) # Add many items at end
>>> L
[1, 2, 3, 4, 5]
>>> L.pop() # Delete and return last item
5
>>> L
[1, 2, 3, 4]
>>> L = ['spam', 'eggs', 'ham']
>>> L.index('eggs') # Index of an object
1
>>> L.insert(1, 'toast') # Insert at position
>>> L
['spam', 'toast', 'eggs', 'ham']
>>> L.remove('eggs') # Delete by value
>>> L
['spam', 'toast', 'ham']
>>> L.pop(1) # Delete by position
'toast'
>>> L
['spam', 'ham']

append方法将一个单项(对象引用)加至列表末端

pop方法根据偏移删除对应的项并返回它的值,该偏移默认值为最后一个

qppend方法与pop方法联用可以实现后进先出堆栈结构

extend能够在末端插入多个元素

index方法查找元素的偏移

insert方法在偏移处插入元素

remove方法通过值删除元素

append方法、extend方法、insert方法remove方法的返回值为None

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
>>> L = ['eat', 'more', 'SPAM!', 'please']
>>> L.sort() # Sort list items('S' < 'e')
>>> L
['SPAM!', 'eat', 'more', 'please']
>>> L = ['abc', 'ABD', 'aBe']
>>> L.sort() # Sort with mixed case
>>> L
['ABD', 'aBe', 'abc']
>>> L = ['abc', 'ABD', 'aBe']
>>> L.sort(key=str.lower) # Normalize to lowercase
>>> L
['abc', 'ABD', 'aBe']
>>> L = ['abc', 'ABD', 'aBe']
>>> L.sort(key=str.lower, reverse=True) # Change sort order
>>> L
['aBe', 'ABD', 'abc']
>>> L = ['abc', 'ABD', 'aBe']
>>> sorted(L, key=str.lower, reverse=True) # Sorting built-in
['aBe', 'ABD', 'abc']
>>> L = ['abc', 'ABD', 'aBe']
>>> sorted([x.lower() for x in L], reverse=True) # Pretransform items:differs!
['abe', 'abd', 'abc']
>>> L = [1, 2, 3, 4]
>>> L.reverse() # In-place reversal method
>>> L
[4, 3, 2, 1]
>>> list(reversed(L)) # Reversal built-in with a result
[1, 2, 3, 4]

sort方法在原始对列表进行排序,使用Python标准的比较检验作为默认值,以递增顺序排序

sort可以通过传入关键字参数来修改排序行为,key参数给出了排序使用的值,reverse参数允许逆序排序

sort方法只对列表中相同类型对象排序,不同类型发生异常

sorted内置函数可以排序任何可迭代对象,返回一个新的列表

reverse方法在原处反转列表

reversed内置函数返回一个迭代器,需要装在list调用中

其他常见列表操作

1
2
3
4
5
6
7
>>> L = ['SPAM!', 'eat', 'more', 'please']
>>> del L[0] # Delete an entire section
>>> L
['eat', 'more', 'please']
>>> del l[1:] # Delete an entire section
>>> L # Same as L[1:]=[]
['eat']

del语句在原处删除某项或某片段

1
2
3
4
5
6
7
>>> L = ['Already', 'got', 'one']
>>> L[1:] = []
>>> L
['Already']
>>> L[0] = []
>>> L
[[]]

可以通过将空列表赋值给分片来删除列表片段

空列表赋值给一个索引只会在指定的位置存储空列表的引用,而不是删除


字典

字典的主要特性

  • 通过键而不是偏移量来读取

    字典又叫关联数组(associative array)或者散列表(hash)

    字典通过将一系列联系起来

    可以通过使用索引操作从字典中获得

  • 任意对象的无序集合

    字典中的项没有特定的顺序

    Python将各项从左到右随机排序,以便快速查找

  • 可变长、异构、任意嵌套

    • 可变长

      字典可以在原处增长或缩短

    • 异构

      字典可以包含任何类型的对象

    • 任意嵌套

      字典可以支持任意深度的嵌套

  • 属于可变映射类型

    通过给索引赋值,字典可以在原处修改

    不支持用于字符串和列表中的序列操作

    字典是唯一内置的映射类型

  • 对象引用表(散列表)

    字典是支持键读取的无序对象引用表

    字典是作为散列表(支持快速检索的数据结构)

    字典存储的是对象引用

常见字典常量和操作

操作 解释
D = {} 空字典
D = {‘spam’: 2, ‘eggs’: 3} 两项目字典
D = {‘food’: {‘ham’: 1, ‘egg’: 2}} 嵌套
D = dict.fromkeys([‘a’, ‘b’]) 其他构造技术
D = dict(zip(keyslist, valslist)) 关键字、对应的对、键列表
D = dict(name=’Bob’, age=42)
D[‘eggs’] 以键进行索引运算
D[‘food’][‘ham’]
‘eggs’ in D 成员关系:键存在测试
D.keys() 方法:键
D.values()
D.items() 键+值
D.copy() 副本
D.get(key, default) 默认
D.update(D2) 合并
D.pop(key) 删除
len(D) 长度(储存的元素的数目)
D[key] = 42 新增/修改键,删除键
del D [key] 根据键删除条目
list(D.keys()) 字典视图
D1.keys() & D2.keys()
Dictionary views
D = {x: x*2 for x in range(10)} 字典解析

实际应用中的字典

字典通过键进行索引,被嵌套的字典项是由一系列索引表示的

字典的基本操作

1
2
3
4
5
>>> D = {'spam':2, 'ham':1, 'eggs':3}	# Make a dictionary
>>> D['spam'] # Fetch a value by key
2
>>> D # Order is scrambled
{'spam': 2, 'ham': 1, 'eggs': 3}

通常创建字典并通过键来存储、访问其中的某项

字典内键由左至右的次序几乎总是和原先输入的顺序不同

原处修改字典

字典可以在原处修改、拓展或缩短而不需生成新字典

1
2
3
4
5
6
7
8
9
10
11
>>> D
{'spam': 2, 'ham': 1, 'eggs': 3}
>>> D['ham'] = ['grill', 'bake', 'fry'] # Change entry
>>> D
{'spam': 2, 'ham': ['grill', 'bake', 'fry'], 'eggs': 3}
>>> del D['eggs'] # Delete entry
>>> D
{'spam': 2, 'ham': ['grill', 'bake', 'fry']}
>>> D['brunch'] = 'Bacon' # Add new entry
>>> D
{'spam': 2, 'ham': ['grill', 'bake', 'fry'], 'brunch': 'Bacon'}

向字典中已存在的索引赋值可以改变与索引相关联的值

对字典中没有被赋值的键赋值会生成一个新的元素

Python中所有集合数据类型都可以彼此任意嵌套

del语句可以删除作为索引的键相关联的元素

其他字典方法

1
2
3
4
5
6
7
8
9
10
11
>>> D = {'spam': 2, 'ham': 1, 'eggs': 3}
>>> len(D) # Number of entries in dictionary
3
>>> 'ham' in D # Key membership test alternative
True
>>> list(D.keys()) # Create a new list of my keys
['spam', 'ham', 'eggs']
>>> list(D.values())
[2, 1, 3]
>>> list(D.items())
[('spam', 2), ('ham', 1), ('eggs', 3)]

内置函数len能够返回存储在字典里的元素的数目

in成员关系操作符提供了键存在与否的测试方法

keys方法返回字典的键列表

values方法返回字典的值列表

items方法返回(key,values)元组

keys方法、values方法和items返回包含所有键的迭代器,需要装在list调用中

1
2
3
4
5
6
7
>>> D = {'spam': 2, 'ham': 1, 'eggs': 3}
>>> D.get('spam') # A key that is there
2
>>> print(D.get('toast')) # A key that is missing
None
>>> D.get('toast',88)
88

读取不存在的键会返回错误

get方法返回键的值,键不存在返回默认值(None或自定义的默认值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> D = {'spam': 2, 'ham': 1, 'eggs': 3}
>>> D2 = {'toast': 4, 'muffin': 5}
>>> D.update(D2)
>>> D
{'spam': 2, 'ham': 1, 'eggs': 3, 'toast': 4, 'muffin': 5}

# pop a dictionary by key
>>> D.pop('muffin')
5
>>> D.pop('toast') # Delete and return from a key
4
>>> D
{'spam': 2, 'ham': 1, 'eggs': 3}

# pop a list by position
>>> L = ['aa', 'bb', 'cc', 'dd']
>>> L.pop() # Delete and return from the end
'dd'
>>> L
['aa', 'bb', 'cc']
>>> L.pop(1) # Delete from a specific position
'bb'
>>> L
['aa', 'cc']

update方法把一个字典的键和值合并到另一个字典中,盲目地覆盖相同的值

pop方法从字典中删除一个键并返回它的值

语言表

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> table = {'Python': 'Guido van Rossum',
... 'Prel': 'Larry Wall',
... 'Tcl': 'John Ousterhout'}
>>> language = 'Python'
>>> creator = table[language]
>>> creator
'Guido van Rossum'
>>> for lang in table: # Same as:for lang in table.keys()
... print(lang, '\t', table[lang])
...
Python Guido van Rossum
Prel Larry Wall
Tcl John Ousterhout

字典不是序列,无法直接通过for语句迭代,可以通过keys方法得到排序后的键的列表,再用for循环得到从键到值的引用

for key in D:key in D.keys()效果相同

字典用法注意事项

  • 序列运算无效

  • 对新索引赋值会添加项

  • 键不一定总是字符串

    所有的不可变对象都可作为键

使用字典模拟灵活的列表

1
2
3
4
5
6
7
8
9
10
11
>>> L = []
>>> L[99] = 'spam'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
>>> D = {}
>>> D[99] = 'spam'
>>> D[99]
'spam'
>>> D
{99: 'spam'}

列表在末尾外的偏移赋值是非法的,可以使用整数键的字典模仿列表对偏移赋值

字典用于稀疏数据结构

1
2
3
4
5
6
7
8
9
10
11
>>> Matrix = {}
>>> Matrix[(2,3,4)] = 88
>>> Matrix[(7,8,9)] = 99
>>> Matrix = {}
>>> Matrix[(2, 3, 4)] = 88
>>> Matrix[(7, 8, 9)] = 99
>>> X = 2; Y = 3; Z = 4 # ;separates statements
>>> Matrix[(X, Y, Z)]
88
>>> Matrix
{(2, 3, 4): 88, (7, 8, 9): 99}

字典键常用于实现稀疏数据结构

避免missing-key错误

读取不存在的键会返回异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> Matrix = {(2, 3, 4): 88, (7, 8, 9): 99}
>>> Matrix[(2, 3, 6)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: (2, 3, 6)
>>> if(2, 3, 6)in Matrix: # Check for key before fetch
... print(Matrix[(2, 3, 6)])
... else:
... print(0)
...
0
>>> try:
... print(Matrix[(2, 3, 6)]) # Try to index
... except KeyError: # Catch and recover
... print(0)
...
0
>>> Matrix.get((2, 3, 4), 0) # Exists:fetch and return
88
>>> Matrix.get((2, 3, 6), 0) # Doesn't excist:use default arg
0

填入默认值而不返回错误的方式

  • if语句中预先对键进行测试
  • 使用try语句捕获并修复异常
  • 使用get方法为不存在的键提供默认值

使用字典作为”记录”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
>>> rec = {}
>>> rec['name'] = 'mel'
>>> rec['age'] = 45
>>> rec['job'] = 'trainer/writer'
>>> print(rec['name'])
mel
>>> mel = {'name': 'Mark',
... 'jobs': ['trainer', 'writer'],
... 'web': 'www.rmi.net/~lutz',
... 'home': {'state': 'CO', 'zip': 80513}}
>>> mel['name']
'Mark'
>>> mel['jobs']
['trainer', 'writer']
>>> mel['jobs'][1]
'writer'
>>> mel['home']['zip']
80513

字典可以表示多种结构化信息的类型

为什么要在意字典接口

有些Python的拓展程序提供了外表类似并且实际工作都和字典一样的接口

  • PythonDBM接口通过键来获取文件
  • shelve是通过键来访问的Python持久对象的数据库
  • Python的CGI脚本支持的一个接口也和字典类似

创建字典的其他方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> {'name': 'mel', 'age': 45}					# Traditional literal expression
{'name': 'mel', 'age': 45}
>>> D = {} # Assign by keys dynamically
>>> D['name'] = 'mel'
>>> D['age'] = 45
>>> dict(name='mel', age=45)
{'name': 'mel', 'age': 45} # dict keyword argument from
>>> dict([('name', 'mel'), ('age', 45)]) # dict key/value tuples form
{'name': 'mel', 'age': 45}
>>> list(zip(['a', 'b', 'c'], [1, 2, 3])) # Zip together keys and values
[('a', 1), ('b', 2), ('c', 3)]
>>> D = dict(zip(['a', 'b', 'c'], [1, 2, 3])) # Make a dict from zip result
>>> D
{'a': 1, 'b': 2, 'c': 3}

在不同条件下使用不同的创建方法

  • 如果可以事先拼出整个字典,第一种比较方便

  • 如果需要一次动态地建立字典的一个字段,第二种比较合适

  • 第三种关键字形式所需的代码比常量少,但是键都是字符串

  • 如果需要在程序运行时把键和值逐步建成序列,第四种形式比较有用

    zip函数是在一个单个调用中从建和值的列表构建一个字典的方式之一

    字典解析表达式

  • 如果所有键的值都相同,可以使用dict.fromkeys([key1,...], value)

Python 3.0中的字典变化

Python 3.0中的字典

  • 支持新的字典解析表达式
  • D.keyD.valueD.items方法,返回可迭代的视图而不是列表
  • 需要新的编码方式通过排序键来遍历
  • 不再支持相对大小比较,使用手动比较
  • 不再有D.has_key方法,使用in成员关系测试

字典解析

字典解析隐式地运行一个循环,根据每次迭代收集表达式的键/值结果,并使用它们填充一个新的字典

1
2
3
4
5
6
7
8
9
10
11
12
>>> D = {k: v for (k,v) in zip(['a', 'b', 'c'], [1, 2, 3])}
>>> D # Use a dict comprehension
{'a': 1, 'b': 2, 'c': 3}
>>> D = {x: x ** 2 for x in [1, 2, 3, 4]} # Or:range(1, 5)
>>> D
{1: 1, 2: 4, 3: 9, 4: 16}
>>> D = {c: c * 4 for c in 'SPAM'} # Loop over any iterable
>>> D
{'S': 'SSSS', 'P': 'PPPP', 'A': 'AAAA', 'M': 'MMMM'}
>>> D = {c.lower(): c + '!' for c in ['SPAM', 'EGGS', 'HAM']}
>>> D
{'spam': 'SPAM!', 'eggs': 'EGGS!', 'ham': 'HAM!'}

字典解析表达式可以迭代键值对获得新的字典

可以迭代单独的一串值映射到字典

1
2
3
4
5
6
7
8
9
10
11
12
>>> D = dict.fromkeys(['a', 'b', 'c'], 0)		# Omotoa;oze doct from keys
>>> D
{'a': 0, 'b': 0, 'c': 0}
>>> D = {k:0 for k in ['a', 'b', 'c']} # Same,but with a comprehension
>>> D
{'a': 0, 'b': 0, 'c': 0}
>>> D = dict.fromkeys('spam') # Other interators,default value
>>> D
{'s': None, 'p': None, 'a': None, 'm': None}
>>> D = {k:None for k in 'spam'}
>>> D
{'s': None, 'p': None, 'a': None, 'm': None}

字典解析可以从键列表初始化字典

字典视图

keysvaluesitems返回视图对象

视图对象是可迭代的.每次对象产生一个结果项而不是内存中立即产生结果列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
>>> D = dict(a=1, b=2, c=3)
>>> D
{'a': 1, 'b': 2, 'c': 3}
>>> K = D.keys() # Makes a view object in 3.0,not a list
>>> K
dict_keys(['a', 'b', 'c'])
>>> list(K) # Force a real list in 3.0 if needed
['a', 'b', 'c']
>>> V = D.values() # Ditto for values and items views
>>> V
dict_values([1, 2, 3])
>>> list(V)
[1, 2, 3]
>>> list(D.items())
[('a', 1), ('b', 2), ('c', 3)]
>>> K[0] # List operations fail unless converted
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'dict_keys' object does not support indexing
>>> for k in D.keys(): print(k) # Iterators used automatically in loops
...
a
b
c
>>> for k in D: print(k)
...
a
b
c

打印显示对应方法的类型的值,需要内置函数list得到列表结果

循环结构会自动迫使可迭代的对象在每次迭代上产生一个结果

Python中字典拥有自己的迭代器,返回连续键,没有必要直接调用keys

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> D = {'a':1, 'b':2, 'c':3}
>>> D
{'a': 1, 'b': 2, 'c': 3}
>>> K = D.keys()
>>> V = D.values()
>>> list(K) # Views maintain same order as dictionary
['a', 'b', 'c']
>>> list(V)
[1, 2, 3]
>>> del D['b'] # Change the dictionary in-place
>>> D
{'a': 1, 'c': 3}
>>> list(K) # Reflected in any current view objects
['a', 'c']
>>> list(V)
[1, 3]

字典视图创建后可以动态地反应在试图对象创建之后对字典做出的修改

字典视图和集合

keys方法和可散列的items方法返回的视图对象类似于集合,支持交集和并集等常见的集合操作

values方法返回的视图不同,因为value不唯一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
>>> D = {'a':1, 'b':2, 'c':3}
>>> D
{'a': 1, 'b': 2, 'c': 3}
>>> K = D.keys()
>>> V = D.values()
>>> K | {'x': 4} # Keys(and some items) views are set-lisk
{'a', 'c', 'x'}
>>> V & {'x': 4}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'dict_values' and 'dict'
>>> V & {'x': 4}.values()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'dict_values' and 'dict_values'
>>> D = {'a':1, 'b':2, 'c':3}
>>> D.keys() & D.keys()
{'a', 'c', 'b'}
>>> D.keys() & {'b'}
{'b'}
>>> D.keys() & {'b':1}
{'b'}
>>> D.keys() | {'b', 'c', 'd'}
{'a', 'c', 'd', 'b'}
>>> D = {'a': 1}
>>> list(D.items()) # Items set-like if hashable
[('a', 1)]
>>> D.items() | D.keys() # Union view and view
{('a', 1), 'a'}
>>> D.items() | D # dict trated same as its keys
{('a', 1), 'a'}
>>> D.items() | {('c', 3), ('d', 4)} # Set of key/value pairs
{('a', 1), ('d', 4), ('c', 3)}
>>> dict(D.items() | {('c', 3), ('d', 4)}) # dict accepts iterable sets too
{'a': 1, 'd': 4, 'c': 3}

在集合操作中,视图可能与其他的视图、集合和字典混合

排序字典键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
>>> D = {'a':1, 'b':2, 'c':3}
>>> D
{'a': 1, 'b': 2, 'c': 3}
>>> Ks = D.keys() # Sorting a view object doesn't work!
>>> Ks.sort()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict_keys' object has no attribute 'sort'
>>> Ks = list(Ks) # Force it to be a list and then sort
>>> Ks.sort()
>>> for k in Ks: print(k,D[k])
...
a 1
b 2
c 3
>>> D
{'a': 1, 'b': 2, 'c': 3}
>>> Ks = D.keys() # Or you can use sorted() on the keys
>>> for k in sorted(Ks): print(k,D[k]) # sorted() accepts any iterable
... # sorted() returns its result
a 1
b 2
c 3
>>> D
{'a': 1, 'b': 2, 'c': 3} # BEtter yet,sort the dict directly
>>> for k in sorted(D): print(k, D[k]) # dict iterators return keys
...
a 1
b 2
c 3

使用sorted排序字典键

字典大小比较不再有效

Python 3.0字典不可以直接比较大小

可以手动模拟sorted(D1.items()) < sorted(D2.items())

has_key方法已死:in永生

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> D {'a': 1, 'b': 2, 'c': 3}
>>> D.has_key('c') # 2.X only:True/False
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'has_key'
>>> 'c' in D
True
>>> 'x' in D
False
>>> if 'c' in D: print('present', D['c']) # Preferred in 3.0
...
present 3
>>> print(D.get('c'))
3
>>> print(D.get('x'))
None
>>> if D.get('c') != None: print('present', D['c']) # Another option
...
present 3

本章习题

  1. 举出两种方式来创建内含五个整数零的列表

    [0, 0, 0, 0, 0]这种常量表达式以及[0] * 5这种重复表达式,都会创建五个零的列表

    在实际应用中,可能会通过循环创建这种列表:一开始是空列表,在每次迭代中附加0:L.append(0)

    列表解析([0 for i in range(5)])在这里也可以用

  2. 举出两种方式来创建一个字典,有两个键’a’和’b’,而每个键相关联的值都是0

    {'a': 0,'b': 0}这种常量表达式,或者像D = {},D['a'] = 0,D['b'] = 0这种一系列的赋值运算都会创建所需要的字典
    dict(a=0,b=0),或者dict([('a', 0), ('b',0)])键/值序列形式

    因为所有键的值都相同,也可以使用特殊形式dict.fromkeys(['a', 'b'], 0)

    可以使用一个字典解析:{k:0 for k in 'ab'}

  3. 举出四种在原处修改列表对象的运算

    appendextend方法可在原处增长列表

    sortreverse方法可以对列表进行排序或者翻转

    insert方法可以在一个偏移值处插入一个元素

    removepop方法会按照值和位置从列表中删除元素
    del语句会删除一个元素或分片,而索引以及分片赋值语句则会取代一个元素或整个片段

  4. 举出四种在原处修改字典对象的运算

    字典的修改主要是赋值新的键或已存在的键,从而建立或修改键在表中的项目

    del语句会删除一个键的元素

    D.update(D2)方法会把一个字典合并到另一个字典的适当的地方

    D. pop(key)则会移除一个键并返回它的值


第九章 元组、文件及其他

本章学习两种核心的对象类型

元组支持所有一般的序列操作,但是因为不可变性所以没有方法

文件是由内置open函数返回的并且提供读写数据的方法

探讨Python对象如何转换字符串

了解picklestruct模块

复习一些所有类型共有的特性

讨论对象类型领域内常见的陷阱


元组

元组由简单的对象组构成,不能在原处修改,写成()

元组的特性

  • 任意对象的有序集合

    元组是一个位置有序的对象的集合,可以嵌入任何类别的对象

  • 通过偏移存取

    元组通过偏移来访问,支持所有基于偏移的操作

  • 属于不可变序列类型

    元组是不可变的,不支持应用在列表中任何原处修改的操作

  • 固定长度、异构、任意嵌套

    • 固定长度

      元组是不可变的,在不生成异构拷贝的情况下不能增长或缩短

    • 异构

      元组可以包含任何类型的对象

    • 任意嵌套

      元组可以支持任意深度的嵌套

  • 对象引用的数组

    元组存储指向其他对象的引用

    元鼓掌进行索引的速度相对较快

常见元组常量和运算

运算 解释
() 空元组
T = (0,) 单个元素的元组
T = (0, ‘Ni’, 1.2, 3) 四个元素的元组
T = 0, ‘Ni’, 1.2, 3 四个元素的元组
T = (‘abd’, (‘def’, ‘ghi’)) 嵌套元组
T = tuple(‘spam’) 一个可迭代对象的项的元组
T[i] 索引
T[i][j] 索引的索引
T[i:j] 分片
len(T) 长度
T1 + T2 合并
T * 3 重复
for x in T: print(x) 迭代
‘spam’ in T 成员关系
[x ** 2 for x in T] 解析表达式
T.index(‘Ni’) 搜索
T.count(‘Ni’) 计数

实际应用中的元组

1
2
3
4
5
6
7
>>> (1, 2) + (3, 3)			# Concatenation
(1, 2, 3, 3)
>>> (1, 2) * 4 # Repetition
(1, 2, 1, 2, 1, 2, 1, 2)
>>> T = (1, 2, 3, 4) # Indexing,slicing
>>> T[0], T[1:3]
(1, (2, 3))

元组支持字符串和列表的一般序列操作

元组的特殊语法:逗号和圆逗号

1
2
3
4
5
6
>>> x = (40)	# An integer!
>>> x
40
>>> y = (40,) # A tuple containing an integer
>>> y
(40,)

()只有一个元素,需要在这一个元素后加,

在不会引起语法冲突的情况下,Python允许忽略元组的圆括号

当元组作为常量传给函数调用时必须使用圆括号

转换、方法以及不可变性

+*以及分片操作应用于元组时将返回新元组

转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> T = ('cc', 'aa', 'dd', 'bb')
>>> tmp = list(T) # Make a list from a tuple's items
>>> tmp.sort() # Sort the list
>>> tmp
['aa', 'bb', 'cc', 'dd']
>>> T = tuple(T) # Make a tuple from the list's items
>>> T
('cc', 'aa', 'dd', 'bb')
>>> sorted(T) # Or use the sorted built-in
['aa', 'bb', 'cc', 'dd']
>>> T = (1, 2, 3, 4, 5)
>>> L = [x + 20 for x in T]
>>> L
[21, 22, 23, 24, 25]

元组与列表转换

  • listtuple内置函数用来返回列表和元组对象进行转换
  • 使用列表解析遍历元组返回一个列表对象

对元组排序

  • 先转换为列表,调用sort方法进行排序
  • 使用sorted内置方法
方法
1
2
3
4
5
6
7
>>> T = (1, 2, 3, 2, 4, 2)	# Tuple methods in 2.6 and 3.0
>>> T.index(2) # Offset of first appearance of 2
1
>>> T.index(2, 2) # Offset of appearance after offset 2
3
>>> T.count(2) # How many 2s are there?
3

index方法查找元素的偏移

count方法统计元素的数量

不可变性
1
2
3
4
5
6
7
8
>>> T = (1, [2, 3], 4)
>>> T[1] = 'spam' # This fails:can't change tuple itself
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> T[1][0] = 'spam' # This works:can change mutables inside
>>> T
(1, ['spam', 3], 4)

元组的不可变性只适用于元组本身顶层而非其内容

为什么有了列表还要元组

元组的不可变性提供了完整性,可以确保元组在程序中不会被另一个引用修改

元组可以用在列表无法使用的地方,例如字典的键

一些内置操作要求使用元组而不是列表


文件

内置函数open会创建一个Python文件对象,可以作为计算机上的一个文件链接

调用open后,可以通过调用返回文件对象的方法来读写相关外部文件

常见文件运算

操作 解释
output = open(r’C:\spam’, ‘w’) 创建输出文件(‘w’指输出)
input = open(‘data’, ‘r’) 创建输入文件(‘r’是指读写)
input = open(‘data’) 创建输入文件(‘r’是默认值)
aString = input.read() 把整个文件读进单一字符串
aString = input.read(N) 读取之后的N个字节到一个字符串
aString = input.readline() 读取下一行(包括行末标志符)到一个字符串
aList = input.readlines() 读取整个文件到字符串列表
output.write(aString) 写入字节字符串到文件
output.writelines(aList) 把列表内所有字符串写入文件
output.close() 手动关闭(当文件收集完成时会自动关闭文件)
output.flush() 把输出缓冲区刷到硬盘上,但不关闭文件
anyFile.seek(N) 修改文件位置到偏移量N处以便进行下一个操作
for line in open(‘data’):use line 文件迭代器一行一行地读取
open(‘f.txt’, endcoding=’latin-1’) Python 3.0 Unicode文本文件(str字符串)
open(‘f.bin’, ‘rb’) Python 3.0二进制byte文件(bytes字符串)

打开文件

调用内置open函数,传入字符串参数外部名处理模式(默认值为r)

处理模式

  • r

    输入模式打开文件

  • w

    输出模式创建或打开文件

  • b

    进行二进制数据处理(行末转化和Python 3.0 Unicode编码被关闭)

  • 后接+

    同时为输入和输出打开文件

    对文件的修改和查找操作配合

参数

参数均为字符串对象

  • 第一个参数为外部文件名,可能包含平台特点的以及绝对火相对目录路径前缀,默认为当前目录
  • 第二个参数指定读取文件时的处理模式
  • 第三参数为可选参数,控制输出缓存,'0'以为输出无缓存,方法调用时立即传给外部文件

使用文件

Python程序中的文本文件采用字符串形式,读取文件返回字符串,写文件传入字符串

  • 文件迭代器是最好的读取行工具

  • 内容是字符串,不是对象

    从文件读取的数据是一个字符串

    把数据写入文件时需要传递一个已经格式化的字符串

  • close是通常选项

    调用文件close方法会终止对外部文件的连接

    当文件对象不再被引用而被回收时,Python会在需要时自动关闭文件

    习惯上手动调用close方法

  • 文件是缓冲的并且是可查找的

    由于文件是缓冲的,写入的文本可能不会立即自动从内存转换到硬盘中

    调用closeflush方法会释放操作系统资源并清空缓冲区,可以迫使缓存的数据写入硬盘

    可以用open参数避免缓存,但是可能影响性能

实际应用中的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
>>> myfile = open('myfile.txt', 'w')		# Open for text output:create/empty
>>> myfile.write('hello text file\n') # Write a line of text:string
16
>>> myfile.write('goodbye text file\n')
18
>>> myfile.close() # Flush output buffers to disk
>>> myfile = open('myfile.txt') # Open for text input:'r' is default
>>> myfile.readline() # Read the lines back
'hello text file\n'
>>> myfile.readline()
'goodbye text file\n'
>>> myfile.readline() # Empty string:end of file
''
>>> myfile.close()
>>> open('myfile.txt').read() # Read all at once into string
'hello text file\ngoodbye text file\n'
>>> print(open('myfile.txt').read() # User-friendly display
... )
hello text file
goodbye text file

>>> for line in open('myfile.txt'): # Use file iterators,not reads
... print(line,end='')
...
hello text file
goodbye text file

write方法返回写入的字符数

write方法不自动添加终止符

read方法将整个文件读入到字符串中

文件迭代器一行一行地扫描一个文本文件

Python 3.0中的文本和二进制文件

  • 文本文件把内容表示为常规的str字符串,自动执行Unicode编码和解码,并且默认执行末行转换
  • 二进制文件把内容表示为一个特殊的bytes字符串类型,并且允许程序不修改地访问文件内容

处理ASCII文件可以用基本文本文件接口和常规的字符串做到

处理国际化应用程序或者面向字节的数据,必须使用bytes字符串处理二进制文件,用str字符串处理文本文件,以文本模式打开一个二进制数据文件可能会导致解码Unicode文本失败

1
2
3
4
5
6
7
8
9
>>> data = open('data.bin', 'rb').read()	# Open binary file:rb=read binary
>>> data # bytes string holds binary data
b'\x00\x00\x00\x07spam\x00\x08'
>>> data[4:8] # Act like strings
b'spam'
>>> data[4] # But readlly are small 8-bit integers
115
>>> bin(data[4]) # Python 3.0 bin() function
'0b1110011'

读取二进制数据文件时,得到一个bytes对象,外观几乎与常规字符串完全相同

二进制文件不会对数据执行末行转换

在文件中存储并解析Python对象

1
2
3
4
5
6
7
8
9
10
11
12
>>> X, Y, Z = 43, 44, 45						# Native PYthon objects
>>> S = 'Spam' # Must be strings to store in file
>>> D = {'a':1, 'b':2}
>>> L = [1, 2, 3]
>>> F = open('datafile.txt', 'w') # Create output file
>>> F.write(S + '\n') # Terminate lines with \n
5
>>> F.write('%s,%s,%s\n' % (X, Y, Z)) # Convert numbers to strings
9
>>> F.write(str(L) + '$' + str(D) + '\n') # Convert and separate with $
27
>>> F.close()

利用write方法把多种Python对象写入文本必须使用转换工具把对象转换成字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
>>> chars = open('datafile.txt').read()				# Raw string display
>>> chars
"Spam\n43,44,45\n[1, 2, 3]${'a': 1, 'b': 2}\n"
>>> print(chars) # User-friendly display
Spam
43,44,45
[1, 2, 3]${'a': 1, 'b': 2}

>>> F = open('datafile.txt') # Open again
>>> line = F.readline() # Read one line
>>> line
'Spam\n'
>>> line.rstrip() # Remove end-of-line
'Spam'
>>> line = F.readline() # Next line from file
>>> line # It's a string here
'43,44,45\n'
>>> parts = line.split(',') # Split(parse) on commas
>>> parts
['43', '44', '45\n']
>>> int(parts[1]) # Convert from string to int
44
>>> numbers = [int(P) for P in parts] # Convert all in list at once
>>> numbers
[43, 44, 45]
>>> line = F.readline()
>>> line
"[1, 2, 3]${'a': 1, 'b': 2}\n"
>>> parts = line.split('$') # Split(parse) on $
>>> parts
['[1, 2, 3]', "{'a': 1, 'b': 2}\n"]
>>> eval(parts[0]) # Convert to any objecy type
[1, 2, 3]
>>> object = [eval(P) for P in parts] # Do same for all in list
>>> object
[[1, 2, 3], {'a': 1, 'b': 2}]
>>> F.close()

交互模式的回显给出正确的字节内容,print语句会解释内嵌行终止符

rstrip方法去掉多余的行终止符,确定所有行(最后一行可能没有)都有\nline[:-1]分片也可以

split方法断开行得到含有数字的子字符串列表

int函数或列表解析表达式把数字字符串转换为整数对象,转换时忽略空白(\n\t\0)

eval把字符串当做可执行程序代码,可以转换列表和字典

用pickle存储Python的原生对象

1
2
3
4
5
6
7
8
9
10
11
>>> D = {'a':1, 'b':2}
>>> F = open('datafile.pkl', 'wb')
>>> import pickle
>>> pickle.dump(D, F)
>>> F.close() # Pickle any object to file
>>> F = open('datafile.pkl', 'rb')
>>> E = pickle.load(F) # Load any object from file
>>> E
{'a': 1, 'b': 2}
>>> open('datafile.pkl', 'rb').read() # Format is prone to change!
b'\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01K\x01X\x01\x00\x00\x00bq\x02K\x02u.'

pickle模块能够在文件中存储几乎任何Python对象

使用pickle进行重建可以将对象取回

pickle内部将对象转换为字符串格式并依靠这一格式重建对象

文件中打包二进制数据的存储和解析

struct模块能够构造并解析打包的二进制数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> F = open('data.bin', 'wb')					# Open binary output file
>>> import struct
>>> data = struct.pack('>i4sh', 7, b'spam', 8) # Make packed bianry data
>>> data
b'\x00\x00\x00\x07spam\x00\x08'
>>> F.write(data) # Write byte string
10
>>> F.close()
>>> F = open('data.bin', 'rb')
>>> data = F.read() # Get packed binary data
>>> data
b'\x00\x00\x00\x07spam\x00\x08'
>>> values = struct.unpack('>i4sh', data) # Convert to Python objects
>>> values
(7, b'spam', 8)

生成打包的二进制数据文件需要使用wb模式打开文件

pack方法将一个格式化字符串待打包的数据按照高位在前的形式传给struct并返回一个二进制数据字符串

unpack方法将一个格式化字符串和待解析的数据传给struct并返回Python对象

格式化字符串

  • i表示4字节整数
  • s表示字符
  • h表示2字节整数

文件上下文管理器

文件上下文管理器允许把文件处理代码包装到一个逻辑层中,确保在退出后自动关闭文件,而不是依赖垃圾收集的自动关闭

文件上下文管理器的格式为

1
2
3
with open(path ) as myfile:
for line in myfile:
...use line here...

try/finally语句提供类似功能

1
2
3
4
5
6
myfile = open(path)
try:
for line in myfile:
...use line here...
finally:
myfile.close()

其他文件工具

seek函数复位在文件中的当前位置

flush函数强制性将缓存输出写入磁盘

open函数及其返回的文件对象是Python脚本通向外部文件的主要借口

Python工具集中类似的文件工具

  • 标准流

    sys模块中预先打开的文件对象

  • os模块中的描述文件

    处理整数文件,支持文件锁定之类的较低级工具

  • socketspipesFIFO文件

    文件类对象,用于同步进程或者通过网络进行通信

  • 通过键来存取的文件

    通过键直接存储的不变的Python对象

  • Shell命令流

    os.popensubprocess.Popen这样的工具,支持产生shell命令,并读取和写入到标准流


重访类型分类

对象分类

对象类型 分类 是否可变
数字 数值
字符串 序列
列表 序列
字典 映射
元组 序列
文件 拓展 N/A
Sets 集合
frozenset 集合
bytearray 序列

要点

  • 对象根据分类来共享操作:例如,字符串、列表和元组都共享诸如合并、长度和索引等序列操作
  • 只有可变对象(列表、字典和集合)可以原处修改;不能原处修改数字、字符串或元组
  • 当处理文件的到时候,它们的状态可能会修改,但这与Python的核心类型的可变性限制不完全相同
  • 数字类型:整数、浮点数、复数、小数和分数
  • 字符串包括str、bytes和unicode;·bytearray字符串类型是可变的
  • 集合类似于一个无值的字典的键,但是不能映射为值,并且没有顺序;因此,集合不是一个映射类型或者一个序列类型,frozenset是集合的一个不可变的版本
  • 除了类型分类操作,所有类型都有可调用的方法,这些方法通常特定于它们的类型

为什么要在意操作符重载

自己实现的类的对象可以在这些分类中任意选择

还可以选择性地实现一些原处修改操作的的方法调用来生成新的可变或不可变对象

1
2
3
4
5
class MySequence:
def __getitem__(self, index):
# Called onm self[index], others
def __add__(self, other):
# CLled on self + other

对象灵活性

Python的复合对象类型支持任意结构

嵌套对象在内部被表示为对不同内存区域的引用

  • 列表、字典和元组可以包含任何种类的对象
  • 列表、字典和元组可以任意嵌套
  • 列表和字典可以动态地扩大和缩小

引用 VS 拷贝

引用

1
2
3
4
5
6
7
8
>>> X = [1, 2, 3]
>>> L = ['a', x, 'b'] # Embed references to X's object
>>> D = {'x':X, 'y':2}
>>> X[1] = 'surprise'
>>> L
['a', [1, 'surprise', 3], 'b']
>>> D
{'x': [1, 'surprise', 3], 'y': 2}

复制操作会产生相同对象的多个引用,在原处修改可变对象时可能会影响程序中对相同对象的其他引用

拷贝

  • 没有限制条件的分片表达式(L[:])能够复制序列
  • 字典copy方法X.copy()能够复制字典
  • 有些内置函数(例如,list)能够生成拷贝(list(L))
  • copy标准库模块能够生成完整拷贝

无条件值的分片以及字典copy方法只能做顶层赋值,不能够复制嵌套的数据结构

标准模块copydeepcopy()方法可以完整的、完全独立的拷贝深层嵌套的数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> L = [1, 2, 3]
>>> D = {'a':1, 'b':2}
>>> A = L[:] # Instead of A = L(or list(L))
>>> B = D.copy() # Instead of B = D(ditto for sets)
>>> A[1] = 'Ni'
>>> B['c'] = 'spam'
>>> L, D
([1, 2, 3], {'a': 1, 'b': 2})
>>> A, B
([1, 'Ni', 3], {'a': 1, 'b': 2, 'c': 'spam'})
>>> X = [1, 2, 3]
>>> L = ['a', X[:], 'b']
>>> D = {'x':X[:], 'y':2}

比较、相等性和真值

所有的Python对象支持比较操作(相等性、相对大小)

相等性比较方法

  • ==操作符测试值的相等性

    Python运行相等测试,递归地比较所有内嵌对象

  • is表达式测试对象的一致性

    Python测试二者是否是同一个对象(在同一个内存地址中)

不等性方法

  • 数字通过相对大小进行比较
  • 字符串是按照字典顺序,一个字符接一个字符地对比进行比较("abc" < "ac")
  • 列表和元组从左到右对每部分的内容进行比较
  • 字典的相对大小比较在Python 3.0中不支持
  • 数字混合类型比较(例如,1 < 'spam') 在Python 3.0中是错误的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> L1 = [1, ('a', 3)]				# Same value, unique objects
>>> L2 = [1, ('a', 3)]
>>> L1 == L2, L1 is L2 # Equivalent?Same object?
(True, False)
>>> L1 = [1, ('a', 3)]
>>> L2 = [1, ('a', 2)]
>>> L1 < L2, L1 == L2, L1 > L2 # Less,equal,greater:tuple of results
(False, False, True)
>>> S1 = 'spam'
>>> S2 = 'spam'
>>> S1 == S2, S1 is S2
(True, True)
>>> S1 = 'a longer string'
>>> S2 = 'a longer string'
>>> S1 == S2, S1 is S2
(True, False)

Python的比较检查复合对象(包括嵌套对象)的所有部分,直到可以得出结果

Python内部暂时储存并重复使用短字符串,使用is一致性测试结果为真

Python 3.0的字典比较

比较方法

  • 编写循环根据键比较值
  • 手动比较排序的键/值列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> D1 = {'A':1, 'b':2}
>>> D2 = {'a':1, 'b':3}
>>> D1 == D2
False
>>> D1 < D2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'dict' and 'dict'
>>> list(D1.items())
[('A', 1), ('b', 2)]
>>> sorted(D1.items())
[('A', 1), ('b', 2)]
>>> sorted(D1.items()) < sorted(D2.items())
True
>>> sorted(D1.items()) > sorted(D2.items())
False

Python中真和假的含义

真和假的概念是每个对象的固有属性

  • 数字如果非零,则为真
  • 其他对象如果非空,则为真

对象真值的例子

对象
“spam” True
“” False
[] False
{} False
1 True
0.0 False
None False

None对象

一种数据类型的唯一值,被作为False

None是对象,有自己的内存块

1
2
3
>>> L = [None] * 100
>>> L
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]

列表只能为已存在的偏移赋值

bool类型

TrueFalse是整数10定制版本,可以让真值更为明确

  • 当明确地用在真值测试时,TrueFalse就变成了10,但它们使得程序员的意图更明确
  • 交互模式下运行的布尔测试的结果打印成TrueFalse的字样,而不是10,以使得程序的结果更明确
1
2
3
4
5
6
>>> bool(1)
True
>>> bool('spam')
True
>>> bool({})
False

内置函数bool用来测试一个对象的布尔值

Python的类型层次

多数对象种类相当于程序单位(函数和模块),或说明了解释器的内容(堆栈和编译码)

Python系统中的任何东西都是对象类型,可以由Python程序来处理

Type对象

类型本身也是对象类型

内置函数type(X)能够返回对象X的类型对象

每个核心类型都有内置名来支持面向对象子类的类型定制:dict、list、str、tuple、int、float、complex、byte、type、set、file

Python 3.0的types标准库模块还提供其他作为内置对象类型的名称

Python的类型可以再分为子类,所以建议使用isinstance函数

1
2
3
4
5
6
7
8
9
10
11
>>> type([1]) == type([])	# Type of another list
True
>>> type([1]) == list # List type name
True
>>> isinstance([1], list) # List or customization thereof
True
>>> import types # types has names for other types
>>> def f(): pass
...
>>> type(f) == types.FunctionType
True

Python中的其他类型

除了核心对象之外,还有函数、模块和类,典型Python的安装还有几十种其他可用的对象类型,允许作为C语言的扩展程序
或是Python的类:正则表达式对象、DBM文件、GUI组件、网络套接字等

内置类型与附带工具区别:内置类型有针对对象的生成语法,其他工具必须先导入才可以使用

内置类型陷阱

赋值生成引用,而不是拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> L = [1, 2, 3]
>>> M = ['x', L, 'Y'] # Embed a reference to L
>>> M
['x', [1, 2, 3], 'Y']
>>> L[1] = 0 # Changes M too
>>> M
['x', [1, 0, 3], 'Y']
>>> L = [1, 2, 3]
>>> M = ['x', L[:], 'Y'] # Embed a copy of L
>>> L[1] = 0 # Changes only L,not M
>>> L
[1, 0, 3]
>>> M
['x', [1, 2, 3], 'Y']

如果不希望修改的值被所有共享对象共享,可以通过使用无限制条件的分片生成一个顶层拷贝

重复能够增加层次深度

1
2
3
4
5
6
7
8
9
10
11
12
>>> L = [4, 5, 6]
>>> X = L * 4 # Like [4,5,6] + [4,5,6] + ..
>>> Y = [L] * 4 # [L] + [L] + ... = [L,L,...]
>>> X
[4, 5, 6, 4, 5, 6, 4, 5, 6, 4, 5, 6]
>>> Y
[[4, 5, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]
>>> L[1] = 0 # Impacts Y but not X
>>> X
[4, 5, 6, 4, 5, 6, 4, 5, 6, 4, 5, 6]
>>> Y
[[4, 0, 6], [4, 0, 6], [4, 0, 6], [4, 0, 6]]

当序列被外层序列嵌套时,外层序列的重复操作会重复多个内层序列的引用

留意循环数据结构

一个复合对象包含指向自身的引用称为循环对象

Python在对象中检测到循环会打印[...]

循环对象可能会导致程序代码陷入无法预期的循环当中

1
2
3
4
>>> L = ['grail']	# Append referencce to same object
>>> L.append(L) # Generates cycle in object:[...]
>>> L
['grail', [...]]

不可变类型不可以在原处改变

可以通过分片、合并等操作创建一个新的对象,再赋值给原引用

1
2
3
4
5
6
>>> T = (1, 2, 3)
>>> T[2] = 4 # Error!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> T = T[:2] + (4,) # OK:(1,2,4)

本章习题

  1. 怎么确定元组有多大

内置的len函数会传回Python中任何容器对象的长度(所含元素的数目),包括元组在内

这是内置函数,而不是类型方法,因为它适用于多种对象

通常,内置函数和表达式可以跨越多种对象类型

方法特定于一种单个的对象类型,尽管通过某些方式可以在多种类型上使用(例如,索引,在列表和元组上都有效)

  1. 写个表达式,修改元组中第一个元素,在此过程中(4,5,6)应该变成(1,5,6)

因为元组是不可变的,无法真正地在原处修改元组,但你以用所需要的值产生新元组

已知T=(4, 5,6),要修改第一个元素时,可以从其组成成分进行分片运算和合并来创建新元组:T=(1,)+T[1:]

也可以把元组转成列表,在原处进行修改,再转换成元组

如果知道对象需要在原处进行修改,就使用列表

  1. open文件调用中,默认的处理模式自变量是什么

    open文件调用中的处理模式参数默认值为’r’:读取输入

    对于输入文本文件,只要传入外部文件名即可

  2. 可能使用什么模块把Python对象储存在文件中,而不需要亲自将它们转换成字符串

    pickle模块可用于把Python对象储存在文件中,而不用刻意转成字符串

    struct模块也是相关的,但是,那是要把数据打包成为二进制格式,从而保存在文件中

  3. 怎么一次复制嵌套结构的所有组成部分

    如果需要复制嵌套结构X的所有组成部分就导入copy模块,然后调用copy.deepcopy(X)

    引用往往就是所需要的行为,而浅层复制(例如,alist[:]aDict. copy())通常就足够满足大多数的复制

  4. Python在什么时候会认为一个对象为真

    如果对象是非零数字或非空集合体对象,就被认作是真

    内置的TrueFalse关键字,从实质上来说,就是预先定义的整数10

CATALOG
  1. 1. 第四章 介绍Python对象类型
    1. 1.1. 为什么使用内置类型
      1. 1.1.1. Python的核心数据类型
    2. 1.2. 数字
      1. 1.2.0.1. 浮点数
      2. 1.2.0.2. 数学模块
      3. 1.2.0.3. random模块
  2. 1.3. 字符串
    1. 1.3.1. 序列的操作
      1. 1.3.1.1. 索引
      2. 1.3.1.2. 分片
      3. 1.3.1.3. 合并与重复
    2. 1.3.2. 不可变性
    3. 1.3.3. 类型特定的方法
    4. 1.3.4. 寻求帮助
    5. 1.3.5. 编写字符串的其他方法
    6. 1.3.6. 模式匹配
  3. 1.4. 列表
    1. 1.4.1. 序列操作
    2. 1.4.2. 类型特定的操作
    3. 1.4.3. 边界检查
    4. 1.4.4. 嵌套
    5. 1.4.5. 列表解析
  4. 1.5. 字典
    1. 1.5.1. 映射操作
    2. 1.5.2. 重访嵌套
    3. 1.5.3. 键的排序:for循环
      1. 1.5.3.1. 键的排序
      2. 1.5.3.2. for循环和while循环
    4. 1.5.4. 迭代和优化
    5. 1.5.5. 不存在的键:if测试
      1. 1.5.5.1. 不存在的键
      2. 1.5.5.2. 测试
      3. 1.5.5.3. if语句
  5. 1.6. 元组
    1. 1.6.1. 为什么要用元组
  6. 1.7. 文件
    1. 1.7.1. 文件对象的方法
    2. 1.7.2. 其他文件类工具
  7. 1.8. 其他核心类型
    1. 1.8.1. 如何破坏代码的灵活性
    2. 1.8.2. 用户定义的类
    3. 1.8.3. 剩余的内容
  8. 1.9. 本章习题
  • 2. 第五章 数字
    1. 2.1. Python的数字类型
      1. 2.1.1. 数字常量
        1. 2.1.1.1. 十六进制数、八进制和二进制常量
        2. 2.1.1.2. 复数
        3. 2.1.1.3. 编辑其他的数字类型
      2. 2.1.2. 内置数学工具和拓展
        1. 2.1.2.1. 表达式操作符
        2. 2.1.2.2. 内置数学函数
        3. 2.1.2.3. 公用模块
        4. 2.1.2.4. 特定于类型的方法
      3. 2.1.3. Python表达式操作符
        1. 2.1.3.1. 混合操作所遵循的操作优先级
        2. 2.1.3.2. 括号分组的子表达式
        3. 2.1.3.3. 混合类型自动升级
        4. 2.1.3.4. 预习:运算符重载
    2. 2.2. 在实际应用中的数字
      1. 2.2.1. 变量和基本的表达式
        1. 2.2.1.1. 变量
        2. 2.2.1.2. 注释
      2. 2.2.2. 数字显示的格式
      3. 2.2.3. 比较:一般的和连续的
        1. 2.2.3.1. 一般的
        2. 2.2.3.2. 连续的
      4. 2.2.4. str和repr显示格式
      5. 2.2.5. 除法:传统除法、Floor除法和真除法
        1. 2.2.5.1. 真除法
        2. 2.2.5.2. Floor除法
        3. 2.2.5.3. 传统除法
        4. 2.2.5.4. 支持两个Python版本
        5. 2.2.5.5. Floor除法VS截断除法
        6. 2.2.5.6. 为什么Floor除法很重要
      6. 2.2.6. 整数精度
      7. 2.2.7. 复数
      8. 2.2.8. 十六进制、八进制和二进制记数
        1. 2.2.8.1. 整数转换字符串
        2. 2.2.8.2. 字符串转换整数
      9. 2.2.9. 位操作
      10. 2.2.10. 其他的内置数学工具
    3. 2.3. 其他数字类型
      1. 2.3.1. 小数数字
        1. 2.3.1.1. 基础知识
        2. 2.3.1.2. 设置全局精度
        3. 2.3.1.3. 小数上下文管理器
      2. 2.3.2. 分数类型
        1. 2.3.2.1. 基本知识
        2. 2.3.2.2. 数值精度
        3. 2.3.2.3. 转换和混合类型
          1. 2.3.2.3.1. float -> fraction
          2. 2.3.2.3.2. fraction -> float
          3. 2.3.2.3.3. 混合类型
          4. 2.3.2.3.4. 精度
      3. 2.3.3. 集合
        1. 2.3.3.1. Python 2.6中的集合基础知识
        2. 2.3.3.2. Python 3.0中的集合常量
        3. 2.3.3.3. 不可变限制和冻结集合
        4. 2.3.3.4. Python 3.0中的集合解析
        5. 2.3.3.5. 为什么使用集合
      4. 2.3.4. 布尔型
    4. 2.4. 数字拓展
    5. 2.5. 本章习题
  • 3. 第六章 动态类型简介
    1. 3.1. 缺少类型声明语句的情况
      1. 3.1.1. 变量、对象和引用
        1. 3.1.1.1. 变量创建
        2. 3.1.1.2. 变量类型
        3. 3.1.1.3. 变量使用
        4. 3.1.1.4. 对象
        5. 3.1.1.5. 引用
      2. 3.1.2. 类型属于对象,而不是变量
      3. 3.1.3. 对象的垃圾收集
    2. 3.2. 共享引用
      1. 3.2.1. 共享引用和在原处修改
      2. 3.2.2. 共享引用和相等
    3. 3.3. 动态类型随处可见
    4. 3.4. 本章习题
  • 4. 第七章 字符串
    1. 4.1. 字符串常量
      1. 4.1.1. 单双引号字符串是一样的
      2. 4.1.2. 用转义序列代表特殊字节
      3. 4.1.3. raw字符串抑制转义
      4. 4.1.4. 三重引号编写多行字符串块
    2. 4.2. 实际应用中的字符串
      1. 4.2.1. 基本操作
      2. 4.2.2. 索引和切片
        1. 4.2.2.1. 拓展分片:第三个限制值
      3. 4.2.3. 为什么要在意:分片
      4. 4.2.4. 字符串转换工具
        1. 4.2.4.1. 字符串代码转换
      5. 4.2.5. 修改字符串
    3. 4.3. 字符串方法
      1. 4.3.1. 字符串方法实例:修改字符串
      2. 4.3.2. 字符串方法实例:文本解析
      3. 4.3.3. 实际应用中的其他常见字符串方法
      4. 4.3.4. 最初的字符串模块(在Python 3.0中删除)
    4. 4.4. 字符串格式化表达式
      1. 4.4.1. 字符串格式化实现形式
      2. 4.4.2. 字符串格式化表达式
      3. 4.4.3. 更高级的字符串格式化表达式
        1. 4.4.3.1. 字符串格式化代码
        2. 4.4.3.2. 转换目标的通用结构
      4. 4.4.4. 基于字典的字符串格式化
    5. 4.5. 字符串格式化调用方法
      1. 4.5.1. 基础知识
      2. 4.5.2. 添加键、属性和偏移量
      3. 4.5.3. 添加具体格式化
      4. 4.5.4. 与%格式化表达式比较
      5. 4.5.5. 为什么用新的格式化方法
        1. 4.5.5.1. 格式化方法
        2. 4.5.5.2. 额外功能
        3. 4.5.5.3. 显示值引用
        4. 4.5.5.4. 方法名和通用参数
        5. 4.5.5.5. 将来可能废弃
    6. 4.6. 通常意义下的类型分类
      1. 4.6.1. 同样分类的类型共享其操作集合
      2. 4.6.2. 可变类型能够在原处修改
    7. 4.7. 本章习题
  • 5. 第八章 列表和字典
    1. 5.1. 列表
      1. 5.1.1. 列表的主要特性
      2. 5.1.2. 常用列表常量和操作
    2. 5.2. 实际应用中的列表
      1. 5.2.1. 基本列表操作
      2. 5.2.2. 列表迭代和解析
      3. 5.2.3. 索引、分片和矩阵
      4. 5.2.4. 原处修改列表
        1. 5.2.4.1. 索引与分片的赋值
        2. 5.2.4.2. 列表方法调用
        3. 5.2.4.3. 其他常见列表操作
    3. 5.3. 字典
      1. 5.3.1. 字典的主要特性
      2. 5.3.2. 常见字典常量和操作
    4. 5.4. 实际应用中的字典
      1. 5.4.1. 字典的基本操作
      2. 5.4.2. 原处修改字典
      3. 5.4.3. 其他字典方法
      4. 5.4.4. 语言表
      5. 5.4.5. 字典用法注意事项
        1. 5.4.5.1. 使用字典模拟灵活的列表
        2. 5.4.5.2. 字典用于稀疏数据结构
        3. 5.4.5.3. 避免missing-key错误
        4. 5.4.5.4. 使用字典作为”记录”
      6. 5.4.6. 为什么要在意字典接口
      7. 5.4.7. 创建字典的其他方法
      8. 5.4.8. Python 3.0中的字典变化
        1. 5.4.8.1. Python 3.0中的字典
        2. 5.4.8.2. 字典解析
        3. 5.4.8.3. 字典视图
        4. 5.4.8.4. 字典视图和集合
        5. 5.4.8.5. 排序字典键
        6. 5.4.8.6. 字典大小比较不再有效
        7. 5.4.8.7. has_key方法已死:in永生
    5. 5.5. 本章习题
  • 6. 第九章 元组、文件及其他
    1. 6.1. 元组
      1. 6.1.1. 实际应用中的元组
        1. 6.1.1.1. 元组的特殊语法:逗号和圆逗号
        2. 6.1.1.2. 转换、方法以及不可变性
          1. 6.1.1.2.1. 转换
          2. 6.1.1.2.2. 方法
          3. 6.1.1.2.3. 不可变性
      2. 6.1.2. 为什么有了列表还要元组
    2. 6.2. 文件
      1. 6.2.1. 打开文件
        1. 6.2.1.1. 处理模式
        2. 6.2.1.2. 参数
      2. 6.2.2. 使用文件
      3. 6.2.3. 实际应用中的文件
        1. 6.2.3.1. Python 3.0中的文本和二进制文件
        2. 6.2.3.2. 在文件中存储并解析Python对象
        3. 6.2.3.3. 用pickle存储Python的原生对象
        4. 6.2.3.4. 文件中打包二进制数据的存储和解析
        5. 6.2.3.5. 文件上下文管理器
      4. 6.2.4. 其他文件工具
    3. 6.3. 重访类型分类
      1. 6.3.0.1. 对象分类
      2. 6.3.0.2. 要点
    4. 6.3.1. 为什么要在意操作符重载
  • 6.4. 对象灵活性
  • 6.5. 引用 VS 拷贝
    1. 6.5.1. 引用
    2. 6.5.2. 拷贝
  • 6.6. 比较、相等性和真值
    1. 6.6.1. Python 3.0的字典比较
    2. 6.6.2. Python中真和假的含义
      1. 6.6.2.1. None对象
      2. 6.6.2.2. bool类型
    3. 6.6.3. Python的类型层次
    4. 6.6.4. Type对象
  • 6.7. Python中的其他类型
    1. 6.7.1. 内置类型陷阱
    2. 6.7.2. 赋值生成引用,而不是拷贝
    3. 6.7.3. 重复能够增加层次深度
    4. 6.7.4. 留意循环数据结构
    5. 6.7.5. 不可变类型不可以在原处改变
  • 6.8. 本章习题