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

83

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

анон.
источник
2
Я предлагаю вам использовать итераторы вместо счетчиков: "for item in simpleList:" выглядит намного лучше.
Mapad

Ответы:

71

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

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

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

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

simplelist = [SimpleClass(count) for count in xrange(4)]
железный лягушонок
источник
2
Недоступно для python 3.x - функция xrange () больше не поддерживается.
r3t40
3
@TitPoplatnik Просто замените xrange () на range ().
eXPRESS
@ironfroggy - возможно ли получить индекс, по которому объект хранится внутри класса. Скажем, если класс A находится на позиции 3 в некотором списке, [x, x, x, A, x], можно ли получить позицию, реализовав метод купола в A.
Александр Цска
55

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

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

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

instancelist[5].attr1 = 'whamma'
Зумулятор
источник
3
лучше быть: instancelist = [MyClass () for _ in range (29)]
tutormike
11

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

Вместо:

x = SimpleClass

тебе нужно:

x = SimpleClass()
Даниэль Нааб
источник
7
x = SimpleClass() будет воссоздавать объект каждый раз.
neil
5

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

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

Joel.neely
источник
3

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

Роберто Лиффредо
источник
2
Повторное использование объекта - глубокая копия или клонирование - обычная путаница среди n00b. Иногда вы не можете ответить на вопрос, который вам задают; иногда приходится отвечать на вопрос, который они должны были задать.
S.Lott
3

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

# 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']
Triple Decker
источник