Python自定义序列类知识以及实现一个自定义序列类

自定义序列类

1 序列类型的分类

1.1 容器序列和扁平序列

容器序列和扁平序列是 Python 中两类基本的序列类型。容器序列存放的是元素的引用,即存放的是对象,而扁平序列存放的是元素的值,即存放的是值。

容器序列又分为 list、tuple 和 collections 模块中的一些其他类型,而扁平序列又分为 str、bytes、bytearray、memoryview 和 array.array,这些类型中存放的元素都是字符、字节或数值等基本类型,而不是对象。

1.1.1 容器序列

容器序列是存放不同类型数据的引用,可以存放不同类型的数据,包括基本数据类型和自定义类的实例等。

Python 容器序列包括:list、tuple 和 collections 模块中的一些其他类型,如 deque、Counter、OrderedDict、defaultdict 等。

1.1.2 扁平序列

扁平序列是存放相同类型数据的值,其中的元素类型通常是数值、字符或字节等基本类型,而不是对象。

Python 扁平序列包括:str、bytes、bytearray、memoryview 和 array.array 等。

1.2 可变序列和不可变序列

序列类型又可以分为可变序列和不可变序列两类。

可变序列可以通过索引修改序列中的元素,而不可变序列则无法修改其元素的值。

Python 中的可变序列包括 list、bytearray、array.array、collections.deque 等类型,而不可变序列包括 str、tuple、bytes 和 range 等类型。

2 abc的继承关系

所有的序列类型都是 collections.abc.Sequence 的子类,该类是 Python 标准库中的一个抽象基类。此外,可变序列还是 MutableSequence 的子类,而不可变序列则是 Reversible、Collection、Sized 和 Iterable 的子类。其中 Sized 是一个抽象基类,Reversible 和 Collection 是 Sized 的子类,而 Iterable 是 Collection 的子类。Sequence是Reversible和Collection的子类,可变序列有__seritem__,__delitem__,这些东西构成了python中的序列类型的协议。

collections.abc 是 Python 标准库中的一个模块,它定义了一些抽象基类,用于表示 Python 中的容器类型。其中,collections.abc.Sequence 是所有序列类型的抽象基类,MutableSequence 是所有可变序列类型的抽象基类,而 Reversible、Collection、Sized 和 Iterable 都是 Sized 的子类。

  • Sized: 表示对象的大小可以被计算,即对象具有 len() 方法。它是 Reversible、Collection 和 Iterable 的父类。
  • Reversible: 表示对象可以反向迭代,即对象具有 reversed() 方法。它是 Collection 的子类。
  • Collection: 表示对象是一种集合类型,即对象具有 contains() 方法和 iter() 方法。它是 Sized 和 Iterable 的子类。
  • Iterable: 表示对象是可迭代的,即对象具有 iter() 方法。它是 Sized 的子类。

除了上述抽象基类以外,collections.abc 还定义了其他一些有用的抽象基类,如 Mapping、MutableMapping、Set 和 MutableSet 等,用于表示 dict、set 等容器类型。

在 Python 中,抽象基类主要用于类型检查和代码设计。通过继承抽象基类,我们可以保证子类具有某些特定的行为和属性,从而提高程序的可读性和可维护性。

3 用python实现一个切片类型

3.1 切片介绍

Python 切片操作的语法为 sequence[start: end: step],其中的 sequence 可以是任意序列类型,startendstep 都是整数。

下面是一些 Python 切片操作的例子:

  • sequence[:]:返回整个序列。
  • sequence[start:]:返回从 start 开始到序列末尾的所有元素。
  • sequence[:end]:返回从序列开头到 end 之前的所有元素。
  • sequence[start:end]:返回从 start 开始到 end 之前的所有元素。
  • sequence[start:end:step]:返回从 start 开始到 end 之间,间隔为 step 的所有元素。
  • sequence[::-1]:返回逆序序列。
  • sequence[::2]:返回序列中所有的偶数位置的元素。
  • sequence[1::2]:返回序列中所有的奇数位置的元素。

