Python进阶笔记(三)深入理解序列类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29027865/article/details/87779204

3.1 py中的序列分类

第一个维度通过序列存储数据的类型:
容器序列:list,tuple,deque;
扁平序列:str,bytes,bytearray,array.array;
第二个维度通过序列是否可变来进行区分:
可变序列:list,deque,bytearray,array
不可变:str,tuple,bytes

序列类型有一个特性就是其可以用for进行遍历;

3.2 序列类型abc继承关系

python中有一个模块,是放在collections中的abc,abc是collections的和容器相关的抽象基类和数据结构都在其下。
我们来看其中的Sequence(不可变序列)和mutibleSequence(可变序列);
在这里插入图片描述
Sequence继承了两个类,Reversible和Collection,Reversible是完成数据的反转;

Collection又继承了Sized,Iterable,Container三个基类
Sized实际上是实现了一个__len__方法,这样就可以去计算Collection的长度;
Iterable实际上是一个迭代器,其实现了__iter__方法,有了这个就可以实现for循环;
Container有一个__contains__方法,有了这个方法后,就可以进行if…in的判断,用来判断某一个数据是否在list里面;
这些魔法函数构成了序列类型的协议,整个Sequence必须满足所有的这些抽象接口,才能构成一个序列。
而MutibleSequence实际上是一个可变的数据类型,这个可变体现在__setitem__和__delitem__这两个魔法函数上,__setitem__我们可以通过其来添加值,__delitem__可以通过其来删除;

3.3 list中extends方法区别

+,+=,extend的区别

# 新建一个list的两种方法
a = [1,2]
a = list([1,2])
c = a + [3,4]
print(c)
-------   [1,2,3,4]
# c是将两个list相加产生一个新的list
# +=表示为就地加
a += [3,4]
print(a)
-------   [1,2,3,4]
# 将加的列表改为元组
a += (3,4)
print(a)
-------   [1,2,3,4]
c = a + (3,4)
print(c)
-------  can only concatenate list

由此可见,+=其中接受的参数,可以是任意的序列类型,我们看到MutibleSequence中有一个__iadd__的魔法函数,其使用extend方法来扩充,而extend的实现,只需要能传递一个iterable类型就可以。

a.extend(range(3))
print(a)
------- [1,2,3,4,0,1,2]
# 错误写法
a = a.extend(range(3))
# 注意extend的实现是直接对a进行修改,没有返回值
a.append([1,2])
print(a)
------- [1,2,[1,2]]
#可以看到append方法是直接将list作为一个值,而不是对list进行迭代;
a.append((1,2))
print(a)
------- [1,2,(1,2)]

3.4 实现可切片的对象

切片的操作是产生一个新元素,是不会改变原来的list的


#模式[start:end:step]
"""
    其中,第一个数字start表示切片开始位置,默认为0;
    第二个数字end表示切片截止(但不包含)位置(默认为列表长度);
    第三个数字step表示切片的步长(默认为1)。
    当start为0时可以省略,当end为列表长度时可以省略,
    当step为1时可以省略,并且省略步长时可以同时省略最后一个冒号。
    另外,当step为负整数时,表示反向切片,这时start应该比end的值要大才行。
"""
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]  # 在列表头部插入元素
print(aList)
aList[3:3] = [666]  # 在列表中间位置插入元素,起始插入在第四个位置,前面有三个元素;
print(aList)
aList[:3] = [1, 2]  # 替换列表元素,等号两边的列表长度相等
print(aList)
aList[3:] = [4, 5, 6]  # 等号两边的列表长度也可以不相等
print(aList)
aList[::2] = [0] * 3  # 隔一个修改一个
print (aList)
aList[::2] = ['a', 'b', 'c']  # 隔一个修改一个
print(aList)
aList[::2] = [1,2,3]  # 左侧切片不连续,等号两边列表长度必须相等
print(aList)
# aList[:3] = []  # 删除列表中前3个元素
# print(aList)
del aList[:3]  # 切片元素连续
print(aList)
del aList[::2]  # 切片元素不连续,隔一个删一个
print(aList)

下面我们来实现自己的可切片对象:

import numbers
class Group:
    #支持切片操作
    def __init__(self, group_name, company_name, staffs):
        self.group_name = group_name
        self.company_name = company_name
        # staffs为一个list
        self.staffs = staffs

    def __reversed__(self):
        self.staffs.reverse()

    # 切片实现的关键:因为staffs是一个list,所以对其做切片时,它是可以返回到getitem中来的;
    def __getitem__(self, item):
    	# 目的是为了使得返回的对象不是个list,而是一个group
        cls = type(self)
        if isinstance(item, slice):
            return cls(group_name=self.group_name, company_name=self.company_name, staffs=self.staffs[item])
        elif isinstance(item, numbers.Integral):
            return cls(group_name=self.group_name, company_name=self.company_name, staffs=[self.staffs[item]])
        # return self.staffs[item]
    def __len__(self):
        return len(self.staffs)

    def __iter__(self):
        return iter(self.staffs)

    def __contains__(self, item):
        if item in self.staffs:
            return True
        else:
            return False

staffs = ["bobby1", "imooc", "bobby2", "bobby3"]
group = Group(company_name="imooc", group_name="user", staffs=staffs)
reversed(group)
for user in group:
    print(user)

3.5 bisect维护已排序序列

bisect是通过二分查找的方法来维持可排序的序列,在开发中如果需要去维持一个排序好的序列,可以使用bisect,一是因为其插入都会将序列排序;二是其采用二分查找,效率比较高。
bisect插入的默认方法是bisect_right,即按照右侧的数值优先插入;

import bisect
from collections import deque

#用来处理已排序的序列,用来维持已排序的序列, 升序
#二分查找
inter_list = deque()
bisect.insort(inter_list, 3)
bisect.insort(inter_list, 2)
bisect.insort(inter_list, 5)
bisect.insort(inter_list, 1)
bisect.insort(inter_list, 6)

print(bisect.bisect_left(inter_list, 3))
#学习成绩
print(inter_list)

(后期会详细更新其用法)

3.5 什么时候我们不该使用列表

list什么都可以放,但是array只能存放指定类型的数据

import array
#array和list的一个重要区别, array只能存放指定的数据类型
my_array = array.array("i")
my_array.append(1)
my_array.append("abc")

3.5 列表生成式,生成器表达式

# 列表生成式
# 1. 提取出1-20之间的奇数
odd_list = []
for i in range(21):
	if i%2 == 1:
		odd_list.append(i)

odd_list = [i for i in range(21) if i % 2 ==1]
# 2. 逻辑复杂的情况
def hadle_item(item):
	return item * item
odd_list = [hadle_item(i) for i in range(21) if i % 2==1]
print(type(odd_list))
print(odd_list)
# 列表生成式性能高于列表操作
# 生成器表达式
odd_gen = (i for i in range(21) if i % 2 == 1)
print(type(odd_gen))
for item in odd_gen:
	print(item)
odd_list = list(odd_gen)
print(odd_list)

# 字典推导式
my_dict = {"bobby1":22,"bobby2":23,"imooc.com":5}
reversed_dict = {value:key for key,value in my_dict.items()}
print(reversed_dict)

# 集合推导式
my_set = {key for key,value in my_dict.items()}
print(my_set)
print(type(my_set))
my_set = set(my_dict.keys())
print(my_set)

python是基于协议来编程的,把继承关系理解为一种协议;
满足于序列类型,即可实现某种操作;

猜你喜欢

转载自blog.csdn.net/qq_29027865/article/details/87779204