2016-07-29 2 views
0

Проблема, которая возникает у меня, заключается в том, что когда я запускаю код, который использует класс plusMinusAverage более одного раза (в моем случае цикл for), новый экземпляр класса сохраняет ссылки на предыдущий список pmaDicts, созданный предыдущим созданием plustMinusAverage, и добавляет его к концу.Python список словарей в классе не ведет себя так, как ожидалось

Значение (код, который приводит это далее вниз ниже)

things = [] 
for i in range(2): 
    thing[i] = plusMinusAverage(count3D=2) 
    print thing[i] 
    print thing[i].values3D 
>>> (plusMinusAverage at 0x00NSTUFF1) 
>>> [{"x":(attr.connection at 0x1234),"y":(attr.connection at 0x2345), etc..}, 
    {"x":(attr.connection at 0x3456),"y":(attr.connection at 0x4567), etc..}] 
>>> (plusMinusAverage at 0x00NSTUFF2) 
>>> [{"x":(attr.connection at 0x1234),"y":(attr.connection at 0x2345), etc..}, 
    {"x":(attr.connection at 0x3456),"y":(attr.connection at 0x4567), etc..}, 
    {"x":(attr.connection at 0x5678),"y":(attr.connection at 0x6789), etc..}, 
    {"x":(attr.connection at 0x7890),"y":(attr.connection at 0x8901), etc..}] 

Что заставляет меня о том, что это, кажется, распечатать объект, а затем список, как представляется, указывают на оригинал, но с больше записей. Я не понимаю, почему список не будет уникальным.

Извините за массивную публикацию кода ниже, но я полагал, что эта проблема имеет достаточно нюансов, что попытка сделать более простую версию, скорее всего, предложит решения, которые не будут работать для моих обстоятельств, и поскольку я не уверен, проблема заключается именно в том, что я собираюсь включить все соответствующие части, где это может пойти не так. ..plus может быть, кто-то, кто работает в майя, может использовать это, чтобы создать свои собственные инструменты shaderNode.

class Tracker2(object): 
    dag = "" 
    obj = "" 
    getTime = "current" 

    def setPathing(self): 
     if self.nodeName == None: 
      self.nodeName = cmds.createNode('transform') 
      cmds.addAttr(self.nodeName, sn="type", ln="type", dt="string") 
      cmds.setAttr(self.nodeName + ".type", type="string", keyable=0) 
     sel = om.MSelectionList() 
     sel.add(self.nodeName) 
     self.obj = om.MObject() 
     self.dag = om.MDagPath() 
     sel.getDependNode(0, self.obj) 
     try: 
      sel.getDagPath(0, self.dag) 
     except: 
      pass 

    def __init__(self): 
     if not self.dag and not self.obj: 
      self.setPathing() 

    def fullpath(self): 
     if self.dag and self.dag.fullPathName(): 
      return self.dag.fullPathName() 
     return om.MFnDependencyNode(self.obj).name() 

class shaderNode(Tracker2): 
    def __init__(self): 
     self.nodeName = cmds.shadingNode(self.type,au=1) 
     Tracker2.__init__(self) 

class connection(object): 
    def __init__(self, attr, *args): 
     self.attr = attr 
    def __set__(self, instance, value): 
     if isinstance(value,basestring): 
      try: 
       cmds.connectAttr(value,instance.fullpath()+"."+self.attr,f=1) 
      except Exception as inst: 
       cmds.warning(inst) 
     elif not value: 
      temp = cmds.listConnections(instance.fullpath()+"."+self.attr,s=1,d=0) 
      if temp: 
       cmds.disconnectAttr(instance.fullpath()+"."+self.attr, temp[0]) 
     else: 
      cmds.warning("Set Connection: Source attribute is non-string value | "+value) 
    def __get__(self, instance, owner): 
     tempIn = cmds.listConnections(instance.fullpath()+"."+self.attr,s=1,d=0) 
     tempIn = tempIn if tempIn else [] 
     tempOut = cmds.listConnections(instance.fullpath()+"."+self.attr,s=0,d=1) 
     tempOut = tempOut if tempOut else [] 
     #returns list of [[incoming] , [outgoing]] 
     return [tempIn,tempOut] 

В отдельном файле, где ру класс, содержащий соединение загружается как атр