注意,切片操作不会改变原序列,而是返回一个新的序列。如果需要修改原序列,需要使用赋值操作。

3.2 切片类实现

from collections.abc import Sequence

class MySliceable(Sequence):
    def __init__(self, sequence):
        self.sequence = sequence

		# 切片关键 getitem
    def __getitem__(self, index):
        if isinstance(index, slice):
            return MySliceable(self.sequence[index])
        return self.sequence[index]

    def __len__(self):
        return len(self.sequence)

上面的代码实现了一个自定义的可切片类 MySliceable,它继承自 collections.abc.Sequence 抽象基类,并实现了其中的 __getitem__()__len__() 方法。

__getitem__() 方法用于获取序列中指定位置的元素,它可以接受一个整数或一个切片对象作为参数。如果传入的是一个整数,则返回序列中对应位置的元素;如果传入的是一个切片对象,则返回一个新的 MySliceable 序列对象,其中包含了原序列中指定范围的元素。

__len__() 方法返回序列的长度,它是实现序列类型必须实现的方法之一。

通过继承抽象基类 collections.abc.Sequence,我们可以保证 MySliceable 类具有序列类型的一些基本行为和属性,从而可以使用 Python 中的一些序列相关函数和方法,如 len()、reversed()、list() 等。

下面是使用 MySliceable 类的例子:

sequence = MySliceable([1, 2, 3, 4, 5])
print(sequence[1])         # 输出 2
print(sequence[1:4])       # 输出 [2, 3, 4]
print(sequence[::-1])      # 输出 [5, 4, 3, 2, 1]
print(len(sequence))       # 输出 5
print(list(sequence))      # 输出 [1, 2, 3, 4, 5]
print(reversed(sequence))  # 输出 <list_reverseiterator object at 0x7f9c0b7f9ca0>

4 bisect模块

bisect 模块是 Python 标准库中的一个模块,用于处理排序后的序列。如果以后需要维持一个排序好的序列的话,可以直接使用bisect。

其中,bisect 函数用于将元素插入到已排序序列中的正确位置,insort 函数用于将元素插入到已排序序列中,并保持序列有序。

下面是 bisect 模块的一些常用函数和用法:

bisect_left 和 bisect_right 函数

  • bisect_left(a, x, lo=0, hi=len(a)):将元素 x 插入到已排序序列 a 中,并返回插入位置(如果有多个相同元素,则插入到最左侧位置)。
  • bisect_right(a, x, lo=0, hi=len(a)):将元素 x 插入到已排序序列 a 中,并返回插入位置(如果有多个相同元素,则插入到最右侧位置)。

insort_left 和 insort_right 函数

  • insort_left(a, x, lo=0, hi=len(a)):将元素 x 插入到已排序序列 a 中,并保持序列有序(如果有多个相同元素,则插入到最左侧位置)。
  • insort_right(a, x, lo=0, hi=len(a)):将元素 x 插入到已排序序列 a 中,并保持序列有序(如果有多个相同元素,则插入到最右侧位置)。

示例

下面是 bisect 模块的一些示例:

import bisect

a = [1, 2, 2, 2, 3, 4, 7]

print(bisect.bisect_left(a, 2))      # 输出 1
print(bisect.bisect_right(a, 2))     # 输出 4
print(bisect .insort_left(a, 2))      # 输出 None
print(a)                             # 输出 [1, 2, 2, 2, 2, 3, 4, 7]
print(bisect.insort_right(a, 2))     # 输出 None
print(a)                             # 输出 [1, 2, 2, 2, 2, 2, 3, 4, 7]

上面的代码演示了如何使用 bisect 模块的函数来处理排序后的序列。其中,bisect_left 和 bisect_right 函数用于查找元素的插入位置,insort_left 和 insort_right 函数用于插入元素并保持序列有序。

5 列表生成式,生成器表达式,字典推导式

5.1 列表生成式

列表生成式:odd = [i for i in range(21) if i % 2 == 1]

