# 第五章:自定义序列类

# 5.1 python中的序列分类

序列是 python 中重要的协议

按照元素类型是否相同

  • 容器序列:list、tuple、deque
  • 扁平序列:str、bytes、bytearray、array.array

按照元素是否可变

  • 可变类型:list、deque、bytearray、array.array
  • 不可变:str、tuple、bytes

    # 元素类型任意
    my_list = list()
    my_list.append(100)
    my_list.append(True)

    # 指定元素类型
    import array
    my_array = array.array('i')
    my_array.append(100)
    # 初始化数组需要整型,附加字符串抛异常
    my_array.append('abc')

# 5.2 序列的abc继承关系

python 中内置的 collections.abc 抽象基类,可以帮助我们理解数据类型实现细节

python 是基于协议的语言,结合鸭子类型和魔法函数,就可以达到实现某种类型

from collections.abc import *

  • Iterable: iter
  • Reversible: reversed
  • Sized: len
  • Container: contains
  • Collection: Sized, Iterable, Container
  • Sequence: getitem, Reversible, Collection
  • MutableSequence: setitem, delitem, Sequence

不同魔法函数的组合,构建不同的类型

# 5.3 序列中+、+=和extend的区别

  • 加号 + 会新生成对象,并且两边类型需要一致
  • 加等 += 就地加,只需要可迭代就行
  • append 附加单个元素,extend 扩展多个元素

    # + 加新增
    l1 = [1, 2]
    l2 = l1 + [3, 4]
    print("type(l1): %d, and l1: %s" % (id(l1), l1))
    print("type(l2): %d, and l2: %s" % (id(l2), l2))

    # += 就地加
    l1 += ['3', '4']
    l1 += ('5', '6')
    l1 += range(2)
    print("type(l1): %d, and l1: %s" % (id(l1), l1))


    # + 两边类型需相同
    # += 只需要可迭代的就行,__iadd__ 魔法函数实现

# 5.4 实现可切片的对象

# 列表切片操作


    '''
    模式 [start:end:step]

    第一个数字 start 表示切片开始位置,默认 0
    第二个数字 end 表示切片截止(但不包含)位置,默认列表长度
    第三个数字 step 表示切片的步骤,默认为 1

    当 start 为 0 时可以省略
    当 end 为列表长度时可以省略
    当 step 为 1 时可以省略,并且省略步长时可以同时省略最后一个冒号
    当 step 为负数时,表示反向切片,这时 start 应该比 end 的值要大才行
    '''

    a_list = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]
    a_list[::]      # 返回包含原列表中所有元素的新列表
    a_list[::-1]    # 返回包含原列表中所有元素的逆向新列表
    a_list[::2]     # 隔一个元素取一个,获取偶数位置的元素
    a_list[1::2]    # 隔一个元素取一个,获取奇数位置的元素
    a_list[3:6]     # 指定切片的开始和结束位置
    a_list[0:100]   # 切片结束位置大于列表长度是,从列表尾部截断
    a_list[100:]    # 切片开始位置大于列表长度时,返回空列表

    a_list[len(a_list):0] = [9]     # 在列表尾部增加元素
    a_list[:0] = [1, 2]             # 在列表头部增加元素
    a_list[3:3] = [100]             # 在列表中间位置插入元素
    a_list[:2] = [100, 200]         # 替换列表元素,等号两边长度相等
    a_list[3:] = [4, 5, 6]          # 替换列表元素,等号两边长度可以不相等
    a_list[:3] = []                 # 删除列表中前 3 个元素

# 自定义序列类

参考 collections.abc 序列类 Sequence 所需的魔法函数


    import numbers

    class Group:
        def __init__(self, group_name, company_name, staff):
            self.group_name = group_name
            self.company_name = company_name
            self.staffs = staff

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

        def __getitem__(self, item):
            cls = type(self)
            if isinstance(item, slice):
                return cls(group_name=self.group_name, company_name=self.company_name, staff=self.staffs[item])
            elif isinstance(item, numbers.Integral):
                return cls(group_name=self.group_name, company_name=self.company_name, staff=[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 = ['linda', 'alex', 'catherine', 'nash', 'curry']
    group = Group(group_name='group', company_name='company', staff=staffs)
    sub_group = group[0]

    print('linda' in sub_group)
    print(len(sub_group))

# 5.5 bisect维护已排序序列

  • bisect 维护一个升序的序列
  • 内部二分查找实现,效率高

    import bisect

    # 处理已排序 序列 升序
    # 内部二分查找算法实现

    l1 = list()
    bisect.insort(l1, 10)
    bisect.insort(l1, 3)
    bisect.insort(l1, 2)
    bisect.insort(l1, 6)

    print(l1)   # [2, 3, 6, 10]

# 5.6 什么时候我们不该用列表

  • 比 list 更好的 python 内置数据结构
  • array 数组 连续的内存空间,性能高
  • deque 双向列表

# array 数组

array 与 list 一个重要区别,array 只能存储指定的数据类型数据


    import array

    list
    my_array = array.array('i')
    my_array.append(100)
    my_array.append('abc')
  • 某些应用场景,除了 list 我们还有其他更好的选择

# 5.7 列表推导式、生成器表达式和字典推导式

# 列表推导式

列表推导式,或列表生成式,通过一行代码生成列表


    # 提取出 1-20 之间的奇数
    odd_list = [i for i in range(21) if i % 2 == 1]
    print(odd_list)

    # 逻辑复杂的情况
    def handle_item(item):
        return item * item

    odd_list = [handle_item(i) for i in range(21) if i % 2 == 1]
    print(odd_list)
  • 列表生成式性能高于列表操作
  • 逻辑过于复杂时,列表生成式可读性降低

# 生成器表达式

列表推导 [] -> ()


    my_gen = (i for i in range(21) if i % 2 == 1)
    print(type(my_gen))     # <class 'generator'>
    for i in my_gen:
        print(i)

# 字典推导式


    d1 = {'key1': 'value1', 'key2': 'value2'}
    d2 = {v: k for (k, v) in d1.items()}
    print(d2)

# 集合推导式


    set1 = {v for v in d1.values()}
    print(set1)

# 5.8 本章小结

  • 序列类型的分类
  • 序列的abc继承关系
  • 序列的+、+=和extend的区别
  • 实现可切片的对象
  • bisect管理可排序序列
  • list的其他选项
  • 列表字典推导式
上次更新: 8/26/2022, 2:06:10 PM