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)) #
将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,以上呢就是本期的全部内容,整理不易,有任何错误与补充欢迎在评论区指出,我是啥都生,我们下期再见。