当然,列表生成式也可以实现很复杂的逻辑,下面是一个稍微复杂一些的例子:

words = ['hello', 'world', 'python', 'is', 'awesome']
# 将 words 列表中所有长度大于 4 的单词转换为大写形式,并保存到一个新的列表中
new_words = [word.upper() for word in words if len(word) > 4]
print(new_words)  # 输出 ['WORLD', 'PYTHON', 'AWESOME']

上面的代码使用列表生成式将 words 列表中所有长度大于 4 的单词转换为大写形式,并保存到一个新的列表中。其中,word.upper() 表示将单词转换为大写形式,for word in words 表示对 words 列表中的每个单词进行遍历,if len(word) > 4 表示只选择长度大于 4 的单词。

另外,列表生成式中还可以包含多个循环和条件语句,例如:

# 将两个列表中的元素组合起来,并计算它们的和,保存到一个新的列表中
a = [1, 2, 3]
b = [4, 5, 6]
new_list = [x + y for x in a for y in b if x % 2 == 0 and y % 2 == 1]
print(new_list)  # 输出 [6, 8]

上面的代码使用列表生成式将两个列表中的元素组合起来,并计算它们的和,只选择两个都是偶数或者两个都是奇数的元素。

5.2 生成器表达式

生成器表达式和列表生成式非常类似,但是它并不会一次性生成所有的元素,而是在需要的时候逐个生成,从而节省内存空间。生成器表达式的语法为 (expression for item in iterable),其中的 expression 是一个表达式,itemiterable 分别表示迭代变量和可迭代对象。

下面是一个使用生成器表达式的例子:

# 生成一个包含 1-100 之间的所有偶数的生成器
generator = (i for i in range(1, 101) if i % 2 == 0)
print(generator)    # 输出 <generator object <genexpr> at 0x7f9c0b7f9ca0>
print(list(generator))    # 输出 [2, 4, 6, ..., 98, 100]

上面的代码使用生成器表达式生成了一个包含 1-100 之间的所有偶数的生成器,然后通过 list() 函数将生成器转换为列表。

注意,生成器表达式和列表生成式的语法非常相似,但是它们的执行方式不同。列表生成式会一次性生成所有的元素,因此占用的内存空间较大,而生成器表达式则是逐个生成元素,因此占用的内存空间较小。如果需要处理大量的数据,建议使用生成器表达式来节省内存空间。

5.3 字典推导式

字典推导式是一种快速创建字典的方式,其语法为 {key: value for item in iterable if condition},其中的 keyvalueitemiterablecondition 分别表示字典的键、值、迭代变量、可迭代对象和筛选条件。

下面是一个使用字典推导式的例子:

# 将一个列表中的元
素作为键,它们的平方作为值,保存到一个字典中
a = [1, 2, 3, 4, 5]
new_dict = {x: x ** 2 for x in a}
print(new_dict)  # 输出 {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

上面的代码使用字典推导式将一个列表中的元素作为键,它们的平方作为值,保存到一个新的字典中。其中,x: x ** 2 表示将 x 作为键,x ** 2 作为值,for x in a 表示对列表中的每个元素进行遍历。

另外,字典推导式中还可以包含多个循环和条件语句,例如:

# 将两个列表中的元素组合起来,并计算它们的和,保存到一个字典中
a = [1, 2, 3]
b = ['a', 'b', 'c']
new_dict = {(x, y): x + y for x in a for y in b if x % 2 == 0 and y != 'a'}
print(new_dict)  # 输出 {(2, 'b'): 4, (2, 'c'): 5}

上面的代码使用字典推导式将两个列表中的元素组合起来,并计算它们的和,只选择其中满足条件的元素。其中,(x, y): x + y 表示将 (x, y) 作为键,x + y 作为值,for x in a for y in b 表示对两个列表中的元素进行遍历,if x % 2 == 0 and y != 'a' 表示只选择满足条件的元素。

总之,字典推导式是一种快速创建字典的方式,可以大大提高编程效率。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦滋堡的摸鱼芝士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值