Создание списка объектов в Python

Я пытаюсь создать скрипт 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, чтобы каждая запись содержала разные экземпляры объекта, а не все указывала на один и тот же?


person Community    schedule 07.12.2008    source источник
comment
Я предлагаю вам использовать итераторы вместо счетчиков: для элемента в simpleList: выглядит намного лучше.   -  person Mapad    schedule 08.12.2008


Ответы (6)


Вы демонстрируете фундаментальное непонимание.

Вы вообще никогда не создавали экземпляр SimpleClass, потому что не вызывали его.

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

Или, если вы позволите классу принимать параметры, вместо этого вы можете использовать понимание списка.

simplelist = [SimpleClass(count) for count in xrange(4)]
person Community    schedule 07.12.2008
comment
Недоступно для python 3.x — функция xrange() больше не поддерживается. - person r3t40; 14.02.2019
comment
@TitPoplatnik Просто замените xrange() на range(). - person eXPRESS; 20.04.2019
comment
@ironfroggy можно ли получить индекс, в котором хранится объект, из класса. Скажем, если класс A находится на позиции 3 в некотором списке [x,x,x,A,x], можно ли получить позицию, реализуя метод купола в A. - person Alexander Cska; 03.07.2019

Чтобы заполнить список отдельными экземплярами класса, вы можете использовать цикл for в объявлении списка. Умножение * свяжет каждую копию с одним и тем же экземпляром.

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

а затем получить доступ к экземплярам через индекс списка.

instancelist[5].attr1 = 'whamma'
person Community    schedule 09.12.2008
comment
лучше: instancelist = [MyClass() for _ in range(29)] - person tutormike; 31.01.2018

Нет необходимости каждый раз воссоздавать объект SimpleClass, как предлагают некоторые, если вы просто используете его для вывода данных на основе его атрибутов. Однако на самом деле вы не создаете экземпляр класса; вы просто создаете ссылку на сам объект класса. Таким образом, вы снова и снова добавляете в список ссылку на один и тот же атрибут класса (вместо атрибута экземпляра).

Вместо:

x = SimpleClass

тебе нужно:

x = SimpleClass()
person Community    schedule 07.12.2008
comment
x = SimpleClass() является воссозданием объекта каждый раз. - person neil; 22.11.2013

Каждый раз создавайте новый экземпляр, где каждый новый экземпляр имеет правильное состояние, вместо того, чтобы постоянно изменять состояние одного и того же экземпляра.

В качестве альтернативы сохраните явно созданную копию объекта (используя подсказку на этой странице). на каждом этапе, а не оригинал.

person Community    schedule 07.12.2008

Если я правильно понимаю ваш вопрос, вы спрашиваете, как выполнить глубокую копию объекта. Как насчет использования 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

person Community    schedule 07.12.2008
comment
Повторное использование объекта — глубокое копирование или клонирование — распространенная путаница. Иногда вы не можете ответить на вопрос, который вам задают; иногда приходится отвечать на вопрос, который они должны были задать. - person S.Lott; 08.12.2008

Я думаю, что это просто демонстрирует, чего вы пытаетесь достичь:

# 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']
person Community    schedule 07.03.2018