python元组

元组是Python中另一个重要的序列结构,和列表类似,也是由一系列按特定顺序排序的元素组成。和列表不同的是,列表可以任意操作元素,是可变序列;而元组是不可变序列,即元组中的元素不可以单独修改。

元组可以看做是不可变的列表。通常情况下,元组用于保存不可修改的内容。

1、从形式上看,元组的所有元素都放在一对小括号“()”中,相邻元素之间用逗号“,”分隔,如下所示:

(element1, element2, ... , elementn)

其中element1~elementn表示元组中的各个元素,个数没有限制,且只要是Python支持的数据类型就可以。

2、从存储内容上看,元组可以存储整数、实数、字符串、列表、元组等任何类型的数据,并且在同一个元组中,元素的类型可以不同,例如:

("c.biancheng.net",1,[2,'a'],("abc",3.0))

在这个元组中,有多种类型的数据,包括整形、字符串、列表、元组。

创建元组

Python提供了多种创建元组的方法。

=运算符直接创建元组

在创建元组时,可以使用赋值运算符“=”直接将一个元组赋值给变量,其语法格式如下

tuplename = (element1,element2,...,elementn)

其中,tuplename表示创建的元组名,可以使用任何符合Python命名规则,且不和Python内置函数重名的标识符作为元组名。

下面定义的元组都是合法的:

num = (7,14,21,28,35)
a_tuple = ("C语言中文网","http://c.biancheng.net")
python = ("Python",19,[1,2],('c',2.0))

# 元组通常都是使用一对小括号将所有元素括起来的,
# 但小括号不是必须的,只要将各元素用逗号隔开,Python 就会将其视为元组
a_tuple = "C语言中文网","http://c.biancheng.net"
print(a_tuple)

当创建的元组中只有一个元素时,此元组后面必须要加一个逗号“,”,否则Python解释器会将其误认为字符串。

#创建元组 a_typle
a_tuple =("C语言中文网",)
print(type(a_tuple))
print(a_tuple)

#创建字符串 a
a = ("C语言中文网")
print(type(a))
print(a)

运行结果为:

<class 'tuple'>  #  a_tuple 才是元组类型
('C语言中文网',)
<class 'str'>  # 变量 a 只是一个字符串
C语言中文网

使用tuple()函数创建元组

tuple函数的语法格式如下:

tuple(data)

其中,data 表示可以转化为元组的数据,其类型可以是字符串、元组、range 对象等。

# 将列表转换成元组
a_list = ['crazyit', 20, -1.2]
a_tuple = tuple(a_list)
print(a_tuple)

# 使用range()函数创建区间(range)对象
a_range = range(1, 5)
print(a_range)
# 将区间转换成元组
b_tuple = tuple(a_range)
print(b_tuple)
# 创建区间时还指定步长
c_tuple = tuple(range(4, 20, 3))
print(c_tuple)

运行结果为:

('crazyit', 20, -1.2)
range(1, 5)
(1, 2, 3, 4)
(4, 7, 10, 13, 16, 19)

访问元组元素

想访问元组中的指定元素,可以使用元组中各元素的索引值获取, 也可以采用切片方式获取指定范围内的元素 。

a_tuple = ('crazyit', 20, -1.2)
print(a_tuple[1]) # 20

b_tuple = ('crazyit', 20, -1.2)
#采用切片方式
print(b_tuple[:2])  # ('crazyit', 20)

修改元组元素

元组是不可变序列,元组中的元素不可以单独进行修改。但是,元组也不是完全不能修改。

我们可以对元组进行重新赋值:

a_tuple = ('crazyit', 20, -1.2)
print(a_tuple)  # 输出是('crazyit', 20, -1.2)
#对元组进行重新赋值
a_tuple = ('c.biancheng.net',"C语言中文网")
print(a_tuple)  # 输出是('c.biancheng.net', 'C语言中文网')

还可以通过连接多个元组的方式向元组中添加新元素。

a_tuple = ('crazyit', 20, -1.2)
print(a_tuple)  # 输出是('crazyit', 20, -1.2)
#连接多个元组
a_tuple = a_tuple + ('c.biancheng.net',)
print(a_tuple)  # 输出是('crazyit', 20, -1.2, 'c.biancheng.net')

