Python 如果我使用保存现有实例的同一变量为类的第二个实例添加属性,会发生什么情况?
除了举例,我不知道如何提问 假设我有一门课:Python 如果我使用保存现有实例的同一变量为类的第二个实例添加属性,会发生什么情况?,python,class,variables,instantiation,Python,Class,Variables,Instantiation,除了举例,我不知道如何提问 假设我有一门课: class Foo(): pass 我创建了它的一个实例: foo = Foo() ... 然后,作为程序的一部分,我用相同的名称重新创建相同的实例(重新启动游戏,但在另一个名为Bar的单独类中保留总分数) (我不知道正确的术语)我没有编写任何代码来消除第一个实例。第一个实例是否被删除或覆盖?它似乎适用于一个小程序。如果我这样做很多次,我会遇到麻烦吗?基本(可能足够)答案: 变量foo被分配给一个新实例,该实例对前一个实例一无所知
class Foo():
pass
我创建了它的一个实例:
foo = Foo()
...
然后,作为程序的一部分,我用相同的名称重新创建相同的实例(重新启动游戏,但在另一个名为Bar的单独类中保留总分数)
(我不知道正确的术语)我没有编写任何代码来消除第一个实例。第一个实例是否被删除或覆盖?它似乎适用于一个小程序。如果我这样做很多次,我会遇到麻烦吗?基本(可能足够)答案:
变量foo
被分配给一个新实例,该实例对前一个实例一无所知。
它基本上与:
a = 1
a = 2
在某个时刻(可能早于晚),foo
的旧实例将被垃圾收集(除非您在其他地方仍然有对它的引用)
理解这一点的简单方法是,foo
名称只是指向实际对象的指针。如果foo
指向一个新对象,则foo
指向一个新对象,句号
一个相关的细节:单例模式
有一些设计模式(人们会想到的singleton
)可能会改变这种行为
基本上,当您执行Foo()
时,Foo.\uuuuuu new\uuuuu
类方法决定您将得到什么
这个方法可以构建为总是返回您创建的第一个实例,但这显然偏离了主题
下面是一个示例实现:
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
Foo()
时,将创建一个新实例(按顺序调用类方法\uuuuuu new\uuuuu
和实例方法\uuuuuuuu init\uuuuuuu
)\uu del\uu
)您最终将一个新的Foo对象绑定到
Foo
,而旧的Foo
对象将丢失一个引用。如果一个对象没有任何引用,那么它将在下一次垃圾收集时被收集。第二次垃圾收集将覆盖第一次垃圾收集。(它取代模块的全局字典中的名称,所有全局变量、函数和类都存储在该字典中)
但是,您创建的foo=foo()将从创建时起继续使用原始实现,直到您创建新的foo=foo()。1stfoo=foo()
:
它创建一个新的实例对象并将其分配给foo
,请参见foo
只是对foo()返回的对象的引用
第二个foo=foo()
它创建一个新的实例对象并将其分配给foo
,而以前的实例对象foo()
被垃圾收集,因为没有指向它的变量
例如:
>>> class Foo:
... pass
...
>>>
>>> foo=Foo()
>>> id(foo) #foo points to an object with id 3077166220L
3077166220L
>>> foo=Foo() #now foo points to some other object and the object with id 3077166220L is garbage collected
>>> id(foo)
3077166252L
>>>
>>>
>>> temp=foo #now both foo and temp point to same object i.e 3077166252L
>>> foo=Foo() #assign foo to a new object
>>> id(temp) #temp still points 3077166252L ,so it's not garbage collected
3077166252L
>>> id(foo) #it points to a new object
3077166092L
有几点需要注意
名称“foo”是在代码中定义的变量。在Python中,只有为变量赋值,变量才有类型
当您说foo=foo()
时,您正在为变量foo
指定类型为foo
的对象的实例Foo()
通过调用Foo
类的构造函数(不带任何参数)来创建此实例
每次调用Foo()
都会创建一个新实例。因此,在代码中重复foo=foo()
将创建foo
类的多个实例,并将它们分配给变量foo
。foo
变量指向的早期实例将不再具有引用,并且可以进行垃圾收集(假设您在此期间没有为这些实例分配任何其他引用)
因此,你用来描述你的问题的词语
创建与现有类同名的类的第二个实例
实例
其实是不对的。因为您没有创建另一个“同名”的实例。您正在创建另一个实例,并将其分配给“同一个变量”。让我尝试以图形方式解释它
当你这样做的时候
foo = Foo()
首次在内存中创建Foo
类型的对象(使用Foo()
),同时创建一个指向此对象的变量:
当你执行
foo = Foo()
这是第二次,您正在创建另一个对象。同时,取同一个变量并将其指向新对象。当然,变量将不再指向上一个对象:
现在,第一个对象发生了什么?好吧,如果程序中没有其他变量指向它,它是无用的,因为你不能再访问它了!在这种情况下,当解释器运行垃圾收集器时,对象将被销毁/从内存中释放。垃圾收集器是一种算法,它将查找每个不可访问的对象并将其删除。垃圾收集器并非每次都运行,因此销毁对象可能需要一段时间
因此,在您的场景中,发生的是:
- 对第一个对象的引用将被覆盖,但该对象将存在。如果另一个变量指向它,它将不会被销毁
- 但是,如果没有其他变量指向该对象,则该对象将在将来某个时候被删除
“删除或覆盖”:两者+1:关键是它不是值,而是参考。每次调用构造函数并为其命名时,都会创建一个新对象。当你创建的东西没有名字时,它会被垃圾收集。非常详细的答案!谢谢@carlosdc:每次调用c
foo = Foo()