杂谈
元组 是python开发中经常被忽略的一种类型,特别是初学者会疑惑:明明有更好用的 列表 不用,要它有甚用?
这就导致很多初学者就像公司领导层感觉手下一名 牛马 无大用,大手一挥,弃之不用给优化了。
这 “牛马” 真的毫无用处吗?难道 列表 这个 “同事” 真就这么好用,元组 就应该被 辞退 吗?
错了,我们都错了,其实 元组 它一直在默默付出,在其 “岗位” 上发光发热!
一、元组与列表的不同
类型说明 | 元组 | 列表 |
可变性 | 不可变 | 可变,增删改都行 |
初始化 | () | [] |
内存空间 | 较少 | 较多 |
安全性 | 更安全 | 安全 |
可哈希性 | 可以 | 不可以 |
其实 元组和列表 确实太像了,导致在使用它们的时候,也经常分不清楚彼此,但它们确实存在不同,且不同中最重要就是 元组不可变。
二、元组的不可代替性
元组 是不可代替的,它虽然与 列表 存在大量的相似性,但谁也不能弃之不用,它的优势是 列表无法替代的。
2.1 内存空间占用更小
关于这一点,其实最直观的就是看代码,请各位看官往下瞅:
import sys
list_data = [i for i in range(1000000)]
tuple_data = tuple(list_data)
# 列表占用 8448728
print(f'列表占用 {sys.getsizeof(list_data)}')
# 元组占用 8000040
print(f'元组占用 {sys.getsizeof(tuple_data)}')代码测试中一目了然,元组 的内存占用更小,主要原因是 列表 需要动态修改,因此会预留空间来完成修改操作。
2.2 更安全
元组 是不可变的,它的数据一旦定型,那么就无法进行修改;而 列表 能够动态修改,因此你获取到的 列表 数据可能已经发生了改变。
话虽然说的这么明白了,但我想很多初学者还是不明白:这什么场景会遇到呢?
确实,光看知识点根本想不出到底什么时候会有安全性问题,还好小卡在日常开发中确实遇到过类似的问题,今天分享出来。
不安全的场景
小卡和另外一位同事在协同开发一个系统时,同事需要将一个 数据序列 发送给我,以便分析使用。
在最开始的时候,我们使用 列表 传输,由于开发初期数据量少,我便在接收后便将这个 数据序列 用 append() 将随机数补充到 列表 中,以便代码测试使用:
import random
def analyse(data: list = []):
# 补充数据,以便测试使用
for i in range(100):
data.append(random.uniform(-1, 1))
...后来系统正式上线后,由于开发时间过长,已经忘记这个事情,导致传递过来的 真实数据 被插入异常的 随机数,导致分析经常发生错误。
这就是 列表 带来的安全问题,后来我和同事后续就以 元组 为数据类型进行传递,并且添加 DEBUG 全局变量以进行测试:
import random
DEBUG = True
def analyse(data: tuple = ()):
# 补充数据,以便测试使用
if DEBUG:
data = tuple([random.uniform(-1, 1) for _ in range(100)])
...2.3 可哈希
关于可哈希这一点很多初学者可能犯迷糊,什么叫 可哈希?
其实 可哈希 很好理解,就是能够生成一个 唯一确定 的值。
更通俗的例子是 字典的键 就是可生成为哈希值,能成为字典的键,即为 可哈希。
tuple_key = (1, 2)
list_key = [2, 3]
# {(1, 2): 1}
data_dict1 = {
tuple_key: 1
}
# 报错:TypeError: unhashable type: 'list'
data_dict2 = {
list_key: 1
}2.4 函数/方法返回多个值
这个或许是 元组 最常用的场景了,且无法被其他类型可替代。
def test():
return 1, 2, 3
a, b, c = test()
# a: 1 b: 2 c: 3
print(f'a: {a} b: {b} c: {c}')一个函数/方法想要返回多个返回值,只要依次用 英文逗号 隔开即可,而这就是应用了 元组,因此如何你的程序运用到这个方式,绝对离不开 元组 的支持。
三、 总结
元组 绝对是所有基础类型中最容易被 忽视 的那一个,虽然它的同事 列表 因其强大的能力被开发者所喜爱,但因为 元组,程序才能更加健全!