# 元组连接的内容必须都是元组,不能将元组和字符串或列表进行连接,否则或抛出 TypeError 错误。
a_tuple = ('crazyit', 20, -1.2)
#元组连接字符串
a_tuple = a_tuple + 'c.biancheng.net'
print(a_tuple)
# 结果为:
# Traceback (most recent call last):
#  File "C:\Users\mengma\Desktop\1.py", line 4, in <module>
#    a_tuple = a_tuple + 'c.biancheng.net'
# TypeError: can only concatenate tuple (not "str") to tuple

删除元组

当已经创建的元组确定不再使用时,可以使用del语句将其删除

a_tuple = ('crazyit', 20, -1.2)
print(a_tuple)
#删除a_tuple元组
del(a_tuple)
print(a_tuple)

运行结果为:

('crazyit', 20, -1.2)
Traceback (most recent call last):
  File "C:\Users\mengma\Desktop\1.py", line 4, in <module>
    print(a_tuple)
NameError: name 'a_tuple' is not defined

元组和列表的区别

元组和列表最大的区别就是,列表中的元素可以进行任意修改;而元组中的元素无法修改。

可以理解为,tuple 元组是一个只读版本的 list 列表。

需要注意的是,这样的差异势必会影响两者的存储方式,我们来直接看下面的例子:

>>> listdemo = []
>>> listdemo.__sizeof__()
40
>>> tupleDemo = ()
>>> tupleDemo.__sizeof__()
24

对于列表和元组来说,虽然它们都是空的,但元组却比列表少占用 16 个字节,这是为什么呢?

事实上,就是由于列表是动态的,它需要存储指针来指向对应的元素(占用 8 个字节)。另外,由于列表中元素可变,所以需要额外存储已经分配的长度大小(占用 8 个字节)。但是对于元组,情况就不同了,元组长度大小固定,且存储元素不可变,所以存储空间也是固定的。

通过对比列表和元组存储方式的差异,我们可以引申出这样的结论,即元组要比列表更加轻量级,所以从总体上来说,元组的性能速度要由于列表。

另外,Python会在后台,对静态数据做一些资源缓存。通常来说,因为垃圾回收机制的存在,如果一些变量不被使用了,Python就会回收它们所占用的内存,返还给操作系统,以便其他变量或其他应用使用。

但是对于一些静态变量(比如元组),如果它不被使用并且占用空间不大时,Python会暂时缓存这部分内存。这样的话,当下次再创建同样大小的元组时,Python就可以不用再向操作系统发出请求去寻找内存,而是可以直接分配之前缓存的内存空间,这样就能大大加快程序的运行速度。

算初始化一个相同元素的列表和元组分别所需的时间。我们可以看到,元组的初始化速度要比列表快 5 倍。

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

列表和元组的底层实现

list列表具体结构

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size
     *     ob_item == NULL implies ob_size == allocated == 0
     * list.sort() temporarily sets allocated to -1 to detect mutations.
     *
     * Items must normally not be NULL, except during construction when
     * the list is not yet visible outside the function that builds it.
     */
    Py_ssize_t allocated;
} PyListObject;

list本质上是一个长度可变的连续数组。其中ob_item是一个指针列表,里边的每一个指针都指向列表中的元素,而allocated则用于存储该列表目前已被分配的空间大小。

需要注意的是,allocated和列表的实际空间大小不同,列表实际空间大小,指的是len(list)返回的结果,也就是上边代码中注释中的ob_size,表示该列表总共存储了多少个元素。而在实际情况中,为了优化存储结构,避免每次增加元素都要重新分配内存,列表预分配的空间allocated往往会大于ob_size

因此allocatedob_size的关系是:allocated >= len(list) = ob_size >= 0

如果当前列表分配的空间已满(即allocated == len(list)),则会向系统请求更大的内存空间,并把原来的元素全部拷贝过去。

元组的具体结构

typedef struct {
    PyObject_VAR_HEAD
    PyObject *ob_item[1];

    /* ob_item contains space for 'ob_size' elements.
     * Items must normally not be NULL, except during construction when
     * the tuple is not yet visible outside the function that builds it.
     */
} PyTupleObject;

tuplelist相似,本质也是一个数组,但是空间大小固定。不同于一般数组,Pythontuple做了许多优化,来提升在程序中的效率。

为了提高效率,避免频繁的调用系统函数freemalloc向操作系统申请和释放空间,tuple源文件中定义了一个free_list

static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];

所有申请过的,小于一定大小的元组,在释放的时候会被放进这个free_list中以供下次使用。也就是说,如果以后需要再去创建同样的tuplePython就可以直接从缓存中载入。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星*湖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值