使用特殊方法和仅定义普通类方法有什么区别?我正在阅读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)
对于这些特殊方法中的每一种,为什么我不能只做一个普通的方法,它们有什么不同呢?我想我只需要一个我找不到的基本解释,谢谢。
答案 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
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)
,这意味着我不能再假装对象是一个函数。