在实例方法中改变类实例

7 投票
3 回答
5138 浏览
提问于 2025-04-15 18:28

有没有人知道怎么让下面的代码正常工作呢?

class Test(object):

    def __init__(self, var):
        self.var = var

    def changeme(self):
        self = Test(3)

t = Test(1)
assert t.var == 1
t.changeme()
assert t.var == 3

像下面这样的写法,使用在更复杂的对象上(比如Django模型),这样可以快速切换实例所指向的数据库条目,这样安全吗?

class Test(object):

    def __init__(self, var):
        self.var = var

    def changeme(self):
        new_instance = Test(3)
        self.__dict__ = new_instance.__dict__

t = Test(1)
assert t.var == 1
t.changeme()
assert t.var == 3

3 个回答

2

之前的代码是可以工作的,但它的作用不大,因为它只是把名为 'self' 的对象替换掉了,这个替换只在 changeme() 这个函数的范围内有效。Python 中的名字并不是固定在某个值上的,它们总是和它们所在的范围或命名空间有关。

如果你想实现你想要的功能,你需要访问类外部的一个名字,然后可以在类内部对这个名字进行赋值:

class Test:
  def changeme(self):
    global myclass
    myclass = Test(3)

myclass = Test(2)
myclass.changeme()
print myclass # 3

这基本上就是把名字 'myclass' 指向了一个新的实例。它并不会像你想的那样“覆盖”第一个实例。旧的实例仍然存在,除非在其他地方被引用,否则它会被垃圾回收。

2

不,可以说不是。

不过,确实可以更改,但也不要这么做。

7

self = Test(3) 其实是在重新给本地的名字 self 赋值,但外面的人看不出来有什么变化。

self.__dict__ 赋值(除非你在谈论有 __slots__ 的实例,或者是一些复杂的类)通常是可以的,使用 self.__init__(3) 来重新初始化这个实例也是可以的。不过,我更喜欢有一个专门的方法 self.restart(3),这个方法知道它是在一个已经初始化过的实例上被调用的,并且会做一些特别的处理来应对这种特殊情况。

撰写回答