我目前正在尝试了解在自定义类上使用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+c
Python时检查/执行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)
给出NotImplemented
为1
是的int
类型和add
的int
类不支持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()。事实证明,这就是方法。 我认为这两个陈述是等效的。即使忽略这一点,我也可以理解将字符串追加到列表的方式(因为字符串只是字符数组),但是