2013-12-11 2 views
4

я пытался найти anwser на этот вопрос, но я не могу найти хорошие слова ...Python: Как создать динамический список значений класса

Я хочу знать, как я могу создать список Value help в экземплярах класса. То, что я не хочу, что:

class Test: 
    def __init__(self,i) 
     self.i = i 

inst1 = Test(2) 
inst2 = Test(5) 

MyList = [inst1.i,inst2.i] 

В этой точке MyList = [2,5] если изменить значение, если inst1

inst1.i = 4 
print MyList 
[2,5] 

MyList ЕЩЕ [2,5], но Я хочу, чтобы это было обновлено до [4,5]

print MyList 
[4,5] 

Так что мой вопрос заключается в том, как создать список, который указывает на переменную, а не значение переменной?

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

class Protein: 
    def __init__(self,sequence,energy): 
     self.sequence = sequence 
     self.energy = energy 

Эта энергетическая ценность некоторых белков обновляется во время моделирования montecarlo. Мне нужен список всех энергий для выполнения некоторых вычислений по распределению. Правильно знаю, я обновил список с циклом for, но было бы более эффективным, если бы у меня был список, указывающий на переменную, таким образом, каждый раз, когда энергия в классе Protein изменяется, список обновляется автоматически.

Большое спасибо!

+7

Почему бы не хранить экземпляры непосредственно в списке и не манипулировать ими? 'MyList = [inst1, inst2]', тогда у вас есть список ссылок на ваши экземпляры. Любые изменения в экземплярах также видны в списке. –

+1

Можете ли вы объяснить, почему вам нужно значение int, а не экземпляр класса в списке? Возможно, какой-то симпатичный прокси-объект может быть создан, но предложение @MartijnPieters - это, вероятно, простой путь вперед. Нет простого способа сохранить ref в int. –

+0

Да, я хоть об этом, но как я могу получить значение тогда? например, если я хочу получить гистограмму, и я: hist, bin = np.histogram (MyList) это не сработает. – Xqua

ответ

3

Очень хороший вопрос.

Две пули точка на пути к вашему ответу:

  1. классической переменным против питона меток, такими как "переменных"/идентификаторов
  2. изменяемых противами неизменного питона-типов

Вы должны иметь в виду, что в python имя переменная может вводить в заблуждение, если вы исходите из другого языка программирования. Может быть, лучше не говорить о переменных, но про «этикетки».

При создании такого объекта, как: myvar = 1 вы создаете (упрощение) объект 1 и следить за ней вы прикрепили ярлык myvar к нему. Так что, если вы хотите поговорить об объекте 1 вы бы сказали: "Объект с пометкой myvar." Вы можете повторно привязать ярлык к другому объекту путем перемаркировки: myvar = 2. Если myvar был единственным лейблом на 1, вы только что потеряли объект 1, и он будет собран в мусор.

В вашем случае:

inst1 = Test(2) # create 2 and attach it to inst1.i 
inst2 = Test(5) # create 5 and attach it to inst2.i 
MyList = [inst1.i,inst2.i] # list of objects: [2 ,5] 

Так теперь у вас есть список 2 неизменяемых объектов! Ваш следующий шаг:

inst1.i = 4 

создает новый объект 4 и прикрепляет на inst1.iярлык на него! Вы просто потеряли свою ручку на объекте 2. Но поскольку он находится в коллекции MyList, он по-прежнему ссылается и не собирается собирать мусор.

Теперь на пулевой пункт 2:

хороших overview of mutable and immutable объекты, показывает, что в основном все примитивные типы неизменны и большинство коллекций изменчивы. Разница есть. что изменяемые объекты могут получить значение на месте, а неизменяемые объекты необходимо заменить.

Или сохранить ярлык anology: На неизменяемых объектах вам нужно переместить «Ярлык», а на изменчивом вы удерживаете «метку» на месте и перемещаете предмет под ним.

Теперь вернемся к вашей проблеме:

В основном вам нужно изменить перспективу! MyList НЕ МАРИЯ, но коллекция. Поэтому, чтобы не изобретать ваши места раствора я бы рекомендовал держать Test объекты в списке, а не их значения !:

MyList = [inst1,inst2] 

Если теперь изменится inst1.i = 4, происходит следующее:

  1. вы создаете объект 4
  2. вы придаете атрибут inst1.i к нему («переквалифицировать» это)
  3. Ваш объект становится посредником б etween список и ваш новый объект
  4. Вы можете получить доступ к 4 через MyList[0].i или inst1.i

Миссия выполнена! ;-)

for value in MyList: 
    print value.i 

inst1.i = 4  
raw_values = [o.i for o in MyList] 
[4, 5] 

inst1.i = 2 
raw_values = [o.i for o in MyList] 
[2, 5] 
+0

Хорошо, поэтому int являются неизменяемыми, а список изменчивым. Значит, до тех пор, пока я храню int, я ввернута ... так или иначе, чтобы сделать int Mutable? – Xqua

+0

В принципе, да, но вокруг есть способы! Это только смущение в начале позже, это более хорошо, а затем плохо! –

+0

Я уверен, что это! ^^ Я использовал python некоторое время, и мне это обычно не нужно! Но в этом конкретном алгоритме он избежал бы двойного цикла, который бы ускорил алгоритм. Я думаю, что я унаследовал класс int к моему классу белков, чтобы сделать его int, а затем сохранить его в списке, таким образом он должен работать. – Xqua

1

Предполагая, что вы уже создали различные экземпляры класса белка, и что энергетическая ценность представляет собой число (ех p1, p2, p3.):

class Protein: 
    def __init__(self,sequence,energy): 
     self.sequence = sequence 
     self.energy = energy 

