我有一个简单的类编码为:
class test():
def __init__(self, a):
self.a = a
def __add__(self, other):
# returns a test object which is the sum of self and other
return test(self.a + other.a)
def double(self):
print()
print ('meanwhile inside test.double() ...')
operand = test(self.a) # a new test object similar to self
print(' self: ', self)
print(' operand:', operand)
self += operand
print(' -> self: ', self)
def __str__(self):
return '[> %r <]' % self.a
S1 = test(1)
S2 = test(2)
S = S1 + S2
print('sums do work : S = S1 + S2 =', S1, '+', S2, '=', S)
S.double()
print()
print('but S doubled =', S, '??')
输出结果为:
sums do work : S = S1 + S2 = [> 1 <] + [> 2 <] = [> 3 <]
meanwhile inside test.double() ...
self: [> 3 <]
operand: [> 3 <]
-> self: [> 6 <]
but S doubled = [> 3 <] ??
那么,我怎样才能实现这种行为(即,当从被调用的方法返回时,自我实例将被正确更新)而不必复制所有属性(在实际代码中这些属性很多,并且每次都需要添加属性以重新检查代码以确保复制完成)?
答案 0 :(得分:0)
self
只是一个变量,是对实例的引用。将它绑定到另一个对象只会将设置为一个引用,而不是对该实例的任何其他引用。您无法替换其他参考。返回新实例和double()
执行此操作的文档(以便调用方必须重新绑定其引用),或者更新self.a
。
返回新对象:
class test():
# ...
def double(self):
return self + self # no need to create a new instance here
S = S.double()
或就地更新:
class test():
# ...
def double(self):
self.a *= 2
您选择哪一个取决于您是否希望test()
个实例是可变的。不可变对象将始终返回操作的新实例,可变对象应该就地应用操作。
您可能想要了解Python名称,我建议Ned Batchelder's Facts and myths about Python names and values。
答案 1 :(得分:0)
最简单的方法是直接在a
属性上操作:
def double(self):
self.a *= 2
这样做就是在原地改变self
。
__iadd__
使用self +=
目前不会就地更新self
,因为__add__
函数(正确)会返回新的test
对象。如果由于某种原因希望不直接对a
方法中的double
属性进行操作,则可以添加被调用的__iadd__
方法(而不是__add__
存在)使用+=
时:
def __iadd__(self, other):
self.a += other.a
def double(self):
self += self
此外,我遗漏了operarand
的创建,因为完全允许other
实际上与self
相同。
答案 2 :(得分:0)
所以最后这段代码按预期工作
from copy import deepcopy
class test():
def __init__(self, a):
self.a = a
def __iadd__(self, other):
# this is the actual implementation of the sum of 2 objects
self.a += other.a
return self # <== required see comment below
def __add__(self, other):
# note: in the code I'm writing this is a relatively complex
# operation. So I would like to avoid to have it written in
# two places. So the actual implementation for the sum happens
# in __iadd__
r = deepcopy(self)
r += other # <== implemented as r = r.__iadd__(other) behind the scenes
return r # this is why the return self in __iadd__ is necessary !
def double(self):
print()
print ('meanwhile inside test.double() ...')
operand = test(self.a) # a new test object similar to self
print(' self: ', self)
print(' operand:', operand)
self += operand
print(' -> self: ', self)
def __str__(self):
return '[> %r <]' % (self.a)
S1 = test(1)
S2 = test(2)
S = S1 + S2
print('sums do work : S = S1 + S2 =', S1, '+', S2, '=', S)
S.double()
print()
print('and S doubled =', S, '!!')
这似乎按预期工作......
sums do work : S = S1 + S2 = [> 1 <] + [> 2 <] = [> 3 <]
meanwhile inside test.double() ...
self: [> 3 <]
operand: [> 3 <]
-> self: [> 6 <]
and S doubled = [> 6 <] !!
注1:__iadd
__需要返回自我,否则无效!
注2:我不确定我是否做得对(即在答案集中添加更多问题)......但我认为如果我在上面的问题中添加这个问题,那么讨论的流程就很难了跟随。