【问题标题】:python how to save new objects into a list without duplicationpython如何将新对象保存到列表中而不重复
【发布时间】:2013-08-23 00:37:59
【问题描述】:

我的程序的高级图片

  • 目的:解析 XML 文件并将文本保存到类似的 python 对象中
  • 问题:每次我创建一个新的 python 对象并将其附加到一个列表时,它似乎不是创建一个新对象,而是附加对以前对象的引用。

我的预期结构总结

应用程序列表,每个应用程序都包含一个连接列表

app1: 
     connection1
     connection2
app2:
     connection3
     connection4
     connection5

这就是它应该做什么的总结......所以这是我的主要功能:

def main(self):
    root = get_xml_root()
    root.get_applications()
    for application in root.applications:
        application.get_connections()           ## this is where the memory goes bad!!!
        for connection in application.connections:
              connection.do_something()

我怎么知道有内存问题

  • 当我更改属于特定应用程序的一个连接列表中的一项内容时,另一个应用程序中的连接也会更改。
  • 我打印出连接的内存位置,发现有重复的引用(请参阅内存打印)

内存打印输出

  • 当我打印出应用程序位置时,我得到了以下信息(它并不漂亮,但您可以看到至少地址不同):

generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a07e8 - 内存位置 = 22677480 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a0758 - 内存位置 = 22677336 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a0830 - 内存位置 = 22677552 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a0878 - 内存位置 = 22677624 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a08c0 - 内存位置 = 22677696 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a0908 - 内存位置 = 22677768 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a0950 - 内存位置 = 22677840 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a0998 - 内存位置 = 22677912 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a09e0 - 内存位置 = 22677984 generator_libraries.data_extraction.extraction.Application_XML 实例位于 0x15a0a28 - 内存位置 = 22678056

  • 当我打印出 3 个不同应用程序的连接位置时,我得到以下信息(您可以看到地址之间的重复):

    • app1:
    • 内存位置 = 22721168
    • 内存位置 = 22721240
    • 内存位置 = 22721024
    • 内存位置 = 22721600
    • 内存位置 = 22721672

    • app2:

    • 内存位置 = 22721240
    • 内存位置 = 22721672
    • 内存位置 = 22721600
    • 内存位置 = 22721168
    • 内存位置 = 22722104
    • 内存位置 = 22722176

记忆分析的结论 似乎每次我创建一个新的连接对象并将其附加到我的“连接”列表时,它都不会创建一个新对象,而是从我以前的对象中获取内存引用。

问题函数代码的更详细视图

class Application_XML(XML_Element_Class):
    name = None
    connections=copy.deepcopy([])
    xml_element=None
    def get_connections(self):
        xml_connections = self.get_xml_children()
        for xml_connection in xml_connections:
            connection = None       ## reset the connection variable
            connection = Connection_XML(xml_connection)
            connection.unique_ID = connection_count
            self.connections.append(copy.deepcopy(connection))
            del connection      ## reset where its pointing to
            connection_count+=1
        self.log_debugging_info_on_connection_memory()   ### this is where I look at memory locations

一个做同样事情的类......但有效

class Root_XML(XML_Element_Class):
    applications = copy.deepcopy([])
    def get_applications(self):
        xml_applications = self.get_xml_children()
        for xml_application in xml_applications:
            self.applications.append(Application_XML(xml_application))
        self.log_application_memory_information()

如果有什么帮助,这里是连接类:

class Connection_XML(XML_Element_Class):
    ### members
    name = None
    type = None
    ID = None
    max_size = None
    queue_size = None
    direction = None
    def do_something(self):
        pass

结束语

我几乎尝试了书中的每一个技巧,以创建对象的替代方法,在我制作它们之后将它们销毁......但没有任何帮助。我觉得答案背后可能有一个基本的python内存概念......但是在我网上搜索之后,没有任何答案。

拜托,如果你能帮忙,那就太棒了!!!谢谢:)

【问题讨论】:

  • 等等,你从一月份开始有 Python 问题。我很惊讶你 8 个月没有被这个咬伤。
  • Bug:与其他语言不同,在类范围内分配给变量不会声明实例字段;它设置了一个类属性。如果需要实例属性,请在__init__ 方法中设置self.attribute_name = whatever_value
  • 如果您发布一个 SSCCE 来运行并演示我们可以为您解决的问题,而不仅仅是发布代码片段和描述,这将非常有帮助。
  • 除了关于类和实例变量的 cmets,connections=copy.deepcopy([]) 是多余的。使用connections=[](或更可能是self.connections=[])创建了一个新列表,您不需要复制它。

标签: python arrays memory-management pass-by-reference class-instance-variables


【解决方案1】:

我认为问题与您正在查看的部分无关,而是与 Connection_XML 类有关:

class Connection_XML(XML_Element_Class):
    ### members
    name = None
    type = None
    ID = None
    max_size = None
    queue_size = None
    direction = None
    def do_something(self):
        pass

所有这些成员都是类属性。每个Connection_XML 实例共享一个name,一个type 等。因此,即使您的实例都是唯一对象,更改一个也会更改所有对象。

您需要实例属性——每个实例都有一个单独的name 等。你这样做的方式是动态地创建属性,通常在__init__ 方法中:

class Connection_XML(XML_Element_Class):
    def __init__(self):
        self.name = None
        self.type = None
        self.ID = None
        self.max_size = None
        self.queue_size = None
        self.direction = None
    def do_something(self):
        pass

如果没有真正的SSCCE,很难确定这是您的问题。在这个玩具示例中,所有属性的值都为None,它是不可变的,因此不会真正导致此类问题。但是,如果其中一个是,比如说,一个列表,或者一个有自己属性的对象,它就会。

【讨论】:

  • 我认为是 Application_XMLconnections 类属性。那是一个列表。
  • @user2357112:很好。
  • 你完全正确!我需要创建实例属性而不是类属性。显然它不是不可变类型的问题,但是对于像列表(我正在使用的)这样的可变类型,如果您更改一个,那么您将全部更改。一旦我让它们成为实例属性,问题就解决了。感谢您的帮助!
  • @Pswiss87:嗯,从技术上讲,可变类型甚至不是真正的问题。如果你只是重新绑定一个恰好持有一个列表的类属性名,你会得到一个实例属性;只有当您就地改变列表(例如,使用append)时,您才会影响共享值。但实际上,即使 没有 问题,将类属性仅用于打算按原样共享的事物(例如常量)会更清楚,而不是用于有很多实例的事物将替换。
猜你喜欢
  • 2014-10-08
  • 2014-03-20
  • 1970-01-01
  • 2016-10-22
  • 2016-09-05
  • 2018-09-27
  • 2021-01-18
  • 2017-12-09
  • 1970-01-01
相关资源
最近更新 更多