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
  • Python中没有覆盖
  • 当您编写
    Foo()
    时,将创建一个新实例(按顺序调用类方法
    \uuuuuu new\uuuuu
    和实例方法
    \uuuuuuuu init\uuuuuuu
  • 当没有指向类实例的指针时,Python的垃圾收集器将最终删除该实例(并对该实例调用实例方法
    \uu del\uu

  • 您最终将一个新的Foo对象绑定到
    Foo
    ,而旧的
    Foo
    对象将丢失一个引用。如果一个对象没有任何引用,那么它将在下一次垃圾收集时被收集。

    第二次垃圾收集将覆盖第一次垃圾收集。(它取代模块的全局字典中的名称,所有全局变量、函数和类都存储在该字典中)

    但是,您创建的foo=foo()将从创建时起继续使用原始实现,直到您创建新的foo=foo()。

    1st
    foo=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()