Python 的 Magic Methods 指南(转)
介绍本指南是数月博客的总结。主题是魔术方法。
什么是魔术方法呢?它们是面向对象Python语言中的一切。它们是你可以自定义并添加“魔法”到类中的特殊方法。它们被双下划线环绕(比如__init__或__lt__)。它们的文档也不像它所需要的那么齐备。Python的所有魔术方法都在Python文档的同一区域,但它们的使用分散,组织松散。而且文档的这部分区域中几乎没有一个示例(这很有可能是设计好的,因为在语法参考里它们都很详尽,但伴随的是枯燥的语法描述等等)。
因此,为了解决Python文档中我认为的缺陷,我想提供一些更简单直白的表述——示例驱动型的Python魔术方法文档。我从每周的博客开始,现在我已经完成了,并把它们合到了一起。
我希望你能喜欢它。把它作为一个教程、复习或参考使用;它希望能成为一个Python魔术方法用户友好的指导。
构造与初始化
我们每个知道的最基本的“魔法”方法是__init__。一种让我们在初始化一个类时定义一些行为。然而当我执行 x = SomeClass(), __init__ 不是第一个被执行的。事实上,第一被执行的的方法是__new__,它会创建一个实例,然后在构造器创建时传递一些参数。在一个object的生命周期的另一端的方法是__del__。让我们仔细看看这3个“魔法”方法:
[*] __new__(cls, [...)
[*] __new__ 是一个类的初始化过程中第一个被执行的方法。它创建了类,然后把一些参数传递给__init__。__new__ 很少被使用,特别是当我们用一些不可变类型的子类时(像tuple ,string),我不想关心__new__的太多的细节,因为那是没有用的。但它有它存在的意义。更多详细的请看 in the Python docs.
[*] __init__(self, [...)
[*] 类的构造器,当初始构造方法被执行(例如,我们执行 x = SomeClass(10,'foo')),__init__ 就会获得 10 和 ‘foo’ 作为参数。__init__ 在python类的定义中经常被使用
[*] __del__(self)
[*] 若果 __new__ 和 __init__ 形成一个类的构造函数,__del__ 是就是析构函数。它不实现语句 del x 的行为(这样代码就不会转换为 x.__del__())。它定义了一个被垃圾回收的行为。它在类消除的时后需要做一些额外的行为时是非常有用的,就像 sockets 和 file 类。注意,当编译器还在运行,如果类还存活着,这里不能确保__del__一定会被执行。所以__del__ 不能替代一些良好的编程习惯(比如连接用完了将其关掉),事实上__del__很少被使用,因为它的调用是非常不稳定的;请谨慎使用!
把他们合起来后,这里就是一个 __init__ 和 __del__ 使用的例子:
01from os.path import joinclass FileObject:
02 '''Wrapper for file objects to make sure the file gets closed on deletion.'''
03
04 def __init__(self, filepath='~', filename='sample.txt'):
05 # open a file filename in filepath in read and write mode
06 self.file = open(join(filepath, filename), 'r+')
07
08 def __del__(self):
09 self.file.close()
10 del self.file
定义自己的类中的操作
我们使用Python的“魔法”方法最大得优势之一是它提供了一种简单的方法去定义类的行为,比如 built-in 类型。这就意味着你可以避免丑陋的,违反直觉的,非标准化的基本操作方法。在一些语言中,他们通常这样写:
1if instance.equals(other_instance):
2 # do something
当让Python中也可以这么做,但是这增加了混乱和不必要的冗余。不同的类库中的相同的方法可能会用不同名字,使得使用者做了太多不必要的操作。相比之下“魔法”方法是强大的,我们可以使用它定义一个方法代替上面的例子(__eq__ , 在这个例子中):
1if instance == other_instance:
2 #do something
这是“魔法”方法强大用途的一部分。他们绝大部分让我们定义操作的意义,以至于我们可以使用他们在我们自己的类中就像使用built in 类型。
魔法比较方法
python拥有大量用于实现对象与对象之间比较的魔法方法,这些对象使用运算符进行直观比较而不是难看的方法调用。同时它也提供了一种方法去重载python默认的对象比较行为(比较引用)。这里有一个这些方法和它们做了什么事情的列表:
[*] __cmp__(self, other)
[*] __cmp__ 是比较方法里面最基本的的魔法方法。实际上它实现了所有的比较运算符(如 other时返回正整数。通常来说最好是定义每个你需要的比较方法而不是一次性定义所有的比较方法,但是__cmp__是一个消除重复性的良途,并且当你有很多比较方法需要用相类似的条件去实现的时候这能让代码变得清晰。
[*] __eq__(self, other)
[*] 定义相等符号的行为,==
[*] __ne__(self,other)
[*] 定义不等符号的行为,!=
[*] __lt__(self,other)
[*] 定义小于符号的行为,<
[*] __gt__(self,other)
[*] 定义大于符号的行为,>
[*] __le__(self,other)
[*] 定义小于等于符号的行为,=
例如,假设一个类是一个单词模型。我们可能要按字典比较单词(按字母),这是比较字符串默认行为,但我们也可能需要基于其他一些标准来做比较,比如按长度、或字节数量等。在下面的例子中,我们将比较长度。下面是实现:
class Word(str):
'''Class for words, defining comparison based on word length.'''
def __new__(cls, word):
# Note that we have to use __new__. This is because str is an immutable
# type, so we have to initialize it early (at creation)
if ' ' in word:
print "Value contains spaces. Truncating to first space."
word = word[:word.index(' ')] # Word is now all chars before first space
return str.__new__(cls, word)
def __gt__(self, other):
return len(self) > len(other)
def __lt__(self, other):
return len(self) < len(other)
def __ge__(self, other):
return len(self) >= len(other)
def __le__(self, other): return len(self)
页:
[1]