# 数据类型概述
# 概述
Python3 中有六个标准的数据类型:
- Number(数字)
- String(字符串)
- List(列表)
- Tuple(元组)
- Set(集合)
- Dictionary(字典)
Python3 的六个标准数据类型中:
- 不可变数据(3 个): Number(数字)、String(字符串)、Tuple(元组);
- 可变数据(3 个): List(列表)、Dictionary(字典)、Set(集合)。
# 字符串
字符串支持转义字符
Python 中字符串使用单引号、双引号或三引号表示,三者意义相同,并没有什么区别。其中,三引号的字符串通常用在多行字符串的场景。
字符串支持索引,切片和遍历等操作
字符串可以用 + 运算符连接在一起,用 * 运算符重复。
字符串不可变,除了+=的所有操作都会创建一个新的字符串
- 在扩充字符串时,若字符串只有当前一个引用,则会尝试在原地扩充buffer大小,而不会重新分配一块内存
- 字符串内置的append和join方法效率较高,append仅为O(1)复杂度。
Python 中字符串的格式化(string.format)常常用在输出、日志的记录等场景。
- % 老版本
- string.format() 新版本
# 字符串前的urbf
字符串前加 u
例:u"我是含有中文字符组成的字符串。"
作用:
后面字符串以 Unicode 格式 进行编码,一般用在中文字符串前面,防止因为源码储存格式问题,导致再次使用时出现乱码。
字符串前加 r
例:r"\n\n\n\n” # 表示一个普通生字符串 \n\n\n\n,而不表示换行了。
作用:
去掉反斜杠的转移机制。
(特殊字符:即那些,反斜杠加上对应字母,表示对应的特殊含义的,比如最常见的”\n”表示换行,”\t”表示Tab等。 )
应用:
常用于正则表达式,对应着re模块。
字符串前加 b
例:
response = b'<h1>Hello World!</h1>' # b' ' 表示这是一个 bytes 对象作用:
b" "前缀表示:后面字符串是bytes 类型。
用处:
网络编程中,服务器和浏览器只认bytes 类型数据。
如:send 函数的参数和 recv 函数的返回值都是 bytes 类型
附:
在 Python3 中,bytes 和 str 的互相转换方式是
str.encode('utf-8') bytes.decode('utf-8')字符串前加 f
import time t0 = time.time() time.sleep(1) name = 'processing' # 以 开头表示在字符串内支持大括号内的python 表达式****f*** print(f'{name} done in {time.time() - t0:.2f} s') # processing done in 1.00 s
# 字典和集合
# dict
字典实现基于哈希表
key要求不可变化
- key首先要求不重复,可变化可能导致重复
- 因此元组可以做key,但列表不可以做key
d = {'b': 1, 'a': 2, 'c': 10}
d_sorted_by_key = sorted(d.items(), key=lambda x: x[0]) # 根据字典键的升序排序
d_sorted_by_value = sorted(d.items(), key=lambda x: x[1]) # 根据字典值的升序排序
d_sorted_by_key
[('a', 2), ('b', 1), ('c', 10)]
d_sorted_by_value
[('b', 1), ('a', 2), ('c', 10)]
# set
- 集合实现基于哈希表
- 集合无序,不支持索引操作
- 集合pop是删除集合中最后一个元素,但集合本身无序,因此无法确定删除的是哪一个元素
s = {3, 4, 2, 1}
sorted(s) # 对集合的元素进行升序排序
[1, 2, 3, 4]
# 字典和集合的相同与区别
相同
都支持创建,访问,增加,删除,更新等操作
实现本质上都是哈希表,经过高度性能优化
- 字典的哈希表中存储了哈希值、键、值三个元素
- 集合的哈希表中只有单一的元素
由于哈希冲突的存在(哈希冲突会大大影响操作速度),因此字典和集合内的哈希表会保证其至少有1/3的剩余空间,当剩余空间小于1/3时就会重新获取更大的内存空间,扩充哈希表,并且重新排放所有元素。
不同
- 字典有序(python37确定的特性),集合无序
- 字典支持索引键,集合不支持索引操作(本质上是一个哈希表,和列表不一样)
# 字典和集合的工作原理
插入操作
首先计算键的哈希值(hash(key)),再和 mask = PyDicMinSize - 1 做与操作,计算这个元素应该插入哈希表的位置 index = hash(key) & mask,若对应位置为空则插入。
若对应位置不空,判断键是否相等,相等则更新,不等则继续寻找空位插入,
寻找空位最简单的方法是线性寻找,即当前位置开始向后逐个寻找。
查找操作
首先根据哈希值,找到其应该处于的位置;
然后,比较哈希表这个位置中元素的哈希值和键,与需要查找的元素是否相等。如果相等,则直接返回;如果不等,则继续查找,直到找到空位或者抛出异常为止。
删除操作
暂时对这个位置的元素,赋于一个特殊的值,等到重新调整哈希表的大小时,再将其删除。
# 列表和元组
# list
- 空列表需要使用40字节来存储信息
- 每次分配存储四个元素的空间来保证增加/删除的时间复杂度为O(1)
l = []
l.__sizeof__() // 空列表的存储空间为40字节
40
l.append(1)
l.__sizeof__()
72 // 加入了元素1之后,列表为其分配了可以存储4个元素的空间 (72 - 40)/8 = 4
l.append(2)
l.__sizeof__()
72 // 由于之前分配了空间,所以加入元素2,列表空间不变
l.append(3)
l.__sizeof__()
72 // 同上
l.append(4)
l.__sizeof__()
72 // 同上
l.append(5)
l.__sizeof__()
104 // 加入元素5之后,列表的空间不足,所以又额外分配了可以存储4个元素的空间
# tuple
与字符串一样,元组的元素不能修改。
元组与字符串类似,可以被索引且下标索引从0开始,-1 为从末尾开始的位置,也可以进行截取。其实,可以把字符串看作一种特殊的元组。
虽然tuple的元素不可改变,但它可以包含可变的对象,比如list列表。
# 列表和元组的异同
相同:
- 都支持负数索引
- 都支持切片操作
- 都可以随意嵌套
- 可以通过list()和tuple()函数相互转换
区别:
列表是动态的,长度大小不固定,可以随意地增加、删减或者改变元素(mutable)。
元组是静态的,长度大小固定,无法增加删减或者改变(immutable)。
列表由于需要维护更多的信息(长度,当前指针等),存储空间略大于元组,性能略差于元组
列表不再使用会触发垃圾回收机制,元组不会(内存空间会被缓存)
# 列表和元组在性能上的差别|python垃圾回收
由于python垃圾回收机制的存在,对于不再使用的变量,python会回收所占用的内存返回给操作系统,但对于静态变量例如元组,如果不被使用且占用空间不大时,python会缓存这部分内存。这样下次再创建同样大小的元组时,python就不会再向操作系统发出请求,去寻求内存,而是直接分配之前缓存的内存空间。
python3 -m timeit -s 'x=[1,2,3,4,5,6]' 'y=x[3]'
10000000 loops, best of 5: 22.2 nsec per loop
python3 -m timeit -s 'x=(1,2,3,4,5,6)' 'y=x[3]'
10000000 loops, best of 5: 21.9 nsec per loop
# 列表和元组如何选择
- 存储数据和数量不变,选用元组更合适
- 存储数据或数量可变,选用列表更合适
# 列表和元组的嵌套
针对可以随意嵌套进行总结:
- 列表嵌套列表:本质是列表,内部列表和外部列表的内容可以进行修改元素,插入,删除元素。也就是二维数组。
- 列表嵌套元组:本质是列表,所以可以对列表中除元组外的其他元素可以修改插入、删除。但元组中的内容不可以改变。
- 元组嵌套列表:本质是元组,元组中的任何元素不能进行改变,但是对于元素本身是列表的情况,可以对列表中的值进行修改。这是因为:列表对象是不变的,只是的列表中的内容进行变化。列表本来就是动态的。
- 元组嵌套元组:本质元组,元组中的元素还是元组。所以这种情况下,不能进行任何改变。也就是不可变的二维数组。