有人可以帮我理解特殊方法与普通方法吗?

时间:2013-10-22 04:40:43

标签: python class methods

使用特殊方法和仅定义普通类方法有什么区别?我正在阅读this网站,其中列出了很多网站。

例如,它提供了这样的类。

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)

对于这些特殊方法中的每一种,为什么我不能只做一个普通的方法,它们有什么不同呢?我想我只需要一个我找不到的基本解释,谢谢。

5 个答案:

答案 0 :(得分:3)

这是一种pythonic方式:

word1 = Word('first')
word2 = Word('second')
if word1 > word2:
    pass

而不是直接使用比较器方法

NotMagicWord(str):
    def is_greater(self, other)
        return len(self) > len(other)

word1 = NotMagicWord('first')
word2 = NotMagicWord('second')
if word1.is_greater(word2):
    pass

和所有其他魔术方法一样。例如,您可以使用内置len函数定义__len__方法来告诉python它的长度。所有魔术方法都将被隐式调用,而标准操作如二元运算符,对象调用,比较和许多其他操作。 A Guide to Python's Magic Methods非常好,阅读它,看看你可以给你的对象带来什么样的行为。它类似于C ++中的运算符重载,如果你熟悉它。

答案 1 :(得分:2)

在代码中使用比较运算符时,会调用__gt__之类的方法。写点像

value1 > value2

相当于写作

value1.__gt__(value2)

答案 2 :(得分:1)

特殊方法由Python语言的其余部分专门处理。例如,如果您尝试将两个Word个实例与<进行比较,则会调用__lt__ Word方法来确定结果。

答案 3 :(得分:1)

当您使用<==>来比较对象时,会调用魔术方法。 functools有一个名为total_ordering的帮助程序,如果您只定义__eq____gt__,则会填写缺少的比较方法。

由于str已经定义了所有比较操作,因此如果您想利用total_ordering

,则必须将它们添加为mixin
from functools import total_ordering

@total_ordering
class OrderByLen(object):
    def __eq__(self, other):
        return len(self) == len(other)
    def __gt__(self, other):
        return len(self) > len(other)


class Word(OrderByLen, 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)


print Word('cat') < Word('dog')         # False
print Word('cat') > Word('dog')         # False
print Word('cat') == Word('dog')        # True
print Word('cat') <= Word('elephant')   # True
print Word('cat') >= Word('elephant')   # False

答案 4 :(得分:1)

Python使用“魔术方法”来实现其许多底层结构。

例如,假设我有一个简单的类来表示(x, y)坐标对:

class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

因此,__init__将是其中一个“魔术方法”的示例 - 它允许我通过简单地执行Point(3, 2)来自动初始化类。我可以通过创建自己的“init”函数而不使用魔术方法来编写它,但是我需要进行显式方法调用来初始化我的类:

class Point(object):
    def init(self, x, y):
        self.x = x
        self.y = y
        return self


p = Point().init(x, y)

让我们再看一个例子 - 如果我想比较两个点变量,我可以这样做:

class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

这让我可以通过p1 == p2来比较两点。相反,如果我将其设为正常的eq方法,则必须通过p1.eq(p2)更加明确。

基本上,魔术方法是Python以一种允许程序员轻松定制的方式实现其大量语法糖的方法。

例如,我可以通过实现__call__来构造一个假装成函数的类:

class Foobar(object):
    def __init__(self, a):
        self.a = a

    def __call__(self, b):
        return a + b

f = Foobar(3)
print f(4)  # returns 7

如果没有魔术方法,我必须手动执行f.call(4),这意味着我不能再假装对象是一个函数。