自定义序列类
一,序列类型的分类
序列类型的分类
序列类型都能用 for 循环遍历
- 第一分类
- 容器序列(能够放置任意类型的数据)
- list,tuple,deque
- 扁平序列(只能放相同的数据类型)
- str,bytes,bytearray,array.array
- 容器序列(能够放置任意类型的数据)
- 第二分类
- 可变序列(能往对象添加数据)
- list,deque,bytearray,array
- 不可变(不能往对象添加数据)
- str,tuple,bytes
- 可变序列(能往对象添加数据)
二,序列类型的abc继承关系
from collections import abc,从abc处进入序列的抽象基类,查看协议
从 abc 进入接口,观察抽象基类,我们发现实现一个序列类型需要实现的魔法方法
__contains__
能够实现某个对象是否能使用 in
的操作,如果没有定义,直接定义了 __getitem__
可以得到
三,序列类型中的+, +=和extend区别
l = [1, 2]
new_l = l + [3, 4, 5, 6] ①
l += [3, 4, 5, 6] ②
l += (3, 4, 5, 6)
l.entend([3, 4, 5]) ③
l.entend(range(3))
l.entend('asdfg')
① 使用加号其实是把一个列表进行相加,不推荐使用,没有优化,速度慢
② 使用 += 操作,对象可以是任何可迭代对象,是在原来的列表上进项加,速度快,有优化,背后调用extend
③ extend
: 接受任何可迭代对象,把对象的值一个一个迭代到列表里面
三,实现可切片的对象
- 只实现
__getitem__
方法,就能进行切片的操作,使用其进行欺骗
class Group:
# 支持切片的操作,实现序列协议
def __init__(self, group_name, company_name, staffs):
self.group_name = group_name
self.company = company_name
self.staffs = staffs # 员工
def __reversed__(self):
pass
def __getitem__(self, item):
"""
实现欺骗的关键
"""
print(item)
return self.staffs[item]
def __len__(self):
pass
def __iter__(self):
pass
def __contains__(self, item):
pass
staffs = ['xyb1', 'xyb2', 'xyb3', 'xyb4']
group = Group(company_name='my_company', group_name='user', staffs=staffs)
print(group[::])
# 当对一个序列进行切片的时候,会自动转换成slice,slice(None, None, None)
-
不过要把序列协议实现完整,在
abc
抽象基类里面查看序列的魔法函数但是我们在开发当中往往需要对一个切出来的数据进行各种操作,应该继续维护切片出来的数据的类型
import numbers
class Group:
# 支持切片的操作,实现序列协议
def __init__(self, group_name, company_name, staffs):
self.group_name = group_name
self.company = company_name
self.staffs = staffs # 员工
def __reversed__(self):
self.staffs.reverse()
def __getitem__(self, item):
"""
实现欺骗的关键
切片的原理:
l = [1, 2, 3, 4, 5, 6]
l[slice(0, 5, 1)]
"""
cls = type(self)
if isinstance(item, slice):
print(666)
return cls(self.group_name, self.company, self.staffs[item])
elif isinstance(item, numbers.Integral):
return cls(self.group_name, self.company, [self.staffs[item]])
def __len__(self):
return len(self.staffs)
def __iter__(self):
return (item for item in self.staffs)
def __contains__(self, item):
if item in self.staffs:
return True
else:
return False
staffs = ['xyb1', 'xyb2', 'xyb3', 'xyb4']
group = Group(company_name='my_company', group_name='user', staffs=staffs)
s = group[2]
print(s.staffs)
优点:可以继续维护切片出来的数据,返回的是一个类,还能继续调用它的类的方法
四,bisect维护已排列序列
biset 能够维护一个有顺序的序列,在一个空列表中无须的加值,最后能够得到有序的列表
- bisect 能够查看插入一个序列的时候应该从哪个位置插入,默认使用 bisect.right
import bisect
from collections import deque
# 用来 处理已排序的序列,用来维持已排序序列,升序
l = []
bisect.insort(l, 8)
bisect.insort(l, 5)
bisect.insort(l, 16)
bisect.insort(l, 7)
bisect.insort(l, 45)
bisect.insort(l, 0)
bisect.insort(l, 62)
bisect.insort(l, 123)
print(bisect.bisect(l, 158)) # 158应该在下表为8的地方插入
print(bisect.bisect_left(l, 123.0)) # 158应该在下表为8的地方插入
print(deque(l))
...
8
7
deque([0, 5, 7, 8, 16, 45, 62, 123])
五,什么时候我们不该使用列表
array 的效率很高,背后是一个 c 语言的数组
-
使用之前需要指定存储的数据类型(一个array只能储存一种数据类型)
-
import array # array只能存放特点的数据类型 a = list my_array = array.array('i') # 申明类型 my_array.append(1) my_array.append(2) print(my_array)
-
他的处理效率比列表高,忒你情况下使用array比较合适