当前位置: 首页 > 面试题库 >

a + b和a .__ add __(b)之间的区别

贺立果
2023-03-14
问题内容

我目前正在尝试了解在自定义类上使用a+b和之间的区别a.__add__(b)。有许多网站说使用’+’运算符会导致使用特殊方法__add__-到目前为止还不错。

但是,当我运行以下示例时,我得到两个不同的结果。

class C:  
  def __add__(self, other):
    print("C.__add__", self, other)
    return "result"  
  def __radd__(self, other):
    print("C.__radd__", self, other)    
    return "reversed result"

c = C()
print(1+c)
print()
print(1 .__add__(c))
print(int.__add__(1,c))

结果:

C.__radd__ <C object at 0x7f60b92e9550> 1
reversed result

NotImplemented
NotImplemented

现在,据我了解,执行1+cPython时检查/执行int__add__方法-发现没有实现添加int和C对象的实现-返回NotImplemented-
这使Python知道检查对象C__radd__并执行其中的代码。

为什么1+c执行__radd__代码会导致结果,但是其他两个版本只是返回NotImplemented而未检查__radd__


问题答案:

a+b等价于import operator;operator.add(a,b)。首先调用a.__add__(b),然后根据需要调用b.__radd__(a)。但是ifsubclass(type(b),type(a)),则先b.__radd__(a)被称为。

根据有关“特殊”方法的文档:

  • 关于__add__()

__add__()被调用以实现二进制算术“ +”运算。例如,要评估表达式x +
y,其中x是具有__add__()方法的类的实例x.__add__(y)

如果这些方法之一不支持使用提供的参数进行的操作,则应返回 NotImplemented

  • 关于__radd__()

仅当左操作数不支持相应的操作并且操作数是不同类型时,才调用这些函数。例如,如果返回NotImplemented
__radd__()y.__radd__(x)则调用求值x + y的表达式,其中y是具有方法的类的实例x.__add__(y)

如果右操作数的类型是左操作数类型的子类,并且该子类为操作提供了反映的方法,则将在左操作数的非反射方法之前调用此方法。此行为允许子类覆盖其祖先的操作。

根据行为举例说明:

情况1:

>>> print 1+c
('C.__radd__', <__main__.C instance at 0x7ff5631397a0>, 1)
reversed result

radd仅当左操作数不支持相应的操作并且操作数是不同类型时,才调用这些函数。在这种情况下,1不支持类的添加,因此,它会退回到类的__radd__()功能C。如果__radd__没有在C()课堂上实施,它将退回到__add__()

情况2:

>>> 1 .__add__(c)
NotImplemented
>>> c .__add__(1)
('C.__add__', <__main__.C instance at 0x7ff563139830>, 1)
'result'

1 .__add__(c)给出NotImplemented1是的int类型和addint类不支持add使用C类对象。但是c .__add(1)运行是因为C()类支持。

情况3:

>>> int.__add__(1, c)
NotImplemented
>>> C.__add__(c, 1)
('C.__add__', <__main__.C instance at 0x7ff5610add40>, 1)
'result'

类似于case 2。但是在这里,调用是通过带有第一个参数的类作为该类的对象进行的。行为将是相同的。

情况4:

>>> int.__add__(c, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor '__add__' requires a 'int' object but received a 'instance'
>>> C.__add__(1, c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method __add__() must be called with C instance as first argument (got int instance instead)

反之亦然case 3。从堆栈跟踪中可以清楚地看出,__add__将调用类的对象作为第一个参数,否则将导致异常。



 类似资料:
  • 问题内容: 正如我在标题中提到的 a + = b和a = + b以及a 和 a有什么区别?我有点困惑 问题答案: 相当于 相当于 且两者都增加1。不同之处在于,返回的是增量之前的值,而返回的是增量之后的值。 那是:

  • 问题内容: 这是我的第一个问题,我开始学习Python。之间有什么区别: 和 在下面的示例中编写时,它显示不同的结果。 和 问题答案: 在中,在将右侧的表达式赋给左侧之前对其求值。因此,它等效于: 在第二个示例中,运行时已更改的值。因此,结果是不同的。

  • 我尝试了一些代码在Java中交换两个整数,而不使用第三个变量,即使用XOR。 以下是我尝试的两个交换函数: 该代码产生的输出如下: 我很想知道,为什么会有这样的说法: 和这个不一样?

  • 问题内容: 我尝试了一些代码,使用XOR在Java中交换两个整数而不使用第三个变量。 这是我尝试的两个交换函数: 这段代码产生的输出是这样的: 我很好奇,为什么这样说: 与这个不同吗? 问题答案: 问题是评估的顺序: 参见JLS第15.26.2节 首先,对左操作数求值以产生一个变量。 如果该评估突然完成,则赋值表达式由于相同的原因而突然完成;右边的操作数不会被评估,并且不会发生赋值。 否则,将保存

  • 问题内容: 在采访中有人问我以下问题。 每行执行一次后b的值是多少?每行输出为0。 为什么输出不为0、1、2、3? 问题答案: 在Java中,表达式 相当于 因此,结果。 (在其他一些语言中,完全相同的表达式具有未指定的行为。请参见未定义的行为和顺序点。)

  • 问题内容: 今天,我发现了python语言一个有趣的“功能”,这让我感到非常悲伤。 那个怎么样?我以为两者是等同的!更糟糕的是,这是我调试时遇到的麻烦的代码 WTF!我的代码中包含列表和字典,并且想知道我到底怎么把dict的键附加到列表上而又没有调用.keys()。事实证明,这就是方法。 我认为这两个陈述是等效的。即使忽略这一点,我也可以理解将字符串追加到列表的方式(因为字符串只是字符数组),但是