1

我只是做了一个 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

我们可以看到 self 的值已经改变了,但是 instance 的值没有。为什么?以及如何解决这个问题?

4

5 回答 5

3

在这种情况下,self是指向调用者实例的指针。虽然你改变了 in 中的指针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.

如果您想实际更改foo_instance(而不仅仅是fv)的值,您应该在其他地方进行,而不是在方法中(这几乎没有概念意义)。

于 2012-10-10T02:00:52.867 回答
1

self只是一个变量。对于常规方法(例如,没有用@staticmethod 或@classmethod ...修饰),传入的对象是实例。但是,在函数内,您可以重新绑定self到您想要的任何内容,但更改不会保留在函数之外,因为赋值只是对右侧的对象进行新引用 - 除非您返回该引用或将它存储在具有更广泛范围的对象上,当函数结束时它将超出范围,再也不会被听到(因为你不再有它的引用/句柄)。

考虑常规函数:

def foo(x):
    x = 2

a = 1
foo(a)
print a #prints 1, not 2

这真的没有什么不同。

于 2012-10-10T02:03:11.633 回答
0

Python 中有一个关于赋值的非常简单的规则。在 Python 中分配一个名称总是只是使该名称现在引用您刚刚分配给它的任何对象。它从来没有真正改变分配之前名称所指的任何对象。

这样做的一个简单结果是,在 lineself = 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仍然引用该原始对象的名称。

这是一个非常,非常好的事情!否则,每当您调用一个函数并向其传递一些对象时,该函数对其自己的局部变量所做的所有赋值都会改变您的变量所指的内容!

于 2012-10-10T02:22:21.080 回答
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)”。

于 2012-10-10T02:03:03.797 回答
0

In try_change_foo_value,self以实例开始,但您在分配时更改它。您可以通过打印idof来检查这一点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

注意ids。

foo_instance.fv: 1
Originally, id(self) = 4299779608
After assignment, id(self) = 4299779680
in change function, self.fv: 2
foo_instance.fv: 1
于 2012-10-10T02:08:05.470 回答