有人告诉我,+=效果可能与的标准符号不同i = i +。是否有与以下情况i += 1不同的情况i = i + 1?
这完全取决于对象i。
+=调用__iadd__方法(如果存在- __add__如果不存在则返回),而+调用__add__方法1或在__radd__某些情况下调用方法2。
__add__
__radd__
从API的角度来看,__iadd__应该将其用于就地修改可变对象(返回已变异的对象),而__add__应该返回某些东西的新实例。对于不可变的对象,这两种方法都返回一个新实例,但是__iadd__会将新实例放置在当前名称空间中,并具有与旧实例相同的名称。这就是为什么
__iadd__
i = 1 i += 1
似乎在增加i。实际上,您将获得一个新的整数并将其分配给“顶部” i-丢失对旧整数的一个引用。在这种情况下,i += 1与完全相同i = i + 1。但是,对于大多数易变的物体,情况就不同了:
i += 1
i = i + 1
作为一个具体的例子:
a = [1, 2, 3] b = a b += [1, 2, 3] print a #[1, 2, 3, 1, 2, 3] print b #[1, 2, 3, 1, 2, 3]
相比:
a = [1, 2, 3] b = a b = b + [1, 2, 3] print a #[1, 2, 3] print b #[1, 2, 3, 1, 2, 3]
请注意,在第一个示例中,由于b和a引用相同的对象,因此当我+=在on上使用时b,它实际上发生了变化b(并且也a看到了这种变化-毕竟,它引用的是相同列表)。但是,在第二种情况下,当我这样做时b = b + [1, 2, 3],它将采用b正在引用的列表并将其与新列表连接起来[1, 2, 3]。然后,它将串联的列表存储为b-而不考虑b之前的行。
b = b + [1, 2, 3]
1在表达式中x + y,如果 x.__add__未实现或如果x.__add__(y)返回NotImplemented并且 x和y具有不同的类型,则x + y尝试调用y.__radd__(x)。所以,如果你有
x + y
x.__add__
x.__add__(y)
NotImplemented
y.__radd__(x)
foo_instance += bar_instance
如果Foo没有实现__add__,__iadd__那么这里的结果与
foo_instance = bar_instance.__radd__(bar_instance, foo_instance)
2在表达式中foo_instance + bar_instance,如果的类型是(例如)类型的子类,bar_instance.__radd__将在之前尝试。合理的,这是因为在某种意义上是一种“更高级”的对象不是那么应该得到压倒一切的选项的行为。foo_instance.__add__ bar_instancefoo_instanceissubclass(Bar, Foo)BarFooBarFoo
foo_instance + bar_instance
bar_instance.__radd__
foo_instance.__add__ bar_instancefoo_instanceissubclass(Bar, Foo)BarFooBarFoo