第四章:自定义序列类
1. Python中的序列该怎么理解?
有下标,有顺序,可以进行迭代,切片,相加等操作.
2. Python中的序列常见的通用操作
索引(index)
分片(slicing)
序列相加(拼接)
乘法(重复)
成员资格(in)
长度(len)
max()
min()
可以迭代
sorted
enumerate
zip
filter
map
3.Python中序列的常用分类
按照存放的类型不同:
容器序列
list , tuple , collections.deque
扁平序列
str, bytes,bytesarray,memoryview,array.array
容器序列和扁平序列的区别?
容器序列存放的是它们对任意类型对象的引用,而扁平序列存放的是值,而不是引用.换句话说,扁平序列是一段连续的内存空间.扁平序列只能存放单一的类型,并且还是基本的数据类型,例如:字符,字节,和数值这种类型的
按照是否可变的维度:
可变序列
list,collections.queue, array.array,bytearray,memoryview
不可变序列
tuple , str, bytes
4.序列的abc继承关系
下图展示了可变序列(MutableSequence)和不可变序列(Sequence)的差异,同时 也能看出前者从后者那里继承了一些方法。虽然内置的序列类型并不是直接从 Sequence 和 MutableSequence 这两个抽象基类(Abstract Base Class,ABC)继承而来的,但是了 解这些基类可以帮助我们总结出那些完整的序列类型包含了哪些功能。
5.序列类型的+, += ,和extend的区别?
+= 在序列中实际上调用的是iadd方法
def __iadd__(self, values):
self.extend(values)
return self
extend()是通过遍历来实现添加元素的
def extend(self, values):
'S.extend(iterable) -- extend sequence by appending elements from the iterable'
for v in values:
self.append(v)
注意: 序列的+ 号调用的是魔法方法__add__
,两边必须是相同的类型.而+=
调用的是extend方法,右边只要是一个可迭代的序列都可以的.
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/15 19:33'
from collections import abc
a = [1,2]
c = a + [3,4]
print(c)
c += (1,2) # 调用的是`iadd`里面调用的是extend.而extend使用的是for循环.
print(c)
# c = a + (1,2) # 这里会报错,+号两边只能放相同的序列.
c.append([1,3])# 这里是将[1,3]列表,作为一个元素添加到列表的后边
c.extend([1,3]) # 这里是将[1,3]合并到原来的列表上.
# append是追加一个元素,extend是扩充列表.\
print(dir(c))
6.Python的切片
格式:
可切片对象[start:end:step]
1.start 表示切片的起始位置.如果不提供,默认是0.可以省略
2.end 表示切片的结束位置.如果不提供,默认是是对象长度,len(object).可以省略
3.step 表示步长,可以省略,默认是1.也可以说hi负数,当step省略的时候,第二个冒号可以省略.step也可以是负数
alist = [3,4,5,6,7,9,11,13,15,17]
print(alist[::]) # 返回包含原列表中所有元素的新列表
print(alist[::-1]) # 返回原列表的逆序排列
print(alist[::2]) # 返回原列表的偶数位数据
print(alist[1::2]) # 获取奇数位置的数据
print(alist[3:6]) # 指定切片的开始和结束位置
print(alist[0:100]) # 切片位置大于列表长度时,从列表尾部截断
print(alist[100:]) # 切片开始位置大于列表长度时,返回空列表
alist[len(alist):]=[9] # 在列表尾部增加元素
print(alist)
alist[:0] = [1,2] # 前面的0省略了,相当于是alist[0:0] = [1,2]
print(alist) # 在列表的头部增加元素
alist[3:3] =[4] # 在列表中间插入元素
print(alist)
alist[:3] = [1,2] # 相当于是alist[0:3] = [1,2] 替换列表元素
alist[3:] = [4,5,6] # 替换元素,结果按照两边的最短元素来决定.
print(alist)
alist[:3] = [] # 删除列表中前三个元素
del alist[:3] # 切片元素连续
del alist[::2] # 隔一个删除一个,切片元素不连续
实现自定义的序列
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 9:42'
import numbers
class Group:
# 支持切片操作
def __init__(self, group_name, company_name, staffs):
self.group_name = group_name
self.company_name = company_name
self.staffs = staffs
def __reversed__(self):
self.staffs.reverse()
# 因为object[] 和 object[::]都会调动这个方法
def __getitem__(self, item):
# 取到class
cls = type(self)
if isinstance(item, slice):
return cls(group_name=self.group_name, company_name=self.company_name,
staffs=self.staffs[item])
if isinstance(item, numbers.Integral):
return self.staffs[item]
def __iter__(self):
return iter(self.staffs)
def __len__(self):
return len(self.staffs)
def __str__(self):
return '组员有:{}'.format(self.staffs)
def __contains__(self, item):
if item in self.staffs:
return True
else:
return False
staffs = ['fioman', '123', '456', '789']
group = Group('A', '大王', staffs=staffs)
sub_group = group[:2]
print(group)
if 'A' in group: # 这里会调用__contains__魔法函数
print('yes')
for item in group:
print(item)
reversed(group) # 实际上是调用了__reversed__魔法函数
print(group)
7. 使用bisect来维护一个有顺序的序列,升序.其实就是向一个序列中添加元素之后使得这个序列是有序的.
bisect功能介绍
1. 插入一个元素,并且使用二分法进行排序,使得这个序列升序排列
2. 如果有相同元素,可以控制它的插入是在左边还是右边.默认是右边插入
3. 可以查看一个元素左插入位置,和右插入位置.默认是查询右边插入的位置
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 10:28'
import bisect
lst = [1,3,4,2,5,1]
# 使用bisect的前提是原来的序列必须是有序的
lst.sort()
print(bisect.bisect_right(lst,3)) # 4
print(bisect.bisect_left(lst,3)) # 3
bisect.insort(lst, 3)
bisect.insort(lst,6)
bisect.insort_left(lst,3) # 从3的位置插入
print(lst)
8. 什么时候我们不应该使用列表,而使用array
当存放的数据是单一数据时,我们最好使用array.因为array比list的效率要高.
array和list的区别?
1.array只能存放相同类型的数据,而list可以存放不同类型的对象.
2.array是一片连续的内存空间,而list里面的对象可能是存放在别处.
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 10:34'
import array
# array 就相当于是C语言的数组.
# array和list的一个重要区别,arr只能存放相当类型的数据.必须指定
# 而list可以存放不同的类型的对象
a = list
my_array = array.array('i') # 有符号的整型
my_array.append(1)
# my_array.append('abc') # 只能存放int类型的数据
9.列表推导式,生成器表达式,字典推导式,集合推导式
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/17 10:42'
# 列表推导式
# 1.提取出1-20之间的奇数
odd_list = []
for i in range(21):
if i % 2 == 1:
odd_list.append(i)
print(odd_list)
# 使用列表推导式
odd_list = [x for x in range(21) if x % 2 == 1]
print(odd_list)
# 列表推导式的格式
# [on True for x in iteralbe 条件表达式(过滤)]
# 逻辑复杂的情况
def handle_item(item):
return item * item
odd_list = [handle_item(x) for x in range(21) if x % 2 == 1]
print(odd_list)
# 列表表达式的前面可以是一个函数,也可以是一个函数,但是不能是匿名函数
# 生成器表达式,将列表推导式的[]改成(),就变成了生成器表达式
gen = (x for x in range(21) if x % 2 == 1)
print(gen) # <generator object <genexpr> at 0x000001CF1B01C8E0>
print(type(gen)) # <class 'generator'>
for item in gen:
print(item)
# 字典推导式,颠倒key和value
my_dict = {'bob1': 22, 'bob3': 23, 'bob4': 5}
reversed_dict = {value: key for key, value in my_dict.items()}
print(reversed_dict)
# 集合推导式 set
# 如何将一个字典的key全部放到一个集合当中.
my_set = {key for key in my_dict.keys()}
# 也可以使用
my_set = set(my_dict.keys())
print(type(my_set))
print(my_set)