元组啊,不就是不可变的列表吗?

B站|公众号:啥都会一点的研究生

相关阅读

整理了几个100%会踩的Python细节坑,提前防止脑血栓
整理了十个100%提高效率的Python编程技巧,更上一层楼
Python-列表,从基础到进阶用法大总结,进来查漏补缺
Python-元组,从基础到进阶用法大总结及与列表核心区别,进来查漏补缺
Python-字典,从基础到进阶用法大总结,进来查漏补缺
Python-集合,从基础到进阶大总结,进来查漏补缺
这些包括我在内都有的Python编程陋习,趁早改掉
Python可变类型的坑,不要再踩了
列表推导式,Python中最好的特性?可读性?
元组啊,不就是不可变的列表吗?
订阅专栏 ===> Python

问:元组是什么

答:呃,呃,内个,嗷,不就是“不可变的列表”嘛。

这个概括对吗?不能说对错,只能说概括不完全,元组除开用作不可变的列表,另一个常被忽略但极其实用的作用是,用于没有字段名的记录,本期我试图和大家一起学习归纳元组的常用方法,争取更上一层楼

首先来看看大家熟知的用法,用作不可变的列表,一句话概括就是,除了跟增删元素相关的方法外,元组支持列表的其他所有方法,为了方便说明,使用dir()分别查看列表与元组的内置方法与属性

dir(list)
# ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', 
'__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', 
'__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
 '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
  '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 
  'remove', 'reverse', 'sort']

dir(tuple)
# ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__dir__', 
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', 
'__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__',
 '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', 
 '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']

使用help()则可以查看内置方法与属性的说明,知道大家十有八九不会再逐个help查看,行吧,我来吧,带大家一一查看对比列表与元组中除开object类支持的方法外的其他方法和属性,以列表为参考进行比照

首先看属性,列表与元组都支持的有这些

s.__add__(s2)     # 拼接,s + s2,不改变s
s.__contains__(e) # s是否包含e,e in s
s.__getitem__(p)  # 获取s中位置p的元素,s[p]
s.__iter__()      # 获取s的迭代器
s.__len__()       # 获取元素数量,len(s)
s.__mul__(n)      # n个s的重复拼接,s * n,不改变s
s.__rmul__(n)     # 反向拼接,n * s

然后就是列表支持但元组不支持的

s.__iadd__(s2)      # 拼接, s += s2,改变s
s.__delitem__(p)    # 删除s中位于p的元素 del s[p]
s.__imul__(n)       # n个s的重复拼接,s *= n,改变s
s.__reversed__()    # 返回 s 的倒序迭代器
s.__setitem__(p, e) # 将s中位置p的元素替换为e,s[p] = e

接着,我们再一起来看看列表与元组都支持的方法

s.count(e) # e在s中的个数
s.index(e) # e在s中第一次出现的位置索引

是的,没了,紧接着看看列表支持但元组不支持的方法

s.append(e)              # 在s尾部新增元素
s.clear()                # 清空s所有元素,保留s对象
s.copy()                 # 浅拷贝s
s.extend(it)             # 将可迭代对象it追加给s
s.insert(p, e)           # 在s的p位置之前插入元素e
s.pop([p])               # 删除s中最后或(可选的)位于p的元素,并返回它的值
s.remove(e)              # 删除 s 中的第一次出现的e值
s.reverse()              # 把 s 的元素倒序排列,改变s
s.sort([key], [reverse]) # 对s中的元素进行排序,可选的参数有键(key)和是否倒序(reverse),改变s

OK,归纳完毕,想必大家对元组充当不可变列表,哪些可用,哪些不可用有了进一步了解,我是不会主动问大家要三连的

接下来继续看看另一个用途,数据记录,如果仅把元组理解为不可变的列表,那所含元素的总数和对应位置似乎就变得可有可无,但若当成字段集合,那么这些信息就变得很重要了,举些例子来说明

比如,在元组中存放直线的斜率与截距

line_k_b = (1.0322, -10.6667) # k, b

