Python 核心编程[第六章]
0x00前言
0x01序列
那些可变类型对象的方法是没有返回值的,它们直接在列表内部进行改变,那些不变类型对象的方法有返回值。大部分情况是这样。
一、操作符
1.标准操作符
- 大于、小于、小于等于、大于等于、等于、不等于
2.序列类型操作符
- 成员关系:(in、not in)
- 连接操作符:( + ) 支持 +=
- 重复操作符:( * ) 支持 *=
- 切片操作符:([x]、[x:y]、[x:y:step]);此处索引可以用正,负、范围超过序列长度的值甚至是 None 做索引,在一个每次去除最后一个成员又要显示原始序列的情况下用 None 做索引是个不错的技巧。
for i in [None].extend(range(-1,-len(s),-1)):
print s[:i]
二、内建函数
序列本身就包含了迭代的概念,因为迭代这个概念就是从序列,迭代器,或其他支持迭代操作的对象中泛化而来的。
1.类型转化函数
- list()
- str()
- tuple()
2.操作性内建函数
(1)只能接收序列对象参数的:
- len()
- reversed():返回逆序迭代器
- sum():
(2)还可以接收可迭代对象参数的:
- enumerate()
- sorted()
- zip():返回一个元组
- max():还可以接收一个参数列表
- min(): 还可以接收一个参数列表
0x02字符串
Python 中字符串并不以 Null 结尾。
一、字符串创建等基本操作
# 创建和赋值
a = 'Hello'
b = "Hello"
c = str()
#访问
a[0] #取第一个元素
a[1:3] #取第二到三个元素
a[0:]
a[:3]
#改变
a = 'Word' #改变值为 Word
a = b #改变值为 b 中的值
#删除
a = a[1:] #删除某个字符
a = '' #清空
del a #删除整个字符串
二、字符串操作符
1.标准操作符
- 大于、小于、小于等于、大于等于、等于、不等于
2.序列操作符
-
同上(序列章节的序列操作符)
-
编译时连接:python 支持下述写法
a = "b" "c" <=> a = "bc"
3.只适用于字符串的操作符
(1)格式化操作符
格式化字符串支持两种形式,一种是元组形式,第二种是字典键值形式。键值形式中,键作为格式字符串出现,相应的值作为参数在转化时提供给格式字符串。
字符格式化符号
格式化字符 | 转换方式 |
---|---|
%c | 转换成 ASCII |
%r | 用 repr() 函数进行字符串转换 |
%s | 优先用 str() 函数进行字符串转换 |
%d | 转换成有符号十进制 |
%u | 转换成无符号十进制 |
%o | 转换成无符号八进制 |
%x/%X | 转换成无符号十六进制 |
%e/%E | 转换成科学计数法 |
%f/%F | 转换成浮点型 |
%g/%G | |
%% | 输出% |
格式化操作辅助指令
符号 | 作用 |
---|---|
* | 定义宽度或小数点精度 |
- | 用作左对齐 |
+ | 在整数前面显示加号 |
< sp> | 在整数面前显示空格 |
# | 在八进制数前面显示(‘0’),在十六进制前面显示(‘0x’) |
0 | 显示的数字前面填充(‘0’) |
% | 输出一个单一的’%’ |
(var) | 映射变量(字典参数) |
m.n | m 是显示的最小总宽度,n 是小数点后的位数 |
(2)原始操作符
在定义的字符串前面加 r/R 则在被定义的字符串中有 \n(此处只的是 ‘’ 和 ‘n’ 两个组合的符号而不是换行符),则该字符串中的 \n 会被定义成两个符号,而不会被转换成换行符。
Unicode 字符串操作符
- u/U,在字符串定义前面加 u/U 该字符串会被转换成 Unicode 字符串对象。
三、内建函数和方法
1.序列类型函数
- 同上
2.字符串内建函数
- input()
- str()
- chr()
- ord()
4.字符串内建方法总表
//待完善
四、字符串的独特性
1.转义字符
- \OOO 八进制值
- \xXX x打头的十六进制值
- \ 连字符,将本行和下一行内容相连接
说明 | 字符 | 转义符号 | 十进制 | 十六进制 |
---|---|---|---|---|
空字符 | Null | \0 | 0 | 0x00 |
响铃字符 | BEL | \a | 7 | 0x07 |
退格 | BS | \b | 8 | 0x08 |
横向制表符 | HT | \t | 9 | 0x09 |
换行 | LF | \n | 10 | 0x0A |
纵向制表符 | VT | \v | 11 | 0x0B |
换页 | FF | \f | 12 | 0x0C |
回车 | CR | \r | 13 | 0x0D |
转义 | ESC | \e | 27 | 0x1B |
双引号 | " | \ " | 34 | 0x22 |
单引号 | ’ | \ ’ | 39 | 0x27 |
反斜杠 | \ | \ | 92 | 0x5C |
2.字符串的不变性
字符串是不可变类型,不能对字符串中的一个或多个字符进行改变。
五、Unicode 相关
//待完善
六、相关模块
0x03列表
一、列表的创建访问修改删除等
# 创建和赋值
a = []
b = list()
#访问
a[0] #取第一个元素
a[1:3] #取第二到三个元素
a[0:]
a[:3]
a[x][y]
#改变
a[x] = 'Word' #改变值为 Word
a = b #改变值为 b 中的值
#删除
a = a[1:] #删除某部分成员
a.remove(xxx) #移除 xxx 成员
a.pop() #移除列表最后一个成员并返回
del a #删除整个列表
二、操作符
1.标准操作符
- 大于、小于、小于等于、大于等于、等于、不等于
2.序列操作符
- 切片
- 成员间的关系
- 连接操作符:也可以用 extend() 方法进行连接,效果和 + 相同
- 重复操作符
3.列表操作符和解析列表
python 中没有专门定义关于列表的操作符
(1)解析列表
[ i * 2 for i in [8,-2,5]]
[ i for in range(8) if i %2 == 0]
三、内建函数
1.序列类型函数
- len()
- max() 和 min()
- sorted() 和 reversed()
- enumerate() 和 zip()
- sum()
- list() 和 tuple()
2.列表类型内建函数
不考虑 range() 函数的话,列表中没有特定的内建函数。不过在 python3 中,range() 返回的是 range() 类型的对象。
3.列表类型所有内建方法
虽然大部分可变对象的方法没有返回值,不过 Python 2.4 版本之后,reversed() 和 sorted() 内建函数可以作为表达式,因为它们返回一个对象,它们并不改变原来的列表,而是返回一个新的对象。不过经实验作者发现 Python 3 环境和 Python 2.7 环境下它们并没有返回值。
方法 | 作用 |
---|---|
append(obj) | 向列表添加元素 |
count(obj) | 返回列表中的元素出现的次数 |
extend(seq) | 将 seq 序列中的内容添加进列表 |
index(obj,i,j=len(list)) | 返回 obj 在列表中的下标,也可以使用 i,j 指定范围 |
insert(index,obj) | 在 index 处添加元素 obj |
pop(index= -1) | 删除并返回指定位置对象,默认为末尾位置 |
remove(obj) | 从列表中删除 obj 对象 |
reverse() | 将列表翻转 即最后一个到第一个,以此类推 |
sort(func=None,key=None,reverse=False) | 以指定方式排序,可以指定 func 来指定它的排序函数,默认为归并 |
四、列表的特性
1.用列表构建其他数据结构
(1)堆栈
#!/usr/bin/env python
# 待补充
(2)队列
#!/usr/bin/env python
# 待补充
0x04元组
一、元组的创建访问修改
# 创建和赋值
a = (x,xx,xxx)
b = (xx,)
c = tuple()
#访问
a[0] #取第一个元素
a[1:3] #取第二到三个元素
a[0:]
a[:3]
a[x][y]
#改变
a = b #改变值为 b 中的值
#删除
成员并返回
del a #删除整个元组
二、元组的操作符
1.标准操作符
- 大于、小于、小于等于、大于等于、等于、不等于
2.序列操作符
- 重复操作、连接操作、成员关系操作、切片操作
3.元组操作符
同列表一样,没有自己的操作符。
三、内建函数
1.序列类型函数
- len()
- max()
- min()
- str()
- 等
2.内建函数
同列表一样没有自己的内建函数,
3.方法
列表的方法都跟列表对象的可变性有关,比如排序、添加等,因为元组不可变,所以这些方法是多余的。
四、元组的特殊性
1.不可变性
因为列表和元组相似,所以在传递参数并且不想别人动自己数据时通常转化为元组形式,如果需要对数据进行修改时,则要转化为列表形式。
2.不可变中的仅存的温存
虽然元组是不可变的类型,不过它在某种意义上可以说成可变的,不过这不是真正的改变了元组的值。在以下场景可以变相看成元组"可变":
- 1.两个元组连接成一个新的元组
- 2.一个元组做重复操作形成一个新的元组
- 3.改变元组元素中的可变元素
3.默认元组类型
在所有的多对象的、逗号分隔的、没有明确定义类型的一些类型的集合都默认为元组类型。并且在返回多对象的函数时,没有明确的符号封装都默认返回元组类型。
'ab',-1,'xyz' #该段数据默认为元组类型
4,2 < 5,3 <=> (4,True,3) #因为默认元组类型
4.单元素元组
因为括号被重载了,所以没法用括号创建单元素元组,所以一般创建单元素元组的时候都会在元素后边添加一个 ‘,’ ,例如 a = (1,)
0x05其他知识
一、深拷贝和浅拷贝
对象赋值实际上是简单的对象引用。也就是说,当你创建一个对象,然后把它赋值给另一个变量时,Python 并没有拷贝这个对象,而是拷贝了对象的引用。
例如:
In [5]: var1 = [1,'name']
In [6]: var2 = var1[:]
In [7]: id(var1),id(var2)
Out[7]: (139942302706792, 139942302706216)
In [8]: id(var1[0]),id(var2[0]),id(var1[1]),id(var2[1])
Out[8]: (23560536, 23560536, 139942382243440, 139942382243440)
## 由本例可以看出在拷贝的时候虽然生成了两个 id 不同,内容相同的两个变量
## 不过这两个不同变量中的元素 id 是相同的
## 也就是说在拷贝的时候,并没有拷贝一个对象,而是将对象中元素的引用拷贝给了 var2
## 注意如果直接用 var1 = var2 进行赋值,var1 和 var2 直接拥有相同 id
## 其实这就是所谓的浅拷贝
下面举个例子让我们更深了解浅拷贝和深拷贝中的一些问题。
In [54]: p = ['name',['save',100]] # 模拟银行
In [55]: h = p[:] # 模拟用户 h
In [56]: w = list(p) # 模拟用户 w
### 获取 h,w id信息
In [57]: [id(x) for x in p,h,w]
Out[57]: [139942301649448, 139942326067568, 139942301650240]
### 获取 h,w 中元素的 id 信息
In [58]: [id(x) for x in h]
Out[58]: [139942382243440, 139942323010016]
In [59]: [id(x) for x in w]
Out[59]: [139942382243440, 139942323010016]
### 在此过程中对 h,w 分别进行初始化设置用户名
In [60]: h[0] = 'hhhh'
In [61]: w[0] = 'wwww'
In [62]: h,w
Out[62]: (['h', ['save', 100]], ['w', ['save', 100]])
### 此时 h 用户从银行取走 30 元,对 h 用户中的钱进行修改
In [63]: h[1][1] = 20
### 查看用户 h,w 银行信息,发现 w 用户的钱也减少了
## 【问题1】:这是为什么呢?
In [64]: h,w,p
Out[64]: (['h', ['save', 20]], ['w', ['save', 20]], ['name', ['save', 20]])
## 【答案1】:因为这是一次浅拷贝,其实就是创建了一个类型和原对象一样,内容为元对象元素的引用
## 也就是拷贝对象本身是新的,内容不是,还是原来的内容
## 【问题2】:那 h,w 名字被赋值的时候为什么相互不影响?
## 【答案2】:因为列表中的元素,第一个字符串是不可变对象,第二个是可变对象。
## 所以在修改的时候不可变对象不会受影响,而可变对象则会受到影响。
## 修改后的个元素 id
In [65]: [id(x) for x in h]
Out[65]: [139942309759136, 139942323010016]
In [66]: [id(x) for x in w]
Out[66]: [139942309758272, 139942323010016]
## 【问题3】:哪如果这样怎样避免这种情况
## 【答案3】:使用 copy 模块的深拷贝函数 deepcopy()
- 序列类型默认是浅拷贝,可以由 完全切片、内建函数、copy 模块的 copy 函数实现。
- 关于拷贝操作的警告:
- 第一:非容器没有被拷贝这样的说法,浅拷贝是用完全切片操作完成的。
- 第二:如果元组变量只包含原子类型对象,对它深拷贝不会进行。即、如果把上述代码的 p = [‘name’,[‘save’,100]] 改成 p = [‘name’,(‘save’,100)] 即使调用深拷贝函数,该深拷贝也不会进行。
二、序列类小结
序列类型操作符、内建函数、方法
//待完善
操作符内建函数和方法 | 字符串 | 列表 | 元组 |
---|---|---|---|
[] | √ | ||
() | √ | ||
“” | √ | ||
append() | √ | √ | √ |
capitalize() | √ | √ | √ |
center() | √ | √ | √ |
chr() | √ | √ | √ |
count() | √ | √ | √ |
decode() | √ | √ | √ |
encode() | √ | √ | √ |
endswith() | √ | √ | √ |
expandtabs | √ | √ | √ |
extend() | √ | √ | √ |
find() | √ | √ | √ |
hex() | √ | √ | √ |
index() | √ | √ | √ |
insert() | √ | √ | √ |
isdecimal() | √ | √ | √ |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ | |
√ | √ | √ |