【问题标题】:Creating a list of objects in Python在 Python 中创建对象列表
【发布时间】:2010-09-25 18:43:27
【问题描述】:

我正在尝试创建一个 Python 脚本来打开多个数据库并比较它们的内容。在创建该脚本的过程中,我在创建内容是我创建的对象的列表时遇到了问题。

我已经将这个程序简化到了本次发布的基本内容。首先,我创建一个新类,创建它的一个新实例,为其分配一个属性,然后将其写入一个列表。然后我为实例分配一个新值并再次将其写入列表......一次又一次......

问题是,它始终是同一个对象,所以我实际上只是在更改基础对象。当我阅读列表时,我一遍又一遍地重复相同的对象。

那么如何在循环中将对象写入列表?

这是我的简化代码

class SimpleClass(object):
    pass

x = SimpleClass
# Then create an empty list
simpleList = []
#Then loop through from 0 to 3 adding an attribute to the instance 'x' of SimpleClass
for count in range(0,4):       
    # each iteration creates a slightly different attribute value, and then prints it to
# prove that step is working
# but the problem is, I'm always updating a reference to 'x' and what I want to add to
# simplelist is a new instance of x that contains the updated attribute

x.attr1= '*Bob* '* count
print "Loop Count: %s Attribute Value %s" % (count, x.attr1)
simpleList.append(x)

print '-'*20
# And here I print out each instance of the object stored in the list 'simpleList'
# and the problem surfaces.  Every element of 'simpleList' contains the same      attribute value

y = SimpleClass
print "Reading the attributes from the objects in the list"
for count in range(0,4):
    y = simpleList[count]
    print y.attr1

那么我如何(追加、扩展、复制或其他)simpleList 的元素,以便每个条目包含对象的不同实例,而不是全部指向同一个?

【问题讨论】:

  • 我建议你使用迭代器而不是计数器:“for item in simpleList:”看起来好多了。

标签: python list object loops


【解决方案1】:

你表现出根本的误解。

您根本没有创建过 SimpleClass 的实例,因为您没有调用它。

for count in xrange(4):
    x = SimpleClass()
    x.attr = count
    simplelist.append(x)

或者,如果您让类接受参数,则可以使用列表推导式。

simplelist = [SimpleClass(count) for count in xrange(4)]

【讨论】:

  • 不适用于 python 3.x - 不再支持 xrange() 函数。
  • @TitPoplatnik 只需将 xrange() 替换为 range()。
  • @ironfroggy 是否可以从类中获取存储对象的索引。假设 A 类在某个列表中的位置 3,[x,x,x,A,x],是否可以通过在 A 中实现圆顶方法来检索位置。
【解决方案2】:

要使用类的单独实例填充列表,您可以在列表的声明中使用 for 循环。 * multiply 会将每个副本链接到同一个实例。

instancelist = [ MyClass() for i in range(29)]

然后通过列表的索引访问实例。

instancelist[5].attr1 = 'whamma'

【讨论】:

  • 最好是:instancelist = [ MyClass() for _ in range(29)]
【解决方案3】:

如果您只是使用它来根据其属性输出数据,则不必每次都重新创建 SimpleClass 对象,正如一些人所建议的那样。但是,您实际上并没有创建该类的实例。您只是在创建对类对象本身的引用。因此,您一遍又一遍地向列表中添加对同一类属性的引用(而不是实例属性)。

代替:

x = SimpleClass

你需要:

x = SimpleClass()

【讨论】:

  • x = SimpleClass() 正在每次都在重新创建对象。
【解决方案4】:

每次创建一个新实例,每个新实例都有正确的状态,而不是不断修改同一个实例的状态。

或者,在每一步存储对象的显式副本(使用提示 at this page),而不是原始副本。

【讨论】:

    【解决方案5】:

    如果我正确理解您的问题,您会问一种方法来执行对象的深层副本。 使用 copy.deepcopy 怎么样?

    import copy
    
    x = SimpleClass()
    
    for count in range(0,4):
      y = copy.deepcopy(x)
      (...)
      y.attr1= '*Bob* '* count
    

    深拷贝是整个对象的递归拷贝。如需更多参考,您可以查看 python 文档:https://docs.python.org/2/library/copy.html

    【讨论】:

    • 重用对象——深拷贝或克隆——是一种常见的混淆。有时你无法回答出现的问题;有时你必须回答他们应该问的问题。
    【解决方案6】:

    我认为这只是说明了您要实现的目标:

    # coding: utf-8
    
    class Class():
        count = 0
        names = []
    
        def __init__(self,name):
            self.number = Class.count
            self.name = name
            Class.count += 1
            Class.names.append(name)
    
    l=[]
    l.append(Class("uno"))
    l.append(Class("duo"))
    print l
    print l[0].number, l[0].name
    print l[1].number, l[1].name
    print Class.count, Class.names
    

    运行上面的代码,你会得到:-

    [<__main__.Class instance at 0x6311b2c>, 
    <__main__.Class instance at 0x63117ec>]
    0 uno
    1 duo
    2 ['uno', 'duo']
    

    【讨论】:

      猜你喜欢
      • 2013-07-01
      • 2019-06-16
      • 1970-01-01
      • 1970-01-01
      • 2022-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多