我只是做一个foo课来解释我的意思:
class Foo:
def __init__(self, fakevalue):
self.fv = fakevalue
@staticmethod
def make_a_foo():
return Foo(2)
def try_change_foo_value(self):
self = Foo.make_a_foo()
print "in change function, self.fv:", self.fv
if(__name__ =='__main__'):
foo_instance = Foo(1)
print "foo_instance.fv:", foo_instance.fv
foo_instance.try_change_foo_value()
print "foo_instance.fv:", foo_instance.fv
我期待:
foo_instance.fv: 1
in change function, self.fv: 2
foo_instance.fv: 2
但结果是:
foo_instance.fv: 1
in change function, self.fv: 2
foo_instance.fv: 1
我们可以看到自我值已经改变,但实例值没有改变。 为什么?以及如何解决这个问题?
答案 0 :(得分:3)
在这种情况下,self
是指向调用者实例的指针。虽然您更改了try_change_foo_value
中的指针,但它就像更改函数中的参数一样:它在方法之外没有任何影响。
为了澄清这一点,你可以考虑
a.try_change_foo_value()
作为Foo.try_change_foo_value(a)
的简写。这应该很明显,当您更改self
时,您正在更改本地变量,而调用方a
保持不变。
要修复它,你应该
def try_change_foo_value(self):
self.fv = 2
但正如mgilson指出的那样,仅仅说foo_instance.fv = 2
就更像Pythonic了。
如果你想真正改变foo_instance
的价值(而不仅仅是fv
),你应该在其他地方改变,而不是在方法中(这在概念上没什么意义)。
答案 1 :(得分:1)
self
只是一个变量。对于常规方法(例如,未使用@staticmethod或@classmethod ...装饰),传入的对象是实例。但是,在函数中,您可以将self
重新绑定到您想要的任何内容,但更改不会保留在函数之外,因为赋值只是在右侧对对象进行新的引用 - 除非你返回那个引用或者将它存储在一个范围更广的对象上,当函数结束时再也听不到它会超出范围(因为你不再有引用/句柄)。
考虑常规功能:
def foo(x):
x = 2
a = 1
foo(a)
print a #prints 1, not 2
这真的没什么不同。
答案 2 :(得分:0)
您正在更改方法try_change_foo_value中的容器“self”。请记住,self作为参数传入,这意味着您可以更改变量self内部的引用;但是您无法更改调用者传递给您的引用。在Java中思考。
public void changeIt(Foo foo) {
foo = new Foo(2);
}
如果我打电话
Foo bar = new Foo(1);
.changeIt(bar);
我可以期待bar仍然是“新的Foo(1)。”
答案 3 :(得分:0)
在try_change_foo_value
中,self
以实例开头,但您在分配时更改它。您可以打印id
的{{1}}来查看此内容。
self
请注意class Foo:
def __init__(self, fakevalue):
self.fv = fakevalue
@staticmethod
def make_a_foo():
return Foo(2)
def try_change_foo_value(self):
print 'Originally, id(self) = %s' % id(self)
self = Foo.make_a_foo()
print 'After assignment, id(self) = %s' % id(self)
print "in change function, self.fv:", self.fv
if __name__ =='__main__':
foo_instance = Foo(1)
print "foo_instance.fv:", foo_instance.fv
foo_instance.try_change_foo_value()
print "foo_instance.fv:", foo_instance.fv
s。
id
答案 4 :(得分:0)
在Python中有一个关于赋值的非常简单的规则。分配给Python中的名称始终只是使该名称现在引用您刚刚分配给它的任何对象。 从不实际上会改变分配前名称所指的任何对象。
这样做的一个简单结果是,在self = Foo.make_a_foo()
行中,完全无关之前的self
是什么。我们谈论类和实例的事实与此无关。无论之前是self
,我们现在只需要引用新self
对象的名称Foo
。
请记住,名称只是一个让您获得对象的句柄。给定对象可以在任何给定时刻由0,1或多个名称引用。赋值是一种影响名称而非对象的操作。您无法通过更改引用它的名称来更改对象。
foo_instance = Foo(1)
print "foo_instance.fv:", foo_instance.fv
foo_instance.try_change_foo_value()
print "foo_instance.fv:", foo_instance.fv
当上述调用foo_instance = Foo(1)
时,会导致名称foo_instance
引用新对象。当您调用foo_instance.try_change_foo_value()
时,该方法范围内的同名对象将获得一个额外的名称self
。当您更改该名称以引用新对象时,它对名称foo_instance
上仍然引用该原始对象的原始对象或没有影响。
这是一件非常好的事情!否则,无论何时调用函数并将其传递给某些对象,函数对其自身局部变量的所有赋值都将改变变量所指的内容!