6.1 序列
序列是一种 Python 的类型,它们的成员有序排列的,并且可以通过下标
偏移量访问到它的一个或者几个成员。
包括下面这些:字符串(普通字符串和 unicode 字符串),列表,和元组类型。
适用于所有序列类型的操作符和内建函数(BIFs):
- 操作符
- 内建函数
- 特性
- 相关模块
6.1.1 标准类型操作符
标准类型操作符(参见 4.5 节)一般都能适用于所有的序列类型
6.1.2 序列类型操作符
表 6.1 列出了对所有序列类型都适用的操作符。操作符是按照优先级从高到底的顺序排列
的。
序列操作符 | 作用 |
---|---|
seq[ind] | 获得下标为 ind 的元素 |
seq[ind1:ind2] | 获得下标从 ind1 到 ind2 间的元素集合 |
seq * expr | 序列重复 expr 次 |
seq1 + seq2 | 连接序列 seq1 和 seq2 |
obj in seq | 判断 obj 元素是否包含在 seq 中 |
obj not in seq | 判断 obj 元素是否不包含在 seq 中 |
- 成员关系操作符 (in, not in)
成员关系操作符使用来判断一个元素是否属于一个序列的
- 连接操作符( + )
允许把一个序列和另一个相同类型的序列做连接。
这种方式看起来似乎实现了把两个序列内容合并的概念,但是这个操作不是最快或者说最有效的:
对字符串来说,这个操作不如把所有的子字符串放到一个列表或可迭代对象中,然后调用一个join方法来把所有的内容连接在一起节约内存;类似地,对列表来说,我们推荐读者用列表类型的extend()方法来把两个或者多个列表对象合并。
- 重复操作符(*)
当需要一个序列的多份拷贝时,重复操作符非常有用。copies_int必须是一个整数(1.6节里面有讲到,不能是长整数).像连接操作符一样,该操作符返回一个新的包含多份原对象拷贝的对象
- 切片操作符 ( [], [:], [::] )
序列类型是其元素被顺序放置的一种数据结构类型,这种方式允许通过指定下标的方式来获得某一个数据元素,或者通过指定下标范围来获得一组序列的元素.这种访问序列的方式叫做切片。
偏移量可以是正值,范围从0到偏移最大值(比序列长度少一),实际的范围是 0 <= inde <= len(sequece)-1。另外,也可以使用负索引,范围是 -1 到序列的负长度,-len(sequence), -len(sequence) <= index <= -1。
用步长索引来进行扩展的切片操作
序列的最后一个切片操作是扩展切片操作,它多出来的第三个索引值被用做步长参数。
>>> s = 'abcdefgh'
>>> s[::-1] # 可以视作"翻转"操作
'hgfedcba'
>>> s[::2] # 隔一个取一个的操作
'aceg'
切片索引的更多内容
切片索引的语法要比简单的单一元素索引灵活的多。开始和结束素引值可以超过字符串的长度。
>>> ('Faye', 'Leanna', 'Daylen')[-100:100]
('Faye', 'Leanna', 'Daylen')
用 None 作为索引值:
>>> s = 'abcde'
>>> for i in [None] + range(-1, -len(s), -1):
... print s[:i]
...
abcde
abcd
abc
ab
a
6.1.3 内建函数(BIFs)
- 类型转换
内建函数 list(),str()和tuple()被用做在各种序列类型之间转换。你可以把它们理解成其他语言里面的类型转换,但是并没有进行任何的转换。这些转换实际上是工厂函数(在第4章介绍),将对象作为参数,并将其内容(浅)拷贝到新生成的对象中。一旦一个 Python 的对象被建立,我们就不能更改
其身份或类型了.如果你把一个列表对象传给 list()函数,便会创建这个对象的一个浅拷贝,
然后将其插入新的列表中。同样地,在做连接操作和重复操作时,我们也会这样处理。
所谓浅拷贝就是只拷贝了对对象的索引,而不是重新建立了一个对象!如果你想完全的拷
贝一个对象(包括递归,如果你的对象是一个包含在容器中的容器),你需要用到深拷贝
表 6.2 序列类型转换工厂函数
函数 | 含义 |
---|---|
list(iter) | 把可迭代对象转换为列表 |
str(obj) | 把 obj 对象转换成字符串(对象的字符串表示法) |
unicode(obj) | 把对象转换成 Unicode 字符串(使用默认编码) |
basestring() | 抽象工厂函数,其作用仅仅是为 str 和 unicode 函数提供父类,所以不能被实例化,也不能被调用(详见第 6.2 节) |
tuple(iter) | 把一个可迭代对象转换成一个元组对象 |
- 序列类型内建函数
表 6.3 序列类型可用的内建函数
函数名 | 功能 |
---|---|
enumerate(iter) | 接受一个可迭代对象作为参数,返回一个 enumerate 对象(同时也是一个迭代器),该对象生成由 iter 每个元素的 index 值和 item 值组成的元组(PEP 279) |
len(seq) | 返回 seq 的长度 |
max(iter,key=None) or max(arg0,arg1…,key=None) | 返回iter或(arg0,arg1,…)中的最大值,如果指定了 key,这个 key 必须是一个可以传给sort()方法的,用于比较的回调函数. |
min(iter, key=None) or min(arg0,arg1…key=None)b | 返回iter里面的最小值;或者返回(arg0,arg2,…)里面的最小值;如果指定了key,这个key必须是一个可以传给sort()方法的,用于比较的回调函数. |
reversed(seq) | 接受一个序列作为参数,返回一个以逆序访问的迭代器(PEP 322) |
sorted(iter,func=None,key=None,reverse=False) | 接受一个可迭代对象作为参数,返回一个有序的列表;可选参数func,key 和 reverse 的含义跟list.sort()内建函数的参数含义一样. |
sum(seq, init=0) | 返 回 seq 和 可 选 参 数 init 的总和,其效果等同于 reduce(operator.add,seq,init) |
zip([it0, it1,… itN]) | 返回一个列表,其第一个元素是it0,it1,…这些元素的第一个元素组成的一个元组,第二个…,类推. |
6.2 字符串
Python 里面单引号和双引号都可以创建字符串(python中没有字符类型),Python实际上有3类字符串.通常意义的字符串(str)和 Unicode 字符串(unicode)实际上都是抽象类 basestring 的子类(basestring 是不能实例化的)
- 赋值(等同新建):引号, str(), 切片
- 删除:赋一个空字符串或者使用 del 语句
6.2.1 标准类型操作符
需要注意的是:在做比较操作的时候,字符串是按照 ASCII 值的大小来比较的
6.2.2 序列操作符
-
切片: []
- 正向索引
- 反向索引
- 默认索引
-
成员操作符(in ,not in)
成员操作符用于判断一个字符或者一个子串(中的字符)是否出现在另一个字符串中。出现则返回True,否则返回 False。
注意,成员操作符不是用来判断一个字符串是否包含另一个字符串的,这样的功能由find()或者index()(还有它们的兄弟:rfind()和rindex())函数来完成
的
- 连接符( + )
- 运行时刻字符串连接
没有必要导入 string 模块了,除非你需要访问该模块自己定义的
字符串常量。出于性能方面的考虑,我们还是建议你不要用 string 模块。原因是 Python 必须为每一个参加连接操作的字符串分配新的内存,包括新产生的字符串。
取而代之,我们推荐你像下面介绍的那样使用字符串格式化操作符(%),或者把所有的字符串放到一个列表中去,然后用一个 join()方法来把它们连接在
一起。
- 编译时字符串连接
Python 的语法允许你在源码中把几个
字符串连在一起写,以此来构建新字符串:
>>> foo = "Hello" 'world!'
>>> foo
'Helloworld!'
- 普通字符串转化为 Unicode 字符串
如果把一个普通字符串和一个 Unicode 字符串做连接处理,Python 会在连接操作前先把普
通字符串转化为 Unicode 字符串:
>>> 'Hello' + u' ' + 'World' + u'!'
u'Hello World!'
6.2.3 只适用于字符串的操作符
6.2.3.1 格式化操作符 %
Python 风格的字符串格式化操作符。只适用于字符串类型,非常类似于C语言里面的printf()函数的字符串格式化
表 6.4 字符串格式化符号
格式化字符 | 转换方式 |
---|---|
%c | 转换成字符(ASCII码值,或者长度为一的字符串) |
%r | 优先用 repr()函数进行字符串转换 |
%s | 优先用 str()函数进行字符串转换 |
%d / %i | 转成有符号十进制数 |
%u | 转成无符号十进制数 |
%o | 转成无符号八进制数 |
%x/%X | (Unsigned)转成无符号十六进制数(x/X 代表转换后的十六进制字符的大小写) |
%e/%E | 转成科学计数法(e/E 控制输出 e/E) |
%f/%F | 转成浮点数(小数部分自然截断) |
%g/%G | %e和%f/%E 和%F 的简写 |
%% | 输出% |
Python 支持两种格式的输入参数:
-
第一种是元组,这基本上是一种的Cprintf()风格的转换参数集;
-
第二种形式是字典形式,key是作为格式字符串出现,相对应的 value 值作为参数在进行转化时提
供给格式字符串.
格式字符串既可以跟print语句一起用来向终端用户输出数据,又可以用来合并字符串形成新字符串,而且还可以直接显示到 GUI(Graphical User Interface)界面上去.
表 6.5 格式化操作符辅助指令
符号 | 作用 |
---|---|
* | 定义宽度或者小数点精度 |
- | 用做左对齐 |
+ | 在正数前面显示加号( + ) |
在正数前面显示空格 | |
# | 在八进制数前面显示零(‘0’),在十六进制前面显示’0x’或者’0X’(取决于用的是’x’还是’X’) |
0 | 显示的数字前面填充‘0’而不是默认的空格 |
% | ‘%%‘输出一个单一的’%’ |
(var) | 映射变量(字典参数) |
m.n | m 是显示的最小总宽度,n是小数点后的位数(如果可用的话) |
# 十六进制输出:
>>> "%x" % 108
# 浮点数和科学记数法形式输出:
>>> '%.2f' % 1234.567890
'1234.57'
>>> '%E' % 1234.567890
'1.234568E+03'
# 整数和字符串输出:
>>> "%+d" % 4
'+4'
>>>
>>> "%+d" % -4
'-4'
事实上,所有的 Python对象都有一个字符串表示形式
(通过 repr()函数,’’ 或str()函数来展现).print 语句自动为每个对象调用 str()函数.
更好的是,在定义自己的对象时,你可以利用"钩子"为你的对象创建字符串表达形式.这样,repr(),str()或`` 或者 print被调用时,就可以获得一个适当的字符串描述信息。
6.2.3.2 字符串模板
字符串格式化操作符是 Python 里面处理这类问题的主要手段,而且以后也是如此。然而它也不是完美的,其中的一个缺点是它不是那么直观
新式的字符串模板的优势是不用去记住所有的相关细节的,而是像现在 shell 风格的脚本
语言里面那样使用美元符号($).
由于新式的字符串 Template 对象的引进使得 string 模块又重新活了过来,Template 对象
有两个方法,substitute()和safe_substitute().前者更为严谨,在 key 缺少的情况下它会报一个 KeyError 的异常出来,而后者在缺少 key 时,直接原封不动的把字符串显示出来.
>>> from string import Template
>>> s = Template('There are ${howmany} ${lang} Quotation Symbols')
>>>
>>> print s.substitute(lang='Python', howmany=3) There are 3 Python Quotation
Symbols
>>>
>>> print s.substitute(lang='Python') Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/usr/local/lib/python2.4/string.py", line 172, in substitute
return self.pattern.sub(convert, self.template)
File "/usr/local/lib/python2.4/string.py", line 162, in convert val =
mapping[named]
KeyError: 'howmany'
>>>
>>> print s.safe_substitute(lang='Python') There are ${howmany} Python Quotation
Symbols
6.2.3.3 原始字符串操作符(r/R)
在原始字符串里,所有的字符都是直接按照字
面的意思来使用,没有转义特殊或不能打印的字符。
>>> '\n'
'\n'
>>> print '\n'
>>> r'\n'
'\\n'
>>> print r'\n'
\n
6.2.3.4 Unicode 字符串操作符( u/U )
它用来把标准字符串或者是包含 Unicode 字符的字符串转换成完全地 Unicode 字
符串对象
注意:Unicode 操作符必须出现在原始字符串操作
符前面.
ur'Hello\nWorld!'
6.2.4 内建函数
6.2.4.1 标准类型函数
- cmp(): 根据字符串的ASCII码值比较
6.2.4.2 序列类型函数
- len()
- max() and min()
- enumerate()
- zip()
6.2.4.3 字符串类型函数
- raw_input(): 使用给定字符串提示用户输入并将这个输入返回(字符串类型)
- str()和unicode()
- chr(),unichr()和ord(): 字符串和数字的互转
6.2.5 字符串内建函数
- string.capitalize()
把字符串的第一个字符大写
- string.center(width)
返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
- string.count(str, beg=0, end=len(string))
返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数
- string.decode(encoding=‘UTF-8’,errors=‘strict’)
以 encoding 指定的编码格式解码string,如果出错默认报一个ValueError 的 异 常 , 除 非 errors 指 定 的 是 ‘ignore’ 或 者’replace’
- string.encode(encoding=‘UTF-8’,errors=‘strict’)
以 encoding 指定的编码格式编码string,如果出错默认报一个ValueError的异常,除非errors指定的是’ignore’或者’replace’
- string.endswith(obj,beg=0,end=len(string))
检查字符串是否以 obj 结束,如果 beg 或者 end 指定则检查指定的范围内是否以obj结束,如果是,返回 True,否则返回 False.
- string.expandtabs(tabsize=8)
把字符串 string 中的 tab符号转为空格,默认的空
格数 tabsize 是 8.
- string.find(str, beg=0,end=len(string))
检测 str 是否包含在 string 中,如果 beg 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1
- string.index(str, beg=0,end=len(string))
跟 find()方法一样,只不过如果str不在string中会报一个异常.
- string.isalnum()
如果 string 至少有一个字符并且所有字符都是字母或数字则返回 True,否则返回 False
- string.isalpha()
如果 string 至少有一个字符并且所有字符都是字母则返回 True,否则返回 False
- string.isdecimal()
如果 string 只包含十进制数字则返回 True 否则返回 False.
- string.isdigit()
如果 string 只包含数字则返回 True 否则返回 False.
- string.islower()
如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False
- string.isnumeric()
如果 string 中只包含数字字符,则返回True,否则返回 False
- string.isspace()
如果 string 中只包含空格,则返回True,否则返回 False.
- string.istitle()
如果 string 是标题化的(见 title())则返回 True,否则返回 False
- string.isupper()
如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False
- string.join(seq)
Merges (concatenates)以 string 作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
- string.ljust(width)
返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
- string.lower()
转换 string 中所有大写字符为小写.
- string.lstrip()
截掉 string 左边的空格
- string.partition(str)
有点像 find()和 split()的结合体,从 str 出现的第一个位置起,把 字 符 串 string 分 成 一 个 3 元素的元组(string_pre_str,str,string_post_str),如果 string 中不包含str 则string_pre_str == string.
- string.replace(str1,str2,num=string.count(str1))
把 string 中的str1替换成str2,如果num指定,则替换不超过 num 次.
- string.rfind(str, beg=0,end=len(string))
类似于 find()函数,不过是从右边开始查找.
- string.rindex( str, beg=0,end=len(string))
类似于 index(),不过是从右边开始.
- string.rjust(width)
返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
- string.rpartition(str)
类似于 partition()函数,不过是从右边开始查找.
- string.rstrip()
删除 string 字符串末尾的空格.
- string.split(str="", num=string.count(str))
以 str 为分隔符切片 string,如果 num
有指定值,则仅分隔 num 个子字符串
- string.splitlines(num=string.count(’\n’))
按照行分隔,返回一个包含各行作为元素的列表,如果 num 指定则仅切片 num 个行.
- string.startswith(obj,beg=0,end=len(string))
检查字符串是否是以obj开头,是则返回True,否则返回 False。如果beg和end指定值,则在指定范围内检查.
- string.strip([obj])
在 string 上执行 lstrip()和 rstrip()
- string.swapcase()
翻转 string 中的大小写
- string.title()
返回"标题化"的string,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())
- string.translate(str, del="")
根据 str 给出的表(包含 256 个字符)转换 string 的字符,要过滤掉的字符放到 del 参数中
- string.upper()
转换 string 中的小写字母为大写
- string.zfill(width)
返回长度为 width 的字符串,原字符串 string 右对齐,前面填充0
6.2.6 字符串的独特特性
6.2.6.1 特殊字符串和控制字符
像其他高级语言和脚本语言一样,一个反斜线加一个单一字符可以表示一个特殊字符,通常是一个不可打印的字符,这就是我们上面讨论的特殊字符,如果这些特殊字符是包含在一个原始字符串中的,那么它就失去了转义的功能.
除了通常用的特殊字符,比如换行符(\n),tab符(\t)之外,也可以直接用ASCII码值来标示特殊字符:\000 或者\xXX,分别对应字符的八进制和十六进制 ASCII 码值
跟 C 字符串的另一个不同之处是Python的字符串并不是以 NUL(\000)作为结束符的.NULL跟其他的反斜杠转义字符没什么两样.事实上,一个字符串中不仅可以出现NUL字符,而且还可以出现不止一次,在字符串的任意位置都可以。
Table 6.7 反斜杠开头的转义字符
/X | 八进制 | 十进制 | 十六进制 | 字符 | 说明 |
---|---|---|---|---|---|
\0 | 000 | 0 | 0x00 | NUL | 空字符 Nul |
\a | 007 | 7 | 0x07 | BEL | 响铃字符 |
\b | 010 | 8 | 0x08 | BS | 退格 |
\t | 011 | 9 | 0x09 | HT | 横向制表符 |
\n | 012 | 10 | 0x0A | LF | 换行 |
\v | 013 | 11 | 0x0B | VT | 纵向制表符 |
\f | 014 | 12 | 0x0C | FF | 换页 |
\r | 015 | 13 | 0x0D | CR | 回车 |
\e | 033 | 27 | 0x1B | ESC | 转义 |
\" | 042 | 34 | 0x22 | " | 双引号 |
\’ | 047 | 39 | 0x27 | ’ | 单引号 |
\\ | 134 | 92 | 0x5C | \ | 反斜杠 |
\OOO 八进制值(范围是 000 到 0177)
\xXX x 打头的十六进制值(范围是 0x00 到 0xFF)
\ 连字符,将本行和下一行的内容连接起来.
控制字符的一个作用是用做字符串里面的定界符,在数据库或者web应用中,大多数的可打印字符都是被允许用在数据项里面的,就是说可打印的字符不适合做定界符.
6.2.6.2 三引号
Python 的三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符
三引号的语法是一对连续的单引号或者双引号(通常都是成对的用):
>>> hi = '''hi there'''
>>> hi # repr()
'hi\nthere'
>>> print hi # str()
hi there
6.2.6.3 字符串的不变性
了字符串是一种不可变数据类型,就是说它的值是不能被改变或修改的。这就意味着如果你想修改一个字符串,或者截取一个子串,或者在字符串的末尾连接另一个字符串等等,你必须新建一个字符串。
对像字符串这样的不可变对象,我们探究了它在赋值操作中所为左值的限制,左值必须是一个完整的对象,比如说一个字符串对象,不能是字符串的一部分.对赋值操作的右值没有这个限制.
6.2.7 Unicode
6.2.7.1 术语
Table 6.8 Unicode 术语
名词 | 意思 |
---|---|
ASCII | 美国标准信息交换码 |
BMP | 基本多文种平面(第零平面) |
BOM | 字节顺序标记(标识字节顺序的字符) |
CJK/CJKV | 中文-日文-韩文(和越南语)的缩写 |
Code point | 类似于 ASCII 值,代表 Unicode 字符的值,范围在 range(1114112)或者说0x000000 到 0x10FFFF. |
Octet | 八位二进制数的位组 |
UCS | 通用字符集 |
UCS2 | UCS 的双字节编码方式(见 UTF-16) |
UCS4 | UCS 的四字节编码方式. |
UTF | Unicode 或者 UCS 的转换格式. |
UTF-8 | 八位 UTF 转换格式(无符号字节序列, 长度为一到四个字节) |
UTF-16 | 16 位UTF转换格式(无符号字节序列,通常是 16 位长[两个字节],见 UCS2) |
6.2.7.2 什么是Unicode
ASCII 编码的文件小巧易读,但是存在最多8位限制
Unicode 通过使用一个或多个字节来表示一个字符的方法突破了 ASCII 的限制,可以表示超过 90,000 个字符.
6.2.7.3 如何使用Unicode
为了让Unicode和ASCII码值的字符串看起来尽可能的相像,Python 的字符串从原来的简单数据类型改成了真正的对象。ASCII字符串成了StringType,而Unicode 字符串成了UnicodeType类型.它们的行为是非常相近的。
Python 里面处理 Unicode 字符串跟处理 ASCII 字符串没什么两样。Python把硬编码的字符串叫做字面上的字符串,默认所有字面上的字符串都用ASCII 编码,可以通过在字符串前面加一个’u’前缀的方式声明 Unicode字符串,这个’u’前缀告诉Python后面的字符串要编码成 Unicode字符串。
内建的 str()函数和chr()函数并没有升级成可以处理 Unicode.它们只能处理常规的ASCII编码字符串,如果一个 Unicode 字符串被作作为参数传给了 str()函数,它会首先被转换成ASCII字符串然后在交给 str()函数.如果该Unicode字符串中包含任何不被 ASCII 字符串支持的字符,会导致str()函数报异常.同样地,chr() 0到255作为参数工作
新的内建函数 unicode()和 unichar()可以看成 Unicode 版本的 str()和 chr().Unicode()
函数可以把任何 Python 的数据类型转换成一个 Unicode 字符串,如果是对象,并且该对象定义
了__unicode__()方法,它还可以把该对象转换成相应的 Unicode 字符串
- 程序中出现字符串时一定要加个前缀 u.
- 不要用 str()函数,用 unicode()代替.
- 不要用过时的 string 模块 – 如果传给它的是非 ASCII 字符,它会把一切搞砸。
- 不到必须时不要在你的程序里面编解码 Unicod 字符.只在你要写入文件或数据库或者网络时,才调用 encode()函数;相应地,只在你需要把数据读回来的时候才调用 decode()函数
- Python 标准库里面的绝大部分模块都是兼容 Unicode 的.除了 pickle 模块!pickle 模块只
支持 ASCII 字符串。最好是避免基于文本的 pickle 操作,现在二进制格式已经作为 pickle 的默认格式
python的Unicode支持
- 内建的 unicode()函数
Unicode 的工厂方法,同 Unicode 字符串操作符(u / U)的工作方式很类似,它接受一个string做参数,返回一个 Unicode 字符串.
- 内建的 decode()/encode()方法
decode()和 encode()内建函数接受一个字符串做参数返回该字符串对应的解码后/编码后的字符串.decode()和 encode()都可以应用于常规字符串和Unicode 字符串
- Unicode 类型
Unicode 字符串对象是basestring的子类、用Unicode()工厂方法或直接在字符串前面加一个 u 或者 U 来创建实例.支持Unicode原始字符串,只要在你的字符串前面加一个 ur 或者 UR就可以了.
- Unicode 序数
标准内建函数ord()工作方式相同,最近已经升级到可以支持 Unicode对象了。内建的unichr()函数返回一个对应的 Unicode字符(需要一个32位的值);否则就产生一个 ValueError异常.
- 强制类型转换
混合类型字符串操作需要把普通字符串转换成Unicode 对象.
- 异常
UnicodeError异常是在exceptions模块中定义的,ValueError 的子类.所有关于Unicode编解码的异常都要继承自 UnicodeError.详见 encode()函数.
6.2.7.4 Codecs 是什么?
codec 是 COder/DECoder的首字母组合.它定义了文本跟二进制值的转换方式,跟ASCII那种用一个字节把字符转换成数字的方式不同,Unicode用的是多字节.这导致了 Unicode 支持多种不同的编码方式.比如说 codec 支持的四种耳熟能详的编码方式是:ASCII,ISO
8859-1/Latin-1,UTF-8 和 UTF-16.
最著名的是 UTF-8编码,它也用一个字节来编码 ASCII字符,这让那些必须同时处理 ASCII
码和 Unicode码文本的程序员的工作变得非常轻松,因为 ASCII 字符的 UTF-8 编码跟 ASCII 编码完全相同。
UTF-8 编码可以用1个到4个字节来表示其他语言的字符,CJK/East这样的东亚文字一般都是用3个字节来表示,那些少用的、特殊的、或者历史遗留的字符用 4 个字节来表示
UTF-16 可能是以后大行其道的一种编码格式,它容易读写,因为它把所有的字符都是用单独的一个 16 位字,两个字节来存储的,正因为此,这两个字节的顺序需要定义一下,一般的UTF-16编码文件都需要一个 BOM(Byte OrderMark),或者你显式地定义UTF-16-LE(小端)或者 UTF-16-BE(大端)字节序.
6.2.7.5 编码解码
Unicode 支持多种编码格式,每向一个文件写入字符串的时候,你必须定义一个编码(encoding参数)用于把对应的 Unicode 内容转换成你定义的格式,Python 通过 Unicode字符串的encode()函数解决了这个问题,该函数接受字符串中的字符为参数,输出你指定的编码格式的内容。
6.2.8 字符串相关模块
模块 | 描述 |
---|---|
string | 字符串操作相关函数和工具,比如 Template 类. |
re | 正则表达式:强大的字符串模式匹配模块 |
struct | 字符串和二进制之间的转换 |
c/StringIO | 字符串缓冲对象,操作方法类似于 file 对象. |
base64 | Base 16,32,64 数据编解码 |
codecs | 解码器注册和基类 |
crypt | 进行单方面加密 |
difflib | 找出序列间的不同 |
stringprep | 提供用于 IP 协议的 Unicode 字符串 |
textwrap | 文本打包和填充 |
unicodedata | Unicode 数据库 |
正则表达式(RE)提供了高级的字符串模式匹配方案.通过描述这些模式的语法,你可以像使用“过滤器”一样高效地查找传进来的文本。这些过滤器允许你基于自定义的模式字符串抽取匹配模式、执行查找-替换或分割字符串.
该模块中包含的关键函数有:
- compile() :将一个RE表达式编译成一个可重用的 RE 对象;
- match() :试图从字符串的开始匹配一个模式;
- search() :找出字符串中所有匹配的项;
- sub() : 进行查找替换操作。其中的一些函数返
回匹配到的对象,你可以通过组匹配来访问(如果找到的话)
6.2.9 字符串关键点总结
- 引号分割:单/双引号以及三引号
- 不可分字符类型:字符串是字符存储操作的最基本单位.字符应该视为长度为 1 的字符串.
- 原始字符串
- Python 字符串不是通过 NUL 或者’\0’来结束的
6.3 列表
列表是能保留任意数目的 Python 对象的灵活的容器
列表不仅可以包含Python的标准类型,而且可以用用户定义的对象作为自己的元素
列表可以包含不同类型的对象
列表可以执行 pop,empt,sort,reverse 等操作.
列表也可以添加或者减少元素,还可以跟其他的列表结合或者把一个列表分成几个.
可以对单独一个元素或者多个元素执行insert,update,或者 remove 操作
- 如何创建列表类型数据并给它赋值
列表是由方括号([])来定义的,写一个列表(空的或者有值的都行)然后赋给一个变量
也可以用工厂方法来创建它
- 如何访问列表中的值
列表的切片操作就像字符串中一样;切片操作符([])和索引值或索引值范围一起使用
- 如何更新列表
可以通过在等号的左边指定一个索引或者索引范围的方式来更新一个或几个元素,你也
可以用 append()方法来追加元素到列表中去.
- 如何删除列表中的元素或者列表(本身)
要删除列表中的元素:确切的知道要删除元素的素引可以用 del 语句,否则可以用remove()方法或者通过 pop()方法来删除并从列表中返回一个特定对象.
一般来说,程序员不需要去删除一个列表对象。列表对象出了作用域(比如程序结束,函数调用完成等等)后它会自动被析构,但是如果你想明确的删除一整个列表,你可以用 del 语句
6.3.1 操作符
6.3.1.1 标准类型操作符
比较列表时也是用的内建的cmp()函数,基本的比较逻辑是这样的:两个列表的元素分别比较,直到有一方的元素胜出
6.3.1.2 序列类型操作符
- 切片([] 和[:])
列表的切片操作返回的是一个对象或者是几个对象的集合,而不是像字符串那样,返回一个字符或者一个子串
不仅可以在一个切片操作的结果之上再进行切片,而且还可以改变这个切片的结果
- 成员关系操作( in ,not in)
列表中(同样适用于元组),我们可以检查一个对象是否是一个列表(或者元组)的成员.
- 连接接操作符( + )
连接操作符允许我们把多个列表对象合并在一起。可以用 extend()方法来代替连接操作符把一个列表的内容添加到另一个中去.使用extend()方法比连接操作的一个优点是它实际上是把新列表添加到了原有的列表里面,而不是像连接操作那样新建一个列表
连接操作符并不能实现向列表中添加新元素的操作
- 重复操作符( * )
重复操作符可能更多的应用在字符串类型中,都是只是元素的复制(不是对象的复制)
6.3.1.3 列表解析
列表的特有构建方法–列表解析,结合了列表的方括弧和for循环,在逻辑上描述要创建的列表的内容
>>> [ i * 2 for i in [8, -2, 5] ]
[16, -4, 10]
>>> [ i for i in range(8) if i % 2 == 0 ]
[0, 2, 4, 6]
6.2.3 内建函数
6.2.3.1 标准类型函数
- cmp()
- 对两个列表的元素进行比较.
- 如果比较的元素是同类型的,则比较其值,返回结果.
- 如果两个元素不是同一种类型,则检查它们是否是数字.
- 如果是数字,执行必要的数字强制类型转换,然后比较.
- 如果有一方的元素是数字,则另一方的元素"大"(数字是"最小的")
- 否则,通过类型名字的字母顺序进行比较.
- 如果有一个列表首先到达末尾,则另一个长一点的列表"大".
- 如果我们用尽了两个列表的元素而且所有元素都是相等的,那么结果就是个平局,就是说返回一个 0.
6.2.3.2 序列类型函数
- len()
- max()和min():只含有数字和字符串元素的列表用处更大
- sorted(), reversed()
- enumrate(), zip()
- sum():仅数字型
- list(), tuple()
list()函数和tuple()函数接受可迭代对象(比如另一个序列)作为参数,并通过浅拷贝数据来创建一个新的列表或者元组。虽然是浅拷贝,但是属于新对象。当列表中含有可迭代对象就会体现浅拷贝。
6.2.3.3 列表类型内建函数
Python 中的列表类型有自己的方法(可简单视为特定对象的函数或者过程)
- dir():对象的所有的方法和属性
表 6.11 | 列表类型内建函数 |
---|---|
list.append(obj) | 向列表中添加一个对象 obj |
list.count(obj) | 返回一个对象 obj 在列表中出现的次数 |
list.extend(seq) | 把序列seq(任意可迭代对象)的内容添加到列表中 |
list.index(obj, i=0, j=len(list)) | 返回 list[k] == obj的k值,并且k的范围在[i,j];否则引发 ValueError 异常 |
list.insert(index, obj) | 在索引量为 index 的位置插入对象 obj. |
list.pop(index=-1) | 删除并返回指定位置的对象,默认是最后一个对象 |
list.remove(obj) | 从列表中删除对象 obj |
list.reverse() | 原地翻转列表 |
list.sort(func=None,key=None, reverse=False) | 以指定的方式排序列表中的成员,如果 func 和 key 参数指定,则按照指定的方式比较各个元素,如果 reverse 标志被置为True,则列表以反序排列 |
6.3 元组
元组是一种不可变类型
处理一组对象时,这个组默认是元组类型
>>> a = 'sd', 'sdw'
>>> a
('sd', 'sdw')
- 如何创建一个元组并给它赋值
- 空元组:()
- 单个元素:(s,)逗号不可缺少,因为圆括号被重载用作分组操作符。由圆括号包裹的一个一元素首先被作为分组操作
- tuple(‘bar’) = (‘b’, ‘a’, ‘r’)
- 如何访问元组中的值:切片
- 如何更新元组
元组也是不可变类型,不能更新或者改变元组的元素,可以通过现有元组的片段再构造一个新元组
- 如何移除一个元组的元素以及元组本身
删除一个单独的元组元素是不可能的(可以采用更新方式‘丢弃’一个片段)
要显示地删除一整个元组,只要用del语句减少对象引用计数
6.3.1 元组操作符和内建函数
6.3.1.1 标准类型操作符,序列类型操作符和内建函数
- 比较: 支持 >, <, ==
- 创建: t = ()
- 重复: t = t * 2
- 连接: t = t1 + t2
- 成员关系: in
- 切片: []
- 内建函数:list(), str(), max(), min(), len()
6.17.2 元组类型操作符和内建函数,内建方法
像列表一样 元组也没有它自己专用的运算符和内建函数.
列表方法都跟列表对象的可变性有关,比如说排序,替换,添加等等,因为元组是不可变的,所以这些操作对元组来说就是多余的,这些方法没有被实现
6.3.2 元组的特殊性
6.3.2.1 元组的不可变性
在三个标准不可变类型里面–数字,字符串和元组字符串–元组是受到影响最大的。对数字和字符串是标量类型,当它们代表的值改变时,这种结果是有意义的。而元组是容器对象,很多时候你想改变的只是这个容器中的一个或者多个元素,但这是不被允许的。
不可变并不是坏事,比如我们把数据传给一个不了解的 API 时,可以确保我们的数据不会被修改。同样地,如果我们操作从一个函数返回的元组,可以通过内建 list()函数把它转换成一个列表.
6.3.2.2 元组“不可变”的灵活性
- 支持连接操作(类似字符串创建新对象)
- 支持重复操作
- 支持list()转换
- 允许修改元组元素中的可变对象
- 虽然元组对象本身是不可变的,但这并不意味着元组包含的可变对象也不可变了。
6.3.2.3 元组的默认集合类型
所有的多对象的,逗号分隔的,没有明确用符号定义的,比如说像用方括号表示列表和用圆括号表示元组一样,等等这些集合默认的类型都是元组
6.4 序列类型的相关模块
模块 | 内容 |
---|---|
数组 | 一种受限制的可变序列类型,要求所有的元素必须都是相同的类型。 |
copy | 提供浅拷贝和深拷贝的能力(详见 6.20) |
operator | 包含函数调用形式的序列操作符,比如 operator.concat(m,n)就相当于连接操作(m+n)。 |
re | Perl 风格的正则表达式查找(和匹配); |
StringIO/cStringIO | 把长字符串作为文件来操作,比如read(),seek()函数等,C 版的更快一些,但是它不能被继承. |
Textwrap | 用作包裹/填充文本的函数,也有一个类 |
types | 包含 Python 支持的所有类型 |
collections | 高性能容器数据类型 |
6.5 python对象拷贝
- 赋值
对象赋值实际上是简单的对象引用。也就是说当你创建一个对象,然后把它赋给另一个变量的时候,Python 并没有拷贝这个对象,而是拷贝这个对象的引用
- 浅拷贝
对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不是.
序列类型对象的浅拷贝是默认类型拷贝,并可以以下几种方式实施:
(1)完全切片操作[:],
(2)利用工厂函数,比如 list(),dict()等,
(3)使用 copy 模块的 copy 函数.
- 深拷贝
一个完全拷贝或者说深拷贝–创建一个新的容器对象,包含原有对象元素(引用)全新拷贝的引用: copy.deepcopy()函数
- 几点关于拷贝操作的警告:
- 第一,非容器类型(比如数字,字符串和其他"原子"类型的对象,像代码,类型和xrange对象等)没有被拷贝一说,浅拷贝是用完全切片操作来完成的
- 第二,如果元组变量只包含原子类型对象,对它的深拷贝将不会进行.如果我们把账户信息改成元组类型,那么即便按我们的要求使用深拷贝操作也只能得到一个浅拷贝
6.6 序列类型小结
字符串是最常用的数据载体,无论是用于给用户显示,存贮到硬盘,通过网络传输,还是作为一个多源信息的容器.
列表和元组提供了容器存储能力,允许简单的操作和访问多个对象,无论它们是Python的对象还是用户自定义的对象.单一元素或一组元素可以通过持续有序地索引偏移进行切片操作来访问.