首页 > Python基础教程 >
-
Python中的魔术方法详解(2)
Python的魔术方法很强大,但是用时却需要慎之又慎,了解正确的使用方法非常重要。
创建自定义容器
有很多方法可以让你的Python类行为向内置容器类型一样,比如我们常用的list、dict、tuple、string等等。Python的容器类型分为可变类型(如list、dict)和不可变类型(如string、tuple),可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。
在讲创建自定义容器之前,应该先了解下协议。这里的协议跟其他语言中所谓的"接口"概念很像,它给你很多你必须定义的方法。然而在Python中的协议是很不正式的,不需要明确声明实现。事实上,他们更像一种指南。
自定义容器的magic method
下面细致了解下定义容器可能用到的魔术方法。首先,实现不可变容器的话,你只能定义 __len__ 和 __getitem__ (下面会讲更多)。可变容器协议则需要所有不可变容器的所有,另外还需要 __setitem__ 和 __delitem__ 。如果你希望你的对象是可迭代的话,你需要定义 __iter__ 会返回一个迭代器。迭代器必须遵循迭代器协议,需要有 __iter__(返回它本身) 和 next。
1
|
__len__( self ): |
返回容器的长度。对于可变和不可变容器的协议,这都是其中的一部分。
1
|
__getitem__( self , key): |
定义当某一项被访问时,使用self[key]所产生的行为。这也是不可变容器和可变容器协议的一部分。如果键的类型错误将产生TypeError;如果key没有合适的值则产生KeyError。
1
|
__setitem__( self , key, value): |
当你执行self[key] = value时,调用的是该方法。
1
|
__delitem__( self , key): |
定义当一个项目被删除时的行为(比如 del self[key])。这只是可变容器协议中的一部分。当使用一个无效的键时应该抛出适当的异常。
1
|
__iter__( self ): |
返回一个容器迭代器,很多情况下会返回迭代器,尤其是当内置的iter()方法被调用的时候,以及当使用for x in container:方式循环的时候。迭代器是它们本身的对象,它们必须定义返回self的__iter__方法。
1
|
__reversed__( self ): |
实现当reversed()被调用时的行为。应该返回序列反转后的版本。仅当序列可以是有序的时候实现它,例如对于列表或者元组。
1
|
__contains__( self , item): |
定义了调用in和not in来测试成员是否存在的时候所产生的行为。你可能会问为什么这个不是序列协议的一部分?因为当__contains__没有被定义的时候,如果没有定义,那么Python会迭代容器中的元素来一个一个比较,从而决定返回True或者False。
1
|
__missing__( self , key): |
dict字典类型会有该方法,它定义了key如果在容器中找不到时触发的行为。比如d = {'a': 1}, 当你执行d[notexist]时,d.__missing__['notexist']就会被调用。
实例
下面是书中的例子,用魔术方法来实现Haskell语言中的一个数据结构。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
# -*- coding: utf-8 -*- class FunctionalList: ''' 实现了内置类型list的功能,并丰富了一些其他方法: head, tail, init, last, drop, take''' def __init__( self , values = None ): if values is None : self .values = [] else : self .values = values def __len__( self ): return len ( self .values) def __getitem__( self , key): return self .values[key] def __setitem__( self , key, value): self .values[key] = value def __delitem__( self , key): del self .values[key] def __iter__( self ): return iter ( self .values) def __reversed__( self ): return FunctionalList( reversed ( self .values)) def append( self , value): self .values.append(value) def head( self ): # 获取第一个元素 return self .values[ 0 ] def tail( self ): # 获取第一个元素之后的所有元素 return self .values[ 1 :] def init( self ): # 获取最后一个元素之前的所有元素 return self .values[: - 1 ] def last( self ): # 获取最后一个元素 return self .values[ - 1 ] def drop( self , n): # 获取所有元素,除了前N个 return self .values[n:] def take( self , n): # 获取前N个元素 return self .values[:n] |