0

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

例如,它提供了这样的课程。

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)

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

4

5 回答 5

4

这是一种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++ 中的运算符重载。

于 2013-10-22T04:50:07.633 回答
2

__gt__当您在代码中使用比较运算符时,会调用类似的方法。写类似的东西

value1 > value2

相当于写

value1.__gt__(value2)
于 2013-10-22T04:47:30.570 回答
1

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

于 2013-10-22T04:47:50.370 回答
1

使用<,比较对象==时会调用魔术方法。如果您只定义and ,则有一个名为的助手将填充缺少的比较方法。>functoolstotal_ordering__eq____gt__

因为str已经定义了所有的比较操作,所以如果你想利用它们,就必须将它们添加为 mixintotal_ordering

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
于 2013-10-22T04:50:51.720 回答
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),这意味着我不能再假装对象是一个函数。

于 2013-10-22T04:52:08.243 回答