Python 的 Magic Methods 指南(2)

定义自己的类中的操作

我们使用Python的“魔法”方法最大得优势之一是它提供了一种简单的方法去定义类的行为,比如 built-in 类型。这就意味着你可以避免丑陋的,违反直觉的,非标准化的基本操作方法。在一些语言中,他们通常这样写:

if instance.equals(other_instance):
    # do something

当让Python中也可以这么做,但是这增加了混乱和不必要的冗余。不同的类库中的相同的方法可能会用不同名字,使得使用者做了太多不必要的操作。相比之下“魔法”方法是强大的,我们可以使用它定义一个方法代替上面的例子(__eq__ , 在这个例子中):

if instance == other_instance:
    #do something

这是“魔法”方法强大用途的一部分。他们绝大部分让我们定义操作的意义,以至于我们可以使用他们在我们自己的类中就像使用built in 类型。

用于比较的“魔法”方法

Python有用于实现整个类之间的比较的“魔法方法”,这些方法设计的很直观,没有一点不方便调用。而且他们还提供重载Python默认的类之间的比较行为的方法。这里列出他们的列表和他们的功能:

__cmp__(self, other)

__cmp__ 是关于比较的“魔法”方法中最基础的方法。其实它已经实现了所有关于比较的操作(<, ==, !=, 等等.),但是有时这并不是我们想要的(例如,如何判断一个类的实例是否等于另一个实例,或是如何判断是否一个实例大于另一个实例)。__cmp__ 方法,如果 self < other ,它会返回一个负整数。如果 self == other , 它会返回 0 。如果self > other ,它会返回正整数。通常定义一次要比每次需要比较的时候都定义要好的多,事实上 __cmp__ 是一种非常好的方法在所有的比较方法有相似的逻辑的时候,它让我们减少重复和提高了代码清晰度。

__eq__(self, other)

定义等于操作的行为,==。

__ne__(self, other)

定义不等于操作的行为。!=。

__lt__(self, other)

定义小于操作的行为,<。

__gt__(self, other)

定义大于操作的行为,>。

__le__(self, other)

定义小于等于操作的行为,<=。

__ge__(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) <= len(other)

现在,我们可以创建两个单词(通过使用Word('foo')和Word('bar'))然后依据长度比较它们。但要注意,我们没有定义__eq__和__ne__,因为这样会导致其他一些奇怪的行为(尤其是Word('foo')==Word('bar')会判定为true),它不是基于长度相等意义上的测量,所以我们回归到字符平等意义上的实现。

现在需要留心啦——为达到预期的比较效果你不需要为每个比较定义魔术方法。如果你只定义__eq__以及其他的(比如__gt__,__lt__等),标准库已经在functools模块里为我们提供了一个类修饰器,它可以定义所有的富特性比较方法。这个特性只有在Python 2.7中才是可用的,但如果你碰巧的话这可以节省大量的时间和精力。你可以通过将@total_ordering放置在类定义前面来使用它。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/cb1b2f78dd9df2088d69413cabe7ac94.html