Python:如何创建类值的动态列表

时间:2013-12-11 22:22:41

标签: python list class dynamic

我试图找到问题的答案,但我找不到好的关键词......

我想知道如何在类的实例中创建值帮助列表。 我不想要的是:

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类中的能量被更改时,列表就会自动更新。

非常感谢!

5 个答案:

答案 0 :(得分:3)

一个非常好的问题。

在回答的路上有两个要点:

  1. 经典变量与python标签类似“变量”/标识符
  2. mutable vs immutable python-types
  3. 你必须记住,如果你来自另一种编程语言,那么在python中,名称​​ variable 可能会产生误导。最好不要谈论变量,而是谈论“标签”。

    当你创建一个像myvar = 1这样的对象时,你创建(过度简化)一个对象1并跟踪它,你附加了一个标签myvar。 因此,如果您想谈论对象1,您可以说:“标有myvar的对象。”您可以通过重新标记将标签重新附加到另一个对象:myvar = 2。如果myvar1上的唯一标签,那么您刚丢失了对象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:在不可变对象上,你需要移动“Label”,而在mutable上你可以保持“Label”并移动它下面的对象。

    现在回到你的问题:

    基本上你需要改变观点! MyList不是数组,而是集合。因此,为了不重新发明您的解决方案,我建议您将Test对象保留在列表中,而不是它们的值!:

    MyList = [inst1,inst2]
    

    如果您立即更改inst1.i = 4,则会发生以下情况:

    1. 您创建了对象4
    2. 您将属性inst1.i附加到它(“重新标记”它)
    3. 您的对象成为列表与新对象之间的中介
    4. 您可以通过4MyList[0].i
    5. 访问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]
      

答案 1 :(得分:1)

假设您已经创建了Protein类的各种实例(例如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]
在我看来,实现这一目标的最佳途径是:)

答案 2 :(得分: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

所以不,int的一个简单子类不会削减它。但能源的新课程将会。有关您要添加到Energy的所有方法,请参阅http://docs.python.org/2/reference/datamodel.html@emulating-numeric-types,使其看起来像一个数字。

努力值得吗?你决定了。

答案 3 :(得分: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

根据您使用它的程度,您可能希望使用extend__add__

等超范围方法

答案 4 :(得分: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]