• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Python中序列的修改、散列与切片详解

python 搞代码 4年前 (2022-01-07) 25次浏览 已收录 0个评论

在Python中,最基本的数据结构是序列(sequence)。下面这篇文章主要给大家介绍了关于Python中序列的修改、散列与切片的相关资料文中通过示例代码介绍的非常详细,需要的朋友可以参考,下面来一起看看吧。

前言

本文主要给大家介绍了关于Python中序列的修改、散列与切片的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

Vector类:用户定义的序列类型

  我们将使用组合模式实现 Vector 类,而不使用继承。向量的分量存储在浮点数数组中,而且还将实现不可变扁平序列所需的方法。

Vector 类的第 1 版要尽量与前一章定义的 Vector2d 类兼容。

Vector类第1版:与Vector2d类兼容

Vector 类的第 1 版要尽量与前一章定义的 Vector2d 类兼容。然而我们会故意不让 Vector 的构造方法与 Vector2d 的构造方法兼容。为了编写 Vector(3, 4) 和 Vector(3, 4, 5) 这样的代码,我们可以让 __init__ 方法接受任意个参数(通过 *args);但是,序列类型的构造方法最好接受可迭代的对象为参数,因为所有内置的序列类型都是这样做的。

测试 Vector.__init__ 和 Vector.__repr__ 方法

 >>> Vector([3.1, 4.2]) Vector([3.1, 4.2]) >>> Vector((3, 4, 5)) Vector([3.0, 4.0, 5.0]) >>> Vector(range(10)) Vector([0.0, 1.0, 2.0, 3.0, 4.0, ...])

vector_v1.py:从 vector2d_v1.py 衍生而来

 from array import array import reprlib import math class Vector: typecode = 'd' def __init__(self, components): self._components = array(self.typecode, components)  #self._components是“受保护的”实例属性,把Vector的分量保存在一个数组中 def __iter__(self): return iter(self._components)    #为了迭代,我们使用self._components构建一个迭代器 def __repr__(self): components = reprlib.repr(self._components)   #使用reprlib.repr()函数获取self._components 的有限长度表示形式(如 array('d', [0.0, 1.0, 2.0, 3.0, 4.0, ...])) components = components[components.find('['):-1]  #把字符串插入 Vector 的构造方法调用之前,去掉前面的array('d' 和后面的 ) return 'Vecotr({})'.format(components)   #直接使用 self._components 构建 bytes 对象 def __str__(self): return str(tuple(self)) def __bytes__(self): return (bytes([ord(self.typecode)]) + bytes(self._components)) def __eq__(self, other): return tuple(self) == tuple(other) def __abs__(self): return math.hypot(sum(x * x for x in self))   #不能使用hypot方法了,因此我们先计算各分量的平方之和,然后再使用sqrt方法开平方 def __bool__(self): return bool(abs(self)) @classmethod def frombytes(cls, octets): typedcode = chr(octets[0]) memv = memoryview(octets[1:]).cast(typedcode) return cls(memv)      #我们只需在 Vector2d.frombytes 方法的基础上改动最后一行:直接把memoryview传给构造方法,不用像前面那样使用*拆包

协议和鸭子类型

在 Python 中创建功能完善的序列类型无需使用继承,只需实现符合序列协议的方法。不过,这里说的协议是什么呢?

在面向对象编程中,协议是非正式的接口,只在文档中定义,在代码中不定义。例如,Python 的序列协议只需要 __len__ 和 __getitem__ 两个方法。任何类(如 Spam),只要使用标准的签名和语义实现了这两个方法,就能用在任何期待序列的地方。Spam 是不是哪个类的子类无关紧要,只要提供了所需的方法即可。

 class FrenchDeck: ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = 'spades diamonds clubs hearts'.split() def __init__(self): self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks] def __len__(self): return len(self._cards) def __getitem__(self, position): return self._cards[position]

协议是非正式的,没有强制力,因此如果你知道类的具体使用场景,通常只需要实现一个协议的部分。例如,为了支持迭代,只需实现__getitem__ 方法,没必要提供 __len__ 方法。

Vector类第2版:可切片的序列

如 FrenchDeck 类所示,如果能委托给对象中的序列属性(如self._components 数组),支持序列协议特别简单。下述只有一行代码的 __len__ 和 __getitem__ 方法是个好的开始:

 class Vector: # 省略了很多行 # ... def __len__(self): return len(self._components) def __getitem__(self, index): return self._components[index]

添加这两个方法之后,就能执行下述操作了:

 >>> v1 = Vector([3, 4, 5]) >>> len(v1) >>> v1[0], v1[-1] (3.0, 5.0) >>> v7 = Vector(range(7)) >>> v7[1:4] array('d', [1.0, 2.0, 3.0])

可以看到,现在连切片都支持了,不过尚不完美。如果 Vector 实例的切片也是 Vector 实例,而不是数组,那就更好了。前面那个FrenchDeck 类也有类似的问题:切片得到的是列表。对 Vector 来说,如果切片生成普通的数组,将会缺失大量功能。

为了把 Vector 实例的切片也变成 Vector 实例,我们不能简单地委托给数组切片。我们要分析传给 __getitem__ 方法的参数,做适当的处理。

切片原理

了解 __getitem__ 和切片的行为

 >>> class MySeq: ... def __getitem__(self, index): ...  return index ... >>> s = MySeq()               >>> s[1]                      #__getitem__直接返回传给它的值 >>> s[1:4]                     #[1:4]表示变成了slice(1, 4, None) slice(1, 4, None) >>> s[1:4:2]                    #[1:4:2]的<i style="color:transparent">来源gaodai$ma#com搞$代*码*网</i>意思为从第1个索引开始,到第4个索引结束,步长为2 slice(1, 4, 2)           >>> s[1:4:2, 9]                   (slice(1, 4, 2), 9)                #神奇的事情发生了..wtf...如果[]中有逗号,那么__getitem__接收的是元祖 >>> s[1:4:2, 7:9]                 #元祖中还可以包含多个切片对象 (slice(1, 4, 2), slice(7, 9, None))

以上就是Python中序列的修改、散列与切片详解的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Python中序列的修改、散列与切片详解

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址