自定义序列的相关魔法方法允许我们自己创建的类拥有序列的特性,让其使用起来就像 python 的内置序列(dict,tuple,list,string等)。
如果要实现这个功能,就要遵循 python 的相关的协议。所谓的协议就是一些约定内容。例如,如果要将一个类要实现迭代,就必须实现两个魔法方法:__iter__、next(python3.x中为__new__)。__iter__应该返回一个对象,这个对象必须实现 next 方法,通常返回的是 self 本身。而 next 方法必须在每次调用的时候都返回下一个元素,并且当元素用尽时触发 StopIteration 异常。
而其实 for 循环的本质就是先调用对象的__iter__方法,再不断重复调用__iter__方法返回的对象的 next 方法,触发 StopIteration 异常时停止,并内部处理了这个异常,所以我们看不到异常的抛出。
这种关系就好像接口一样,如果回顾以前几篇的魔法方法,可以发现许多的内置函数得到的结果就是相应的魔法方法的返回值。
下面是一下相关的魔法方法:
•__len__(self)
•返回容器的长度。可变和不可变容器都要实现它,这是协议的一部分。
•__getitem__(self, key)
•定义当某一项被访问时,使用self[key]所产生的行为。这也是可变容器和不可变容器协议的一部分。如果键的类型错误将产生TypeError;如果key没有合适的值则产生KeyError。
•__setitem__(self, key, value)
•定义当一个条目被赋值时,使用self[key] = value所产生的行为。这也是可变容器协议的一部分。而且,在相应的情形下也会产生KeyError和TypeError。
•__delitem__(self, key)
•定义当某一项被删除时所产生的行为。(例如del self[key])。这是可变容器协议的一部分。当你使用一个无效的键时必须抛出适当的异常。
•__iter__(self)
•返回一个容器迭代器,很多情况下会返回迭代器,尤其是当内置的iter()方法被调用的时候,以及当使用for x in container:方式循环的时候。迭代器是它们本身的对象,它们必须定义返回self的__iter__方法。
•__reversed__(self)
•实现当reversed()被调用时的行为。应该返回序列反转后的版本。仅当序列是有序的时候实现它,例如列表或者元组。
•__contains__(self, item)
•定义了调用in和not in来测试成员是否存在的时候所产生的行为。这个不是协议要求的内容,但是你可以根据自己的要求实现它。当__contains__没有被定义的时候,Python会迭代这个序列,并且当找到需要的值时会返回True。
•__missing__(self, key)
•其在dict的子类中被使用。它定义了当一个不存在字典中的键被访问时所产生的行为。(例如,如果我有一个字典d,当"george"不是字典中的key时,使用了d["george"],此时d.__missing__("george")将会被调用)。
下面是一个代码示例:
class Foo(object): def __init__(self, key, value): self.key = [] self.value = [] self.key.append(key) self.value.append(value) def __len__(self): return len(self.key) def __getitem__(self, item): try: __index = self.key.index(item) return self.value[__index] except ValueError: raise KeyError('can not find the key') def __setitem__(self, key, value): if key not in self.key: self.key.append(key) self.value.append(value) else: __index = self.key.index(key) self.value[__index] = value def __delitem__(self, key): try: __index = self.key.index(key) del self.key[__index] del self.value[__index] except ValueError: raise KeyError('can not find the key') def __str__(self): result_list = [] for index in xrange(len(self.key)): __key = self.key[index] __value = self.value[index] result = __key, __value result_list.append(result) return str(result_list) def __iter__(self): self.__index = 0 return self def next(self): if self.__index == len(self.key): self.__index = 0 raise StopIteration() else: __key = self.key[self.__index] __value = self.value[self.__index] result = __key, __value self.__index += 1 return result def __reversed__(self): __result = self.value[:] __result.reverse() return __result def __contains__(self, item): if item in self.value: return True else: return False
这里创建一个模拟字典的类,这个类的内部维护了两个列表,key 负责储存键,value 负责储存值,两个列表通过索引的一一对应,从而达到模拟字典的目的。
首先,我们看看__len__方法,按照协议,这个方法应该返回容器的长度,因为这个类在设计的时候要求两个列表必须等长,所以理论上返回哪个列表的长度都是一样的,这里我选择返回 key 的长度。
然后是__getitem__方法。这个方法会在a['scolia']时,调用a.__getitem__('scolia')。也就是说这个方法定义了元素的获取,我这里的思路是先找到 key 列表中建的索引,然后用索引去 value 列表中找对应的元素,然后将其返回。然后为了进一步伪装成字典,我捕获了可能产生的 ValueError (这是 item 不在 key 列表中时触发的异常),并将其伪装成字典找不到键时的 KeyError。
理论上只要实现了上面两个方法,就可以得到一个不可变的容器了。但是我觉得并不满意所以继续拓展。
__setitem__(self, key, value)方法定义了 a['scolia'] = 'good' 这种操作时的行为,此时将会调用a.__setitem__('scolia', 'good') 因为是绑定方法,所以self是自动传递的,我们不用理。这里我也模拟了字典中对同一个键赋值时会造成覆盖的特性。这个方法不用返回任何值,所以return语句也省略了。
__delitem__(self, key)方法定义了del a['scolia'] 这类操作时候的行为,里面的‘scolia'就作为参数传进去。这里也进行了异常的转换。
只有实现里以上四个方法,就可以当做可变容器来使用了。有同学可能发现并没有切片对应的魔法方法,而事实上,我也暂时没有找到先,这部分内容先搁着一边。
接下来的 __str__ 是对应于 str() 函数,在类的表示中会继续讨论,这里是为了 print 语句好看才加进去的,因为print语句默认就是调用str()函数。
__iter__和next方法在开头的时候讨论过了,这里是为了能让其进行迭代操作而加入的。
__reversed__(self)方法返回一个倒序后的副本,这里体现了有序性,当然是否需要还是要看个人。
__contains__实现了成员判断,这里我们更关心value列表中的数据,所以判断的是value列表。该方法要求返回布尔值。
下面是相应的测试:
a = Foo('scolia', 'good') a[123] = 321 a[456] = 654 a[789] = 987 print a del a[789] print a for x, y in a: print x, y print reversed(a) print 123 in a print 321 in a
•__missing__(self, key)
class Boo(dict): def __new__(cls, *args, **kwargs): return super(Boo, cls).__new__(cls) def __missing__(self, key): return 'The key(%s) can not be find.'% key
测试:
b = Boo() b['scolia'] = 'good' print b['scolia'] print b['123']
当然你也可以在找不到 key 的时候触发异常,具体实现看个人需求。
以上这篇python魔法方法-自定义序列详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