def update_list_energy(list, value): 
    for prot in list: 
     prot.energy += value #or whatever the update should be 

p1 = Protein('AAA', 1) 
p2 = Protein('BBB', 2) 
p3 = Protein('CCC', 3) 

list_of_proteins = [p1,p2,p3] 
print [p.energy for p in list_of_proteins] # prints [1,2,3] 
update_list_energy(list_of_proteins, 1) 
print [p.energy for p in list_of_proteins] # prints [2,3,4] 

мне кажется, что лучший способ достичь этого :)

+0

Спасибо Да, вот как я это делаю, но я хочу избежать цикла for так, чтобы алгоритм достиг большей скорости! – Xqua

1
>>> class ProteinEnergy(int): pass 
... 
>>> e = ProteinEnergy(1) 
>>> e 
1 
>>> e + 1 
2 
>>> class Protein(object): 
...  def __init__(self, value): 
...   self.energy = ProteinEnergy(value) 
... 
>>> p1 = Protein(1) 
>>> p2 = Protein(2) 
>>> protein_energies = [p1.energy, p2.energy] 
>>> protein_energies 
[1, 2] 
>>> p1.energy += 5 
>>> protein_energies 
[1, 2] 
>>> class Energy(object): 
...  def __init__(self, v): 
...   self.v = v 
... 
>>> class Protein(object): 
...  def __init__(self, value): 
...   self.energy = Energy(value) 
... 
>>> p1 = Protein(1) 
>>> p2 = Protein(2) 
>>> p1.energy.v 
1 
>>> protein_energies = [p1.energy, p2.energy, ] 
>>> p1.energy.v = 5 
>>> protein_energies[0].v 
>>> 5 

Так нет, простой подкласс междунар не режет его. Но новый класс для Энергии будет. См. http://docs.python.org/2/reference/[email protected] для всех методов, которые вы хотите добавить в Energy, чтобы они выглядели как число.

Насколько это стоит? Вам решать.

1

Вы можете расширить класс list и переопределить методы последовательности.Вот пример:

class Protein(list): 
    def __init__(self, energy=0): 
     self.energy = energy 

    def __setitem__(self, key, value): 
     self.energy -= value - self[key] 
     super(Protein, self).__setitem__(key, value) 
     self.energy += value 

    def __delitem__(self, key): 
     self.energy -= self[key] 
     super(Protein, self).__delitem__(key) 

    def append(self, value): 
     super(Protein, self).append(value) 
     self.energy += value 

Использование:

>>> p = Protein() 
>>> p.append(1) 
>>> print p 
[1] 
>>> print p.energy 
1 
>>> 
>>> p.append(5) 
>>> print p 
[1, 5] 
>>> print p.energy 
6 
>>> 
>>> p[0] = 2 
>>> print p 
[2, 5] 
>>> print p.energy 
7 
>>> 
>>> del p[1] 
>>> print p 
[2] 
>>> print p.energy 
2 

В зависимости от того, сколько вы делаете с ним, вы можете overrwide методы как extend и __add__

+1

+1 расширяется с приятным прикосновением! –

+0

Ваш класс не следует называть '' Protein'', но '' список энергий белков' – eyquem

+0

@eyquem, когда он начинает добавлять некоторые свойства в класс 'Protein', например' name', он начнет напоминают «белок». –

1
class Protein: 
    Energies = [] 
    def __init__(self,en): 
     self.__dict__['energy'] = en 
     # this instruction to avoid writing self.i that 
     # would call __setattr__(self,'i',x) while 
     # attribute L wouldn't be defined at this moment 
     self.L = len(self.Energies) 
     Protein.Energies.append(en) 
     # appended only at the creation of the instance 
    def __setattr__(self,name,x): 
     self.__dict__[name] = x 
     # this writing to avoid recursive call 
     if name=='energy': 
      Protein.Energies[self.L] = x 

inst1 = Protein(2) 
inst2 = Protein(5) 

print Protein.Energies 
print inst1.Energies 
print inst2.Energies 
print 

inst1.energy = 10 
print Protein.Energies 
print inst1.Energies 
print inst2.Energies 

результат

[2, 5] 
[2, 5] 
[2, 5] 

[10, 5] 
[10, 5] 
[10, 5] 
+0

Спасибо. - Мне интересно узнать, наблюдаете ли вы большую скорость при выполнении программы. - Обращаю ваше внимание на этот факт: «Объем имен, определенных в блоке класса, ограничен блоком класса; он не распространяется на кодовые блоки методов'' (http://docs.python.org/2/reference/executionmodel.html). Именно по этой причине мы обязаны писать '' Protein.Energies'' внутри методов , а не просто '' Energies'', чтобы получить доступ к списку ** Energies **, который является атрибутом класса, определенным в блоке класса (я пишу '' Energies'' для имени и ** Energies ** для объект). – eyquem

+0

Когда метод встречает ссылку на атрибут '' Protein.Energies', функция, на которой основан метод, выходит из своего пространства имен, потому что в ней нет локального идентификатора '' Protein'' и исследуется пространство имен этого внешнего пространство, в настоящее время пространство имен модулей, в котором есть идентификатор '' Protein''. Затем он ищет атрибут имени '' Energies'' класса ** Protein **. Если бы это было написано '' Energies'' вместо '' Protein.Energies'', он бы не нашел идентификатор '' Energies'' там, в пространстве имен модулей – eyquem

+0

Кстати, если вы предпочитаете его, вы можете определить введите «Энергии» на уровне модуля и вызовите его только с помощью методов «Энергии» в классе. Но это может столкнуться с наличием в модуле другого списка, уже названного '' Energies'', логичнее делать то же, что и в моем коде. – eyquem

Смежные вопросы