目录
介绍Python中内置的基本数据类型,包括数字类型及浮点计算的问题、序列类型(range
、list
、tuple
、str
、bytes
、bytearray
)、容器类型(frozenset
、set
)、映射类型(dict
)和枚举类型(Enum
)。
主要内置类型继承关系
下图展示了python主要内置类型的继承关系。int
是数字类型,bool
继承自int。非数字类型主要包括 Sequence
、Set
、Mapping
三大类,这三类数据类型中,MutableXXX
的子类是可变类型,即该类型对象可以被修改,而其他子类的对象为只读,不能被修改。
数字类型
内置三种基本数字类型: 整数, 浮点数 和 复数。标准库还包含附加的数字类型:分数、Decimal。
具体参考官方文档:https://docs.python.org/zh-cn/3/library/stdtypes.html#numeric-types-int-float-complex
这里重点记录一下 浮点计算 需要注意的问题和解决方案。
浮点计算的问题
关于浮点数问题的详细介绍可参考: 浮点算术:争议和限制
举个例子:
>>> 0.1 + 0.1 + 0.1 == 0.3
False
对 0.1 进行舍入之后再计算:
>>> round(0.1, 1)
0.1
>>> round(0.1, 1) + round(0.1, 1) + round(0.1, 1) == 0.3
False
>>> round(0.1, 1) + round(0.1, 1) + round(0.1, 1)
0.30000000000000004
>>> round(0.1 + 0.1 + 0.1, 1) == 0.3
True
另外,python 3 中的 round()
方法已经不再像 python 2 那样是“四舍五入”,而是“四舍六入五成双”,即:
- 5后不为0时,舍5进1
- 5后为0时,看5前面的数字,奇进偶不进
>>> for x in range(10):
... print('round(%d.5): ' %x, round(x+0.5))
...
round(0.5): 0
round(1.5): 2
round(2.5): 2
round(3.5): 4
round(4.5): 4
round(5.5): 6
round(6.5): 6
round(7.5): 8
round(8.5): 8
round(9.5): 10
>>> for x in range(10):
... print('round(%d.51): ' %x, round(x+0.51))
...
round(0.51): 1
round(1.51): 2
round(2.51): 3
round(3.51): 4
round(4.51): 5
round(5.51): 6
round(6.51): 7
round(7.51): 8
round(8.51): 9
round(9.51): 10
使用 Decimal 类型
如果要进行精确计算,并且要实现 “四舍五入”,就需要使用 Decimal
类型了。下面代码演示了 Decimal
的基本用法,详细说明参考:十进制定点和浮点运算
from decimal import Decimal as D, InvalidOperation
from decimal import DefaultContext, ROUND_HALF_UP, setcontext
# Set applicationwide defaults
# for all threads about to be launched
DefaultContext.prec = 10 # 10位精度(有效数字,默认值是28)
DefaultContext.rounding = ROUND_HALF_UP # 舍入模式为四舍五入(默认值是 ROUND_HALF_EVEN)
setcontext(DefaultContext)
# 小数位数
ZERODIGITS = D('1')
TWODIGITS = D('0.01')
FOURDIGITS = D('0.0001')
def calc(x, op='+', y=0):
# 计算过程保留4位小数
d1 = D(x).quantize(FOURDIGITS)
d2 = D(y).quantize(FOURDIGITS)
operates = {
'+': lambda a, b: a + b,
'-': lambda a, b: a - b,
'*': lambda a, b: a * b,
'/': lambda a, b: a / b,
}
return operates[op](d1, d2)
print('-' * 40)
print(calc(0.1, '+', 1/3))
print(calc(1/3, '-', 1/7))
print(calc(100000.1, '*', 3))
# 精度超限(因计算过程保留4位小数,此处有效数字达到11位)
try:
print(calc(1000000.1, '*', 3))
except InvalidOperation as e:
print(repr(e))
print(calc(0.2, '/', 3))
print(calc(0.2, '/', 3).quantize(FOURDIGITS))
print('-' * 40)
for x in range(6):
# 结果保留2位小数
print(calc(x + 0.5).quantize(TWODIGITS))
print('-' * 40)
for x in range(6):
# 结果保留0位小数
print(calc(x + 0.5).quantize(ZERODIGITS))
运行结果:
----------------------------------------
0.4333
0.1904
300000.3000
InvalidOperation([<class 'decimal.InvalidOperation'>])
0.06666666667
0.0667
----------------------------------------
0.50
1.50
2.50
3.50
4.50
5.50
----------------------------------------
1
2
3
4
5
6
序列类型
序列类型 即 Sequence
的子类。主要包括 range
、list
、tuple
、str
、bytes
、bytearray
。
所有 Sequence 类型都支持的操作
在表格中,s 和 t 是具有相同类型的序列,n, i, j 和 k 是整数而 x 是任何满足 s 所规定的类型和值限制的任意对象。
运算 | 结果 | 备注 |
---|---|---|
x in s | 如果 s 中的某项等于 x 则结果为 True ,否则为 False | |
x not in s | 如果 s 中的某项等于 x 则结果为 False ,否则为 True | |
s + t | s 与 t 相拼接 |
range 除外
拼接不可变序列总是会生成新的对象 |
s * n 或 n * s | 相当于 s 与自身进行 n 次拼接 |
range 除外
序列中的项不会被拷贝,它们会被多次引用 |
s[i] | s 的第 i 项,起始为 0 | |
s[i:j] | s 从 i 到 j 的切片 | |
s[i:j:k] | s 从 i 到 j 步长为 k 的切片 | |
len(s) | s 的长度 | |
min(s) | s 的最小项 | |
max(s) | s 的最大项 | |
s.index(x[, i[, j]]) | x 在 s 中首次出现项的索引号(索引号在 i 或其后且在 j 之前) |
range 不支持参数 i 和 j
|
s.count(x) | x 在 s 中出现的总次数 |
拼接不可变序列总是会生成新的对象。 这意味着通过重复拼接来构建序列的运行时开销将会基于序列总长度的乘方。想要获得线性的运行时开销,你必须改用下列替代方案之一:
- 如果拼接
str
对象,你可以构建一个列表并在最后使用str.join()
或是写入一个io.StringIO
实例并在结束时获取它的值- 如果拼接
bytes
对象,你可以类似地使用bytes.join()
或io.BytesIO
,或者你也可以使用bytearray
对象进行原地拼接。bytearray
对象是可变的,并且具有高效的重分配机制- 如果拼接
tuple
对象,请改为扩展list
类- 对于其它类型,请查看相应的文档
所有 MutableSequence 类型都支持的操作
表格中的 s 是可变序列类型的实例,t 是任意 Iterable
对象,而 x 是符合对 s 所规定类型与值限制的任何对象。
运算 | 结果 | 备注 |
---|---|---|
s[i] = x | 将 s 的第 i 项替换为 x | |
s[i:j] = t | 将 s 从 i 到 j 的切片替换为可迭代对象 t 的内容 | |
del s[i:j] | 等同于 s[i:j] = [] | |
s[i:j:k] = t | 将 s[i:j:k] 的元素替换为 t 的元素 | |
s.append(x) | 将 x 添加到序列的末尾 (等同于 s[len(s):len(s)] = [x]) | |
s.clear() | 从 s 中移除所有项 (等同于 del s[:]) | |
s.copy() | 创建 s 的浅拷贝 (等同于 s[:]) |
浅拷贝 指的是重新分配一块内存,创建一个新的对象,
但里面的元素是原对象中各个子对象的引用。 |
s.extend(t) 或 s += t | 用 t 的内容扩展 s (基本上等同于 s[len(s):len(s)] = t) | |
s *= n | 使用 s 的内容重复 n 次来对其进行更新 |
序列中的项不会被拷贝,它们会被多次引用
|
s.insert(i, x) | 在由 i 给出的索引位置将 x 插入 s (等同于 s[i:i] = [x]) | |
s.pop() 或 s.pop(i) | 提取在 i 位置上的项,并将其从 s 中移除 | |
s.remove(x) | 删除 s 中第一个 s[i] 等于 x 的项目。 | |
s.reverse() | 就地将列表中的元素逆序。 |
范围(range)
range
类型表示 不可变 的数字序列,通常用于在 for 循环中循环指定的次数。以下是 range
的构造函数:
class range(stop)
class range(start, stop[, step])
>>> for x in range(10,15):
... print(x)
...
10
11
12
13
14
>>> for x in range(5,15,3):
... print(x)
...
5
8
11
14
>>>
元组(tuple)与列表(list)
tuple
与 list
是一对性质相似的类型。区别在于 tuple
是 不可变序列,而 list
是 可变序列。
元组
tuple
的构造函数为:
class tuple([iterable])
可以用多种方式构建元组:
- 使用一对圆括号来表示空元组: ()
- 使用一个后缀的逗号来表示单元组: a, 或 (a,)
- 使用以逗号分隔的多个项: a, b, c or (a, b, c)
- 使用内置的 tuple(): tuple() 或 tuple(iterable)
>>> t = tuple(range(5))
>>> t
(0, 1, 2, 3, 4)
>>> t = 10, 20, 30 # 元组打包
>>> t
(10, 20, 30)
>>> a, b, c = t # 序列解包,可以是其他序列类型
>>> a
10
>>> b
20
>>> c
30
>>> x, y, z = 1, 2, 3 # 多重赋值,其实只是元组打包和序列解包的组合
>>> x
1
>>> y
2
>>> z
3
列表
list
的构造函数为:
class list([iterable])
可以用多种方式构建列表:
- 使用一对方括号来表示空列表: []
- 使用方括号,其中的项以逗号分隔: [a], [a, b, c]
- 使用列表推导式: [x for x in iterable]
- 使用类型的构造器: list() 或 list(iterable)
>>> [x for x in (10,15,20) if x % 10 == 0]
[10, 20]
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
利用列表推导式实现矩阵转置:
>>> matrix = [
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12],
... ]
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
以上代码等价于:
>>> lst = []
>>> for i in range(4):
... newr = []
... for r in matrix:
... newr.append(r[i])
... lst.append(newr)
...
>>> lst
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
list
除了支持前面提到的所有 Sequence
及 MutableSequence
类型的操作,还额外提供 sort()
方法,此方法会对列表进行原地排序。insert()
、remove()
、sort()
等方法只修改列表,不输出返回值——返回的默认值为 None
。
虽然 tuple
是不可变序列, list
是可变序列,但是 tuple
的元素可以是 list
(list
的元素也可以是 tuple
),也就是说,当 tuple
的元素是可变类型时,其元素仍然是可以被修改的。
>>> t = (list(range(3)), [], ['hello'])
>>> t[1].extend([7,8,9])
>>> t
([0, 1, 2], [7, 8, 9], ['hello'])
>>> t[0].pop()
2
>>> t
([0, 1], [7, 8, 9], ['hello'])
tuple
和 list
中的元素可以是不同类型,例如:
>>> t = (10, 'cheese', [3,4])
>>> t
(10, 'cheese', [3, 4])
列表排序
1. 使用 sorted()
函数,不改变序列本身
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> sorted(basket)
['apple', 'apple', 'banana', 'orange', 'orange', 'pear']
>>> basket
['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
2. 使用 list.sort()
方法,列表自身被排序
>>> basket.sort()
>>> basket
['apple', 'apple', 'banana', 'orange', 'orange', 'pear']
>>> basket.sort(key=lambda a: len(a), reverse=True) # 通过key传入一个用于计算排序值的函数
>>> basket
['banana', 'orange', 'orange', 'apple', 'apple', 'pear']
字符串(str)与字节串(bytes、bytearray)
str
与 bytes
、bytearray
有许多相似之处,但需要记住,str
是文本序列,而 bytes
和 bytearray
是二进制序列,因此字节串对象中的元素其实是 0 到 255 的整数。str
和 bytes
是 不可变序列,bytearray
是 可变序列。
-
在 Python 中处理文本数据是使用
str
对象,也称为 字符串。 字符串是由 Unicode 码位 构成的不可变序列。之前提到过,字符串的字面值可以用'
、"
、'''
或"""
表示。也提到过字符串变量和字符串字面值的区别。 -
表示
bytes
字面值的语法与字符串字面值的大致相同,只是添加了一个 b 前缀。另外,bytes
字面值中只允许 ASCII 字符(无论源代码声明的编码为何)。 任何超出 127 的二进制值必须使用相应的转义序列形式加入bytes
字面值。
>>> b'This is a ByteString.'
b'This is a ByteString.'
>>> b'中文'
File "<stdin>", line 1
b'中文'
^
SyntaxError: bytes can only contain ASCII literal characters.
>>> b'\xe4\xb8\xad\xe6\x96\x87'
b'\xe4\xb8\xad\xe6\x96\x87'
官方文档关于字符串与字节串字面值的详细说明看这里:https://docs.python.org/zh-cn/3/reference/lexical_analysis.html#strings 。
str
和bytes
都可以使用 r 前缀来禁用转义序列处理,例如:
>>> print('C:\some\name') # here \n means newline!
C:\some
ame
>>> print(r'C:\some\name') # note the r before the quote
C:\some\name
>>> print('\u4e2d\u6587')
中文
>>> print(r'\u4e2d\u6587')
\u4e2d\u6587
>>> len(b'a\nb')
3
>>> len(rb'a\nb')
4
bytearray
对象是bytes
对象的可变对应物。因为字面值是常量值的表示法,所以bytearray
没有专属的字面值语法,它们总是通过调用构造函数来创建。
字符串
str
的构造函数为:
class str(object=‘’)
class str(object=b’', encoding=‘utf-8’, errors=‘strict’)
当参数 encoding 和 errors 都没有时,调用的是第一个构造函数,返回 type(object).__str__(object)
,如果对象没有 __str__()
方法,则返回 repr(object)
的值。
>>> str(t)
"([0, 1], [7, 8, 9], ['hello'])"
>>> class A:
... pass
...
>>> myclass = A()
>>> str(myclass)
'<__main__.A object at 0x000001C3E90009D0>'
>>> type(myclass).__str__(myclass)
'<__main__.A object at 0x000001C3E90009D0>'
>>> from math import ceil
>>> str(ceil)
'<built-in function ceil>'
>>> str(b'\xe4\xb8\xad\xe6\x96\x87')
"b'\\xe4\\xb8\\xad\\xe6\\x96\\x87'"
当参数 encoding 和 errors 至少传入一个时,调用的是第二个构造函数,此时 object 应该是一个 bytes
或 bytearray
对象,等价于bytes.decode(encoding, errors)
。
>>> str(b'\xe4\xb8\xad\xe6\x96\x87', encoding='utf-8')
'中文'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'
字符串支持所有不可变序列的操作。同时还提供了许多额外的方法。这里对常见的字符串操作和方法做一些说明。
字符串拼接
(1) 字面值特有的拼接方式:
>>> s = ('This is a long long long' ' ... '
... 'sentense. ')
>>> s
'This is a long long long ... sentense. '
(2) 使用 +
进行拼接(适用于字符串变量和字面值):
>>> s1 = 'Hello!'
>>> s2 = 'World!'
>>> s3 = s1 + ' ' + s2
>>> s3
'Hello! World!'
(3) 使用 *
进行重复拼接(适用于字符串变量和字面值):
>>> s1 = 'hello~' * 5
>>> s1
'hello~hello~hello~hello~hello~'
(4) 使用 str.join()
进行拼接(适用于字符串变量和字面值):
>>> '--'.join('ABCD')
'A--B--C--D'
>>> '.'.join(['www','somesite','com'])
'www.somesite.com'
>>> ''.join(['aa','bb','cc','dd'])
'aabbccdd'
字符串索引与切片
字符串索引与切片,即字符序列索引与切片,与其他序列的索引与切片逻辑是一致的。
字符串支持 索引 (下标访问),第一个字符的索引是 0。索引还支持负数,用负数索引时,从右边开始计数。-0 和 0 一样,因此,负数索引从 -1 开始。
>>> s = 'Python世界'
>>> for i in range(len(s)):
... print(str(i) + ':' + s[i])
...
0:P
1:y
2:t
3:h
4:o
5:n
6:世
7:界
>>> for i in reversed(range(- len(s), 0)):
... print(str(i) + ':' + s[i])
...
-1:界
-2:世
-3:n
-4:o
-5:h
-6:t
-7:y
-8:P
索引可以提取单个字符,切片 则提取子字符串:
>>> print(s[3:7])
hon世
>>> print(s[-6:-2])
thon
省略开始索引时,默认值为 0;省略结束索引时,默认为到字符串的结尾。
注意,输出结果包含切片开始,但不包含切片结束。因此,s[:i] + s[i:] 总是等于 s
。
还可以这样理解切片,索引指向的是字符 之间 ,第一个字符的左侧标为 0,最后一个字符的右侧标为 n ,n 是字符串长度。例如:
+---+---+---+---+---+---+----+----+
| P | y | t | h | o | n | 世 | 界 |
+---+---+---+---+---+---+----+----+
0 1 2 3 4 5 6 7 8
-8 -7 -6 -5 -4 -3 -2 -1
对于使用非负索引的切片,如果两个索引都不越界,切片长度就是起止索引之差。例如, s[3:7]
的长度是 4。
索引越界会报错:
>>> s[40] # the string only has 8 characters
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
但是,切片会自动处理越界索引:
>>> s[4:40]
'on世界'
>>> s[40:]
''
字符串查找
str.count(sub[, start[, end]])
返回子字符串 sub 在 [start, end] 范围内非重叠出现的次数。 可选参数 start 与 end 会被解读为切片表示法。
>>> s = 'Type "help", "copyright", "credits" or "license" for more information.'
>>> s.count('or')
4
str.find(sub[, start[, end]])
返回子字符串 sub 在 s[start : end] 切片内被找到的最小索引。 可选参数 start 与 end 会被解读为切片表示法。 如果 sub 未被找到则返回 -1。
str.index(sub[, start[, end]])
类似于 find()
,但在找不到子字符串时会引发 ValueError
。
类似的还有 str.rfind(sub[, start[, end]])
和 str.rindex(sub[, start[, end]])
>>> s = 'Type "help", "copyright", "credits" or "license" for more information.'
>>> s.find('or')
36
>>> s.rfind('or')
61
使用正则表达式:
>>> import re
>>> s = 'Type "help", "copyright", "credits" or "license" for more information.'
>>> re.search('\\"[a-z]+\\"', s)
<re.Match object; span=(5, 11), match='"help"'>
>>> re.match('[a-z]+', s, re.IGNORECASE)
<re.Match object; span=(0, 4), match='Type'>
>>> m = re.fullmatch(r'(\"?[a-z]+\"?,?( |\.))+', s, re.IGNORECASE)
>>> if m:
... print(m.group())
...
Type "help", "copyright", "credits" or "license" for more information.
>>> re.findall(r'\"\w*\"', s)
['"help"', '"copyright"', '"credits"', '"license"']
字符串拆分
str.partition(sep)
在 sep 首次出现的位置拆分字符串,返回一个 3 元组,其中包含分隔符之前的部分、分隔符本身,以及分隔符之后的部分。 如果分隔符未找到,则返回的 3 元组中包含字符本身以及两个空字符串。
类似的还有 str.rpartition(sep)
。
>>> s.partition('or')
('Type "help", "copyright", "credits" ', 'or', ' "license" for more information.')
>>> s.rpartition('or')
('Type "help", "copyright", "credits" or "license" for more inf', 'or', 'mation.')
str.split(sep=None, maxsplit=-1)
返回一个由字符串内单词组成的列表,使用 sep 作为分隔字符串。 如果给出了 maxsplit,则最多进行 maxsplit 次拆分。如果 sep 未指定或为 None
,则连续的空格会被视为单个分隔符。
类似的还有 str.rsplit(sep=None, maxsplit=-1)
。
>>> s.split('or')
['Type "help", "copyright", "credits" ', ' "license" f', ' m', 'e inf', 'mation.']
>>> s.rsplit(maxsplit=2)
['Type "help", "copyright", "credits" or "license" for', 'more', 'information.']
使用正则表达式拆分字符串:
>>> import re
>>> s = 'Type "help", "copyright", "credits" or "license" for more information.'
>>> re.split(r'\"?,? \"?', s)
['Type', 'help', 'copyright', 'credits', 'or', 'license', 'for', 'more', 'information.']
字符串格式化
(1) printf 风格的字符串格式化
字符串具有一种特殊的内置操作:使用
%
(取模) 运算符。 这也被称为字符串的 格式化 或 插值 运算符。 对于 format%
values (其中 format 为一个字符串),在 format 中的%
转换标记符将被替换为零个或多个 values 条目。 其效果类似于在 C 语言中使用sprintf()
。
>>> print('Hello %s.' % 'python')
Hello python.
>>> print('%d-%02d-%02d' % (2022, 5, 2))
2022-05-02
>>> print('Value: %010.4f%%' % 20.13)
Value: 00020.1300%
>>> import decimal
>>> v = decimal.Decimal('12.34567')
>>> print('Value: %10.4f%%' % v)
Value: 12.3457%
>>> print('ASCII: %#x' % b'A'[0])
ASCII: 0x41
>>> print('%(language)s has %(number)03d quote types.' %
... {'language': "Python", "number": 2})
Python has 002 quote types.
(2) str.format() 方法
str.format(*args, **kwargs)
执行字符串格式化操作。 调用此方法的字符串可以包含字符串字面值或者以花括号 {}
括起来的替换域。 每个替换域可以包含一个位置参数的数字索引,或者一个关键字参数的名称。 返回的字符串副本中每个替换域都会被替换为对应参数的字符串值。
>>> print("Hello {}".format('python'))
Hello python
>>> print('{}-{:02d}-{:02d}'.format(2022, 5, 2))
2022-05-02
>>> print('Value: {:010.4f}%'.format(20.13))
Value: 00020.1300%
>>> print('Value: {{{:10.4f}%}}'.format(20.13))
Value: { 20.1300%}
>>> import decimal
>>> v = decimal.Decimal('12.34567')
>>> print('Value: {:10.4f}%'.format(v))
Value: 12.3457%
>>> print('ASCII: {:#x}'.format(b'A'[0]))
ASCII: 0x41
>>> print('Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W'))
Coordinates: 37.24N, -115.81W
>>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'}
>>> print('Coordinates: {latitude}, {longitude}'.format(**coord))
Coordinates: 37.24N, -115.81W
(3) 格式字符串字面值
格式字符串字面值 或称 f-string 是标注了 ‘f’ 或 ‘F’ 前缀的字符串字面值。这种字符串可包含替换字段,即以
{}
标注的表达式。其他字符串字面值只是常量,格式字符串字面值则是可在运行时求值的表达式。
>>> lang = 'python'
>>> print(f'Hello {lang!s}.')
Hello python.
>>> year = 2022
>>> month = 5
>>> day = 2
>>> print(f'{year}-{month:02d}-{day:02d}')
2022-05-02
>>> d = {'year':2022, 'month':5, 'day':2}
>>> print(f'{d["year"]}-{d["month"]:02d}-{d["day"]:02d}')
2022-05-02
>>> width = 10
>>> precision = 6
>>> value = decimal.Decimal("12.34567")
>>> print(f'Value: {value:{width}.{precision}}')
Value: 12.3457
>>> print(f'Value: {value:10.4f}') # 4代表小数位数
Value: 12.3457
>>> print(f'Value: {value:10.4}') # 4代表精度
Value: 12.35
>>> print(f'ASCII: {b"A"[0]:#x}')
ASCII: 0x41
字符串转换为字节串
str.encode(encoding='utf-8', errors='strict')
返回原字符串编码为 bytes
对象的版本。 默认编码为 ‘utf-8’。 可以给出 errors 来设置不同的错误处理方案。 errors 的默认值为 ‘strict’,表示编码错误会引发 UnicodeError
。
>>> s = 'Python世界'
>>> s.encode('utf-8')
b'Python\xe4\xb8\x96\xe7\x95\x8c'
其他字符串方法
详细文档参考:https://docs.python.org/zh-cn/3/library/stdtypes.html#string-methods
- 大小写转换:
str.capitalize()
/str.lower()
/str.upper()
/str.swapcase()
/str.casefold()
- 判断字符串类型:
str.isalnum()
/str.isalpha()
/str.isdecimal()
/str.isdigit()
/str.isnumeric()
/str.isascii()
/str.isprintable()
/str.isspace()
- 字符串填充:
str.ljust(width[, fillchar])
/str.rjust(width[, fillchar])
/str.center(width[, fillchar])
- 移除字符:
str.lstrip([chars])
/str.rstrip([chars])
/str.strip([chars])
- 前缀后缀:
str.startswith(prefix[, start[, end]])
/str.endswith(suffix[, start[, end]])
/str.removeprefix(prefix, /)
/str.removesuffix(suffix, /)
- 左填充’0’:
str.zfill(width)
- 字符串替换:
str.replace(old, new[, count])
str.lstrip()
和 str.removeprefix()
的区别:
>>> 'Hello python.'.lstrip('Helo')
' python.'
>>> 'Hello python.'.removeprefix('Hello')
' python.'
>>> 'Arthur: three!'.lstrip('Arthur: ')
'ee!'
>>> 'Arthur: three!'.removeprefix('Arthur: ')
'three!'
str.isnumeric()
、str.isdigit()
、str.isdecimal()
的区别:
>>> '52'.isnumeric()
True
>>> '52'.isdigit()
True
>>> '52'.isdecimal()
True
>>> '52'.isnumeric()
True
>>> '52'.isdigit()
True
>>> '52'.isdecimal()
True
>>> '⒌⒉'.isnumeric()
True
>>> '⒌⒉'.isdigit()
True
>>> '⒌⒉'.isdecimal()
False
>>> '⑸⑵'.isnumeric()
True
>>> '⑸⑵'.isdigit()
True
>>> '⑸⑵'.isdecimal()
False
>>> '五十二'.isnumeric()
True
>>> '五十二'.isdigit()
False
>>> '五十二'.isdecimal()
False
>>> '㈤㈡'.isnumeric()
True
>>> '㈤㈡'.isdigit()
False
>>> '㈤㈡'.isdecimal()
False
>>> 'ⅩⅩⅩⅩⅩⅡ'.isnumeric()
True
>>> 'ⅩⅩⅩⅩⅩⅡ'.isdigit()
False
>>> 'ⅩⅩⅩⅩⅩⅡ'.isdecimal()
False
字节串
前面提到,bytes
字面值的语法与字符串字面值的大致相同,只是添加了一个 b 前缀。
除了字面值形式,bytes
对象还可以通过其他几种方式来创建:
- 指定长度的以零值填充的
bytes
对象:bytes(10)
- 通过由整数组成的可迭代对象:
bytes(range(20))
- 通过缓冲区协议复制现有的二进制数据:
bytes(obj)
bytearray
对象可以通过以下方式创建:
- 创建一个空实例:
bytearray()
- 创建一个指定长度的以零值填充的实例:
bytearray(10)
- 通过由整数组成的可迭代对象:
bytearray(range(20))
- 通过缓冲区协议复制现有的二进制数据:
bytearray(b'Hi!')
十六进制数形式的字符串与 bytes
或 bytearray
对象相互转换:
classmethod fromhex(string)
与 hex([sep[, bytes_per_sep]])
>>> bytes.fromhex('41F0 f1f2')
b'A\xf0\xf1\xf2'
>>> b'A\xf0\xf1\xf2'.hex()
'41f0f1f2'
>>> bytearray.fromhex('41F0 f1f2')
bytearray(b'A\xf0\xf1\xf2')
>>> bytearray(b'\x41\xf0\xf1\xf2').hex('-',2)
'41f0-f1f2'
由于
bytes
对象是由整数构成的序列(类似于元组),因此对于一个bytes
对象 b,b[0] 将为一个整数,而 b[0:1] 将为一个长度为 1 的bytes
对象。 (这与文本字符串不同,索引和切片所产生的将都是一个长度为 1 的字符串)。
总是可以使用 list(b)
将 bytes
或 bytearray
对象转换为一个由整数构成的列表。
>>> b = bytes.fromhex('41F0 f1f2')
>>> list(b)
[65, 240, 241, 242]
>>> list(bytearray(b'\x41\xf0\xf1\xf2'))
[65, 240, 241, 242]
bytes
和 bytearray
支持所有通用的序列操作,bytearray
还支持可变序列的操作。另外,bytes
和 bytearray
还支持很多与 str
中的方法类似的方法,例如 endswith()
、find()
、strip()
等等。具体可参考:bytes 和 bytearray 操作 。bytes
和 bytearray
也都支持 printf风格的格式化。
前面提到,可以用 str.encode()
方法将字符串转换为 bytes
对象。相反的,可以用 decode()
方法将 bytes
或 bytearray
对象转换为字符串。
bytes.decode(encoding='utf-8', errors='strict')
bytearray.decode(encoding='utf-8', errors='strict')
返回从给定 bytes
解码出来的字符串。 默认编码为 ‘utf-8’。 可以给出 errors 来设置不同的错误处理方案。
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode()
'中文'
>>> bytearray([0xe4,0xb8,0xad,0xe6,0x96,0x87]).decode()
'中文'
集合(frozenset、set)
frozenset
与 set
是一对性质相似的类型。区别在于 frozenset
是 不可变类型,而 set
是 可变类型。
集合是由不重复元素组成的无序容器。基本用法包括成员检测、消除重复元素。集合对象支持合集、交集、差集、对称差分等数学运算。
与其他多项集一样,集合也支持
x in set
,len(set)
和for x in set
。 作为一种无序的多项集,集合并不记录元素位置或插入顺序。 相应地,集合不支持索引、切片或其他序列类的操作。
集合可用多种方式来创建:
- 使用花括号内以逗号分隔元素的方式:
{'jack', 'sjoerd'}
- 使用集合推导式:
{c for c in 'abracadabra' if c not in 'abc'}
- 使用类型构造器:
set()
,set('foobar')
,set(['a', 'b', 'foo'])
注意,创建空集合只能用 set(),不能用 {},{} 创建的是空字典
>>> # Demonstrate set operations on unique letters from two words
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b # letters in a but not in b
{'r', 'd', 'b'}
>>> a | b # letters in a or b or both
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b # letters in both a and b
{'a', 'c'}
>>> a ^ b # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}
frozenset
和 set
的方法详见:https://docs.python.org/zh-cn/3/library/stdtypes.html#set-types-set-frozenset
字典(dict)
Mapping
对象会将 hashable 值映射到任意对象。 映射属于可变对象。 目前仅有一种标准映射类型dict
。
- 字典以 关键字 为索引,关键字通常是字符串或数字,也可以是其他任意不可变类型。
- 可以把字典理解为 键值对 的集合,但字典的键必须是唯一的。
- 字典的主要用途是通过关键字存储、提取值。用
del
语句可以删除键值对。用已存在的关键字存储值,与该关键字关联的旧值会被取代。通过不存在的键提取值,则会报错。 - 对字典执行
list(d)
操作,返回该字典中所有键的列表,按插入次序排列(如需排序,请使用sorted(d)
)。 - 检查字典里是否存在某个键,使用关键字
in
。 dict.keys()
,dict.values()
和dict.items()
所返回的对象是 视图对象。 该对象提供字典条目的一个动态视图,这意味着当字典改变时,视图也会相应改变。
以下示例返回的字典均等于 {"one": 1, "two": 2, "three": 3}
:
>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> f = dict({'one': 1, 'three': 3}, two=2)
>>> a == b == c == d == e == f
True
在字典中循环时,用 items() 方法可同时取出键和对应的值:
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
... print(k, v)
...
gallahad the pure
robin the brave
dict
的方法详见:https://docs.python.org/zh-cn/3/library/stdtypes.html#mapping-types-dict
数据结构
建议读一读官方文档这一章节:https://docs.python.org/zh-cn/3/tutorial/datastructures.html
枚举(Enum)
完整文档参考:对枚举的支持
>>> from enum import Enum
>>> class Color(Enum):
... RED = 1
... GREEN = 2
... BLUE = 3
...
>>> print(Color.RED)
Color.RED
成员值可以是
int
、str
等。