Python中的__add__和__concat__有什么区别?

15
Python的标准操作符列表中包括__add__(a, b)__concat__(a, b)。它们都通常由a + b调用。我的问题是,它们之间有什么区别?是否有场景会使用其中一个而不是另一个?是否有任何理由在单个对象上定义两者?
这是我找到的文档中提到的方法。
编辑:增加了这篇文档的怪异之处:
引用:

最后,序列类型应通过定义下面描述的方法 __add__(), __radd__(), __iadd__(), __mul__(), __rmul__()__imul__() 实现加法(指连接)和乘法(指重复); 它们不应该定义__coerce__()或其他数值运算符。


根据你提供的文档,一个是用于数字,另一个是用于序列。 - Craicerjack
2
请注意,__concat__ 不像 __add__ 一样是一个“魔法方法”:https://docs.python.org/2/reference/datamodel.html - jonrsharpe
@jonrsharpe - 你为什么说其中一个是“魔术方法”,而另一个不是呢?这是官方术语吗?我认为这只是人们编造的一个术语,因为在口头交流中,用“魔法<方法>”这个词比用“下划线下划线<方法>下划线下划线”更容易。此外,看了你链接的文档后,我发现了一句话,这让事情变得更加混乱了。我编辑了我的问题并加入了这句话。 - ArtOfWarfare
@ArtOfWarfare “魔术方法”在官方上被称为“特殊方法”,指的是您可以为类型实现的方法,以提供运算符和其他语法功能的内置功能。一般来说,双下划线方法只是受到名称混淆的影响,并且有时用于私有成员。 - poke
@jonrsharpe - 好的,重要的是__concat__实际上没有定义在任何对象上 - 这就是为什么你说它不是一个魔术方法。如果您发布一个回答,概述了我的困惑主要源于operator模块使用与魔术方法名称相同的方法名称,那么我会接受这种解释。 - ArtOfWarfare
显示剩余3条评论
3个回答

13
如果你查看 operator 模块的源代码(addconcat),你会发现这些函数的定义:
def add(a, b):
    "Same as a + b."
    return a + b

def concat(a, b):
    "Same as a + b, for a and b sequences."
    if not hasattr(a, '__getitem__'):
        msg = "'%s' object can't be concatenated" % type(a).__name__
        raise TypeError(msg)
    return a + b

因此,除了 concat 函数需要使用序列类型外,实际上没有任何区别。这两个函数都使用 + 运算符,其效果取决于所添加的类型。

通常情况下,使用 operator 模块 并没有太多用处。该模块主要在您需要传递执行操作的函数时使用,例如传递给函数式函数如mapfilterreduce 等。但通常情况下,您可以直接使用 + 运算符。

至于下划线函数(__add____concat__),它们只是 别名

__add__ = add
__concat__ = concat

但这些当然与用于重载自定义类型运算符的特殊方法无关。它们是与这些特殊方法同名的函数,可能是为了使它们看起来类似。请注意,对象上没有特殊的__concat__方法。
在自定义类型上实现__add__将影响运算符模块函数的工作方式,例如:
>>> class Example:
        def __init__ (self, x):
            self.x = x
        def __repr__ (self):
            return 'Example({})'.format(self.x)
        def __add__ (self, other):
            return Example(self.x + other.x)

>>> a = Example(2)
>>> b = Example(4)
>>> operator.add(a, b)
Example(6)
>>> a + b
Example(6)

正如您所看到的,operator.add 将使用特殊方法 Example.__add__ 的实现;但原因是 operator.add 的实现只是使用了 + 运算符(其行为由特殊的 __add__ 方法明确定义)。

很好,operator 模块对于将操作符传递给 reduce() 函数非常有用。 - fferri
1
@mescalinum 这就是我写的:“当你需要传递执行某个操作的函数时,该模块通常用得比较多。” - poke
好的。我只是想提一下reduce(),因为函数式编程太酷了 :) - fferri
@mescalinum,我为你添加了一些功能示例;) - poke

3
  • operator.__add__(a, b): 返回 a + b,其中ab数字 *。
  • operator.__concat__(a, b): 返回 a + b,其中ab序列

它们之间有什么区别呢?

例如,您无法连接整数:

>>> operator.__concat__(2,3)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'int' object can't be concatenated

  • 实际上,__add__(a, b) 只是执行 a + b 操作,因此它也适用于序列。

0
根据文档,

operator.__add__(a, b) 返回 a + b,其中 a 和 b 是数字。

operator.__concat__(a, b) 返回 a + b,其中 a 和 b 是序列。

operator.__add__(a, b): 它将尝试执行 a + b 并给出结果。 例如。
operator.__add__(1,2)  # performs 1 + 2
3

operator.__add__('a','b') # performs 'a'+'b'
'ab'

operator.__concat__(a, b):

这里,它将检查 a 是否具有属性 __getitem__。如果它没有 __getitem__ 属性,则会引发异常,否则尝试执行 a + b

例如:

在数字上执行此操作时,它将引发异常。

operator.__concat__(1,2)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError:'int' object can't be concatenated

当对两个字符串执行时,它执行字符串连接。

operator.__concat__('a','b')
'ab'

行为实际上有所不同/限制吗?operator.add("a","b")产生了预期的结果("a"+"b"=>"ab"),文档说两者都“返回a + b”。 - user2864740
请注意,OP所谈论的是“operator”模块,而不是特殊方法。请注意,“__concat__”方法不存在。 - poke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接