class pmaDict(dict): 
    def __init__(self,instance,*args,**kwargs): 
     self.instance = instance 
     dict.__init__(self,*args,**kwargs) 
    def __getitem__(self, key): 
     thing = dict.__getitem__(self,key) 
     if key in self and isinstance(dict.__getitem__(self, key),attr.Attribute): 
      return thing.__get__(self.instance,None) 
     if key in self and isinstance(dict.__getitem__(self,key),attr.connection): 
      return thing.__get__(self.instance,None) 
     else: 
      return dict.__getitem__(self,key) 

    def __setitem__(self, key, value): 
     thing = dict.__getitem__(self,key) 
     if key in self and isinstance(dict.__getitem__(self,key),attr.Attribute): 
      thing.__set__(self.instance,value) 
     elif key in self and isinstance(dict.__getitem__(self,key),attr.connection): 
      thing.__set__(self.instance, value) 
     else: 
      dict.__setitem__(self,key,value) 

class plusMinusAvg(attr.shaderNode): 
    type = "plusMinusAverage" 
    values1D = [] 
    values2D = [] 
    values3D = [] 

    def addInput1D(self): 
     i = len(self.values1D) 
     print self 
     cmds.setAttr(self.fullpath() + ".input1D[" + str(i) + "]", 0) 
     newInput = pmaDict(self, 
          {"x": attr.Attribute("input1D[" + str(i) + "]", "float"), 
          "x_con": attr.connection("input1D[" + str(i) + "]")}) 
     self.values1D.append(newInput) 

    def addInput2D(self): 
     i = len(self.values2D) 
     print self 
     cmds.setAttr(self.fullpath() + ".input2D[" + str(i) + "]", 0, 0, type="double2") 
     newInput = pmaDict(self, 
          {"xy": attr.Attribute("input2D[" + str(i) + "]", "float"), 
          "x": attr.Attribute("input2D[" + str(i) + "].input2Dx", "float"), 
          "y": attr.Attribute("input2D[" + str(i) + "].input2Dy", "float"), 
          "xy_con": attr.connection("input2D[" + str(i) + "]"), 
          "x_con": attr.connection("input2D[" + str(i) + "].input2Dx"), 
          "y_con": attr.connection("input2D[" + str(i) + "].input2Dy")}) 
     self.values2D.append(newInput) 

    def addInput3D(self): 
     i = len(self.values3D) 
     print self 
     cmds.setAttr(self.fullpath()+".input3D["+str(i)+"]",0,0,0, type="double3") 
     newInput = pmaDict(self, 
          {"xyz": attr.Attribute("input3D["+str(i)+"]","double3"), 
          "x": attr.Attribute("input3D["+str(i)+"].input3Dx","float"), 
          "y": attr.Attribute("input3D["+str(i)+"].input3Dy","float"), 
          "z": attr.Attribute("input3D["+str(i)+"].input3Dz","float"), 
          "xyz_con": attr.connection("input3D["+str(i)+"]"), 
          "x_con": attr.connection("input3D["+str(i)+"].input3Dx"), 
          "y_con": attr.connection("input3D["+str(i)+"].input3Dy"), 
          "z_con": attr.connection("input3D["+str(i)+"].input3Dz")}) 
     self.values3D.append(newInput) 

    def __init__(self, count1D=0, count2D=0, count3D=0): 
     attr.shaderNode.__init__(self) 
     for i in range(count1D): 
      self.addInput1D() 
     for i in range(count2D): 
      self.addInput2D() 
     for i in range(count3D): 
      self.addInput3D() 
+1

У вас есть * атрибуты класса *; они устанавливаются для каждого класса, а не для каждого экземпляра, и используются совместно с экземплярами. –

+1

Установите 'self.values1D',' self.values2D', 'self.values2D' вместо метода' __init__'. –

+0

Спасибо. Это сработало! –

ответ

1

Проблемные линии здесь:

class plusMinusAvg(attr.shaderNode): 
    type = "plusMinusAverage" 
    values1D = [] 
    values2D = [] 
    values3D = [] 

Вы назначаете списки в качестве атрибутов класса. Обычно вы привыкли к такому назначению, потому что, если вы хотите сделать что-то вроде values1d = blah в вызове метода, назначение будет неявно сделано на self. Однако вы никогда не выполняете другое задание: вы просто используете список классов классов с помощью таких методов, как append, __setitem__ и т. Д. Поэтому все экземпляры используют те же списки, которые определены в объекте класса.

Чтобы исправить, переместите три списка присвоений в __init__:

self.values1D = [] 
self.values2D = [] 
self.values3D = [] 

Это будет гарантировать, что каждый экземпляр получает свой собственный список. Сделайте это для всех изменяемых атрибутов, таких как списки и dicts, как общее правило, чтобы избежать того же типа проблем в будущем.