元组同样支持存放不同类型的数据

name, age, height, weight = ('CaiXukong', 30, 142.01, 180.02)

当数据增多时,通常还会以元组列表的形式存放并且搭配循环遍历,使用%格式运算符可以匹配元组中对应元素

user_infos = [('ZS', '001'), ('LS', '002'), ('WW', '003')]

for user_info in user_infos:
    print('%s/%s' % user_info)
    
"""
ZS/001
LS/002
WW/003
"""

此外,还可以使用拆包提取元素

user_infos = [('ZS', '001'), ('LS', '002'), ('WW', '003')]

for name, uid in user_infos:
    print(name)
    
"""
ZS
LS
WW
"""

关于拆包,最常见的就是平行赋值,比如之前的例子,把一个可迭代对象中的元素赋值到对应变量组成的元组中,对应变量组成的元组也就是说其实name, age, height, weight也为元组

name, age, height, weight = ('CaiXukong', 30, 142.01, 180.02)

说到这里当然得提一下利用这个特性快速进行值交换的例子,我们可以使用如下方法交换两个变量的值

b, a = a, b

然后通常搭配*运算符把一个可迭代对象拆开作为函数的参数,比如使用divmod得到10除以8的商和余数,提一嘴,其实函数返回值也是元组类型

divmod(10, 8) # 1, 2

type(divmod(10, 8)) # <class 'tuple'>

将10和8存入元组中并结合*运算符喂给函数同样达到目的

data = (10, 8)
quotient, remainder = divmod(*data)

# quotient : 1
# remainder : 2

但有时候不是对所有数据感兴趣,比如只会用到余数,那么则可以使用_占位符处理这种情况

data = (10, 8)
_, remainder = divmod(*data)

# remainder : 2

讲到这个,那如果我不感兴趣的数据很多怎么办,诶没关系,*运算符可以助你宠幸关心的数据,我们知道在Python中经常使用*args来获取不确定的参数,这个用法也被扩展到了平行赋值中,一起来看看这个例子

a, b, *rest = range(10)
# 0 1 [2, 3, 4, 5, 6, 7, 8, 9]

a, b, *rest = range(3)
# 0 1 [2]

a, b, *rest = range(2)
# 0 1 []

虽然这个运算符只能出现在一个变量名之前,但是这个变量可以在赋值表达式的任意位置出现,不止尾部,比如中间和头部

a, *middle, b = range(10)
# 0 [1, 2, 3, 4, 5, 6, 7, 8] 9

*head, b, c = range(10)
# [0, 1, 2, 3, 4, 5, 6, 7] 8 9

元组的拆包同样也可以用于嵌套结构,比如这个例子

*head, (b, c) = (1, 2, (3, 4)) 
# [1, 2] 3 4

注意了如果bc不加括号,则得到的结果完全就不同了

*head, b, c = (1, 2, (3, 4)) 
# [1] 2 (3, 4)

讲完了拆包,下一个要讲的则是具名元组namedtuple,它继承了普通元组的属性,那是干嘛的呢,元组如果作为记录来用,缺少给记录的字段命名的功能。而namedtuple常用来构建一个带字段名的元组和一个有名字的类,怎么用呢,来看看这个例子

先看第二行,创建一个具名元组需要两个参数,一个类名,一个该类各字段的名字,后者可以是由若干字符串组成的可迭代对象,或由空格分开的字段名组成的单字符串

下一行,存放在对应字段里的数据要以一串参数的形式传入,然后便可以通过字段名或者位置来获取一个字段的信息

from collections import namedtuple
User = namedtuple('User', ['name', 'age', 'height', 'weight'])
# User = namedtuple('User', 'name age height weight')
CaiXukang = User('CaiXukang', 30, 142.01, 180.02)

print(CaiXukang.weight) # 180.02

ok,以上呢就是本期的全部内容,整理不易,有任何错误与补充欢迎在评论区指出,我是啥都生,我们下期再见。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

啥都生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值