python列表和元组如何选择,让程序更有效率!

1. 元组和列表的区别

列表和元祖都属于可以存储任意数据类型的有序集合,他们的区别用一句话总结就是:
元组和列表的关系就是,元组中元素不可变,列表中是可以变化的

元组一旦创建出来,元组就不能修改元组中所包含的元素,长度大小固定,无法增加删减或者改变,静态序列列表创建之后,可以增加、修改或者删除元素,属于动态序列

>>> lt = [10, 20, 30, 40]
> lt[3] = 40 # 索引从0开始,lt[3] 表示访问列表的第四个元素
> lt
[1, 2, 3, 40]
> tup = (1, 2, 3, 4)
> tup[3] = 40  # 修改元素的时候报错
Traceback (most recent call last): 
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

2. 区别决定场景

2.1 元组(静态)

2.1.1 运维场景

linux运维过程中,经常会结合一些脚本返回给监控软件,这些使用一般就是key-value这种形式,这些key一般是固定的,因为调用的bash命令输出是固定不变的。比如内存的情况,我们比较关心内存的容量,剩余容量,可用容量,一般我们会用free命令,那么对应的key就是total, free, aviable。这三个值在处理过程中,我们不希望被修改的。

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-


#######################
#
# Author: hao.zhang
# Time: 2020-05-24
#
#######################

import subprocess


def Run(cmd):
    '''
    cmd => linux操作系统系统命令,格式为列表
    return => 返回为列表,包括返回码、命令输出、报错信息
    '''
    c = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    code = c.wait()
    output = c.communicate()
    out = output[0]
    err = output[1]
    return code, out, err

def get_mem_info():
    cmd = ['free', '-h']
    code, out, err = Run(cmd)
    mem_info=out.split()
    mem_key=(mem_info[7], mem_info[9], mem_info[12])
    return mem_key

if __name__ == '__main__':
    mem_result=get_mem_info()
    print mem_result

输出
在这里插入图片描述

2.1.2 数据安全

有时候我们格式化一批数据的时候,我们程序的处理格式是有要求的,那么对于数据,我们希望是不可改变的,这样保证数据处理。比如登记基本信息,我们希望是(姓名,年龄,性别),这个数据在处理过程中不能被误改的。

样例

#!/usr/bin/env python
#coding:utf-8

info = ("haozi", "man", 18)

print("姓名是:%s 性别是 %s 年龄是 %d" %info)

输出
在这里插入图片描述

2.2 列表(动态)

对于列表,我能想出来的的场景就是对于数据进行批量处理,比如有一批数据,我们需要从GB转化为MB这种操作。

3. 元组和列表的共通点

3.1 通过索引处理元素

3.1.1 正数索引

列表个元组都支持索引操作,索引都是从0开始,第一个元素对应的索引为0

3.1.2 负数索引

倒数第一个元素对应的索引为-1

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

test_tup = ('test1', 'test2', 'test3', 'test4')
print("索引为0的元素: %s" % test_tup[0])
print("索引为-1的元素: %s" % test_tup[-1])

输出
在这里插入图片描述

3.2 支持切片处理

用法:[start: end: step]

start和end 两个索引值都可使用正数或负数 , 其中负数表示从倒数开始 。 该语法表示从start索引的元素开始(包含),到end索引的元素结束(不包含) 的所有元素。
step 表示步长,因此 step 使用负数没有意义

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

test_tup = ('test1', 'test2', 'test3', 'test4')

# 输出索引0<< index < 3
print test_tup[0:3]

# 输出索引1<< index < 3
print test_tup[1:3]

# 输出索引0<< index < 3,间隔为2
print test_tup[0:3:2]

输出
在这里插入图片描述

3.3 嵌套

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

test_tup = (1, 2, (3, 4, 5), 6, 7, (8, 9))
test_tup1 = (1, 2, [3, 4, 5], 6, 7, (8, 9))
test_list = [10, 11, 12, [13, 14, 15], 16, [17, 18, 19]]
test_list1 = [10, 11, 12, (13, 14, 15), 16, [17, 18, 19]]

print test_tup[2]
print test_list[3]
print tuple(test_list[5])
print test_list

print "==========================="
print test_tup1[2]
print test_list1[3]
print tuple(test_list1[5])
print test_list1

输出
在这里插入图片描述