2小时内可以学会Python的基本编程概念和技能。1.学习变量和数据类型,2.掌握控制流(条件语句和循环),3.理解函数的定义和使用,4.通过简单示例和代码片段快速上手Python编程。

Python在web开发、数据科学、机器学习、自动化和脚本编写等领域有广泛应用。1)在web开发中,Django和Flask框架简化了开发过程。2)数据科学和机器学习领域,NumPy、Pandas、Scikit-learn和TensorFlow库提供了强大支持。3)自动化和脚本编写方面,Python适用于自动化测试和系统管理等任务。

两小时内可以学到Python的基础知识。1.学习变量和数据类型,2.掌握控制结构如if语句和循环,3.了解函数的定义和使用。这些将帮助你开始编写简单的Python程序。

如何在10小时内教计算机小白编程基础?如果你只有10个小时来教计算机小白一些编程知识,你会选择教些什么�...

使用FiddlerEverywhere进行中间人读取时如何避免被检测到当你使用FiddlerEverywhere...

Python3.6环境下加载Pickle文件报错:ModuleNotFoundError:Nomodulenamed...

如何解决jieba分词在景区评论分析中的问题?当我们在进行景区评论分析时,往往会使用jieba分词工具来处理文�...

如何使用正则表达式匹配到第一个闭合标签就停止?在处理HTML或其他标记语言时,常常需要使用正则表达式来�...


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

WebStorm Mac版
好用的JavaScript开发工具

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

Atom编辑器mac版下载
最流行的的开源编辑器