3.4 封包和解包

  • 封包:程序将多个值赋值给一个变量,python将多个值自动封装成一个元组,这个称谓序列封包
  • 解包:元组或列表可以赋值给多个变量,此时序列的各元素会被依次赋值给每个变量,要求序列的元素个数和变量个数相等。这种功能被称为序列解包。
3.4.1 异步方式
  • 一个变量对应多个值的时候,会将这些值组成一个元组。
  • 将一个元组对应多个值,将元组中元素按照顺序复制给变量,所以元组个数和变量个数要保持一致。

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

# 封包
test = 1, 2, 3, 4, 5
print("test变量:%s , test变量类型:%s" % (test, type(test)))

# 解包
test2 = tuple(range(0, 10, 2))
print test2
a, b, c, d, e = test2
print a, b, c, d, e

输出
在这里插入图片描述

3.4.2 同步方式
  • 封包和解包同时应用,一个表达式可以搞定,其实内部执行顺序和上面异步的方式是相同的

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

x, y, z = 1, 2, 3
print("x:%d, y:%d, z:%d" % (x, y, z))

输出
在这里插入图片描述

3.5 常用内建函数

函数列表元组函数作用
count支持支持list.count(n),列表或者数组中元素是n的个数
index支持支持list.index(n), 列表或者元组中元素为n的索引
append支持不支持添加元素
reverse支持不支持列表支持,对列表进行倒置
sort支持不支持列表支持,对列表元素进行排序,数据按照大小,字符串按照
reversed支持支持元组支持,返回一个迭代器,然后通过list输出为列表
sorted支持支持元组支持,返回一个迭代器,然后通过list输出为列表

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-

ltest = [3, 2, 3, 4, 7, 1]
ttest = (3, 2, 3, 4, 7, 1)


print("count函数,元素为3的个数:%d" % ltest.count(3))
print("index函数,元素为7的索引:%d" % ltest.index(7))
print "================tuple============================"
print("count函数,元素为3的个数:%d" % ttest.count(3))
print("index函数,元素为7的个数:%d" % ttest.index(7))
print("reversed函数,元素倒置:%s" % list(reversed(ttest)))
print("sorted函数,元素排序:%s" % sorted(ttest))

输出
在这里插入图片描述

4. 列表和元组的存储空间分配

4.1 定义序列,同时赋值

列表和元组的区别是一个可变,一个不可变,那么存储方式和空间分配也是不同的,通过__sizeof__可以查询目前列表或者元组消耗的空间字节数。

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-
l = [1, 2, 3]
print("列表占用空间数:%d " % l.__sizeof__())

tup = (1, 2, 3)
print("元组占用空间数:%d" % tup.__sizeof__())

输出
在这里插入图片描述
可以看出来,同样的元素,在列表和元组两种方式下是不同的,列表占用的字节数明显高于元组的。
由于列表是动态的,所以需要指针指向存储位置,指向对应的元素。另外,由于列表可变,所以需要额外存储已经分配的长度大小,这样才可以实时追踪列表空间的使用情况,当空间不足时,及时分配额外空间。

4.2 先定义序列,然后append

这个方式是针对列表方式,因为元组是不可以append的。

样例

#!/usr/bin/env python
# -*- coding:utf-8 -*-
l = []
print("空列表占用空间数:%d " % l.__sizeof__())
tup = ()
print("空元组占用空间数:%d" % tup.__sizeof__())

for i in range(10):
    l.append(i)
    print("%d个元素空列表占用空间数:%d " % (i, l.__sizeof__()))

输出
在这里插入图片描述
从上面可以看出,空列表占用40个字节,元组占用24个字节,列表再append一次,会申请32个字节的空间,知道空间用完之后,再次进行申请

所以元组的空间开销要比列表小,对于大型数据量的话, 这个空间开销会更加明显

5. 元组和列表性能开销

从下面的程序可以看出来,元组创建效率要比列表搞,但是索引的时间是差不多的

5.1 创建性能对比


python3 -m timeit 'x=(1,2,3,4,5,6)'
20000000 loops, best of 5: 9.97 nsec per loop
python3 -m timeit 'x=[1,2,3,4,5,6]'
5000000 loops, best of 5: 50.1 nsec per loop

5.2 索引性能对比


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

  • 参考资料:
    • 极客时间 景霄 python核心技术与实战
    • 疯狂python讲义
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值