2016-07-29 35 views
0

Das Problem, das ich habe, ist, dass wenn ich einen Code, der die PlusMinusAverage-Klasse mehr als einmal verwendet (in meinem Fall eine for-Schleife), die neue Instanz der Klasse behält Verweise auf die vorherige Liste von pmaDicts, die von der vorherigen plustMinusAverage-Erstellung erstellt wurden, und fügt sie dem Ende hinzu.Python-Liste der Wörterbücher in der Klasse verhält sich nicht wie erwartet

Bedeutung (Code, führt dies weiter unter unten)

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..}] 

Was dies bringt mich ist, dass es aus dem Objekt drucken erscheint, aber dann wird die Liste auf das Original zu zeigen, aber mit mehr Einträge. Ich verstehe nicht, warum die Liste nicht einzigartig sein sollte.

Entschuldigung für die massive Veröffentlichung von Code unten, aber ich dachte, dieses Problem hat genug Nuancen, dass der Versuch, eine einfachere Version zu machen würde wahrscheinlich Lösungen laden, die für meine Umstände nicht funktionieren würde, und da ich nicht sicher bin, wo Das Problem liegt genau, ich werde alle relevanten Teile einbeziehen, wo es schief gehen könnte. ..plus vielleicht kann jemand, der in Maya arbeitet, diese verwenden, um ihre eigenen ShaderNode-Tools zu erstellen.

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] 

In getrennten py Datei, in der Klasse enthalten Verbindung geladen wird als attr

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

Sie haben * Klassenattribute *; Diese werden pro Klasse und nicht pro Instanz festgelegt und unter den Instanzen geteilt. –

+1

Setzen Sie 'self.values1D',' self.values2D', 'self.values2D' stattdessen in einer' __init__' Methode. –

+0

Danke. Das hat funktioniert! –

Antwort

1

Die Problemlinien sind hier:

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

Sie sind die Listen als Klassenattribute zuweisen. Normalerweise sind Sie an eine solche Aufgabe gewöhnt, denn wenn Sie bei einem Methodenaufruf etwas wie values1d = blah machen würden, würde die Zuweisung implizit unter self erfolgen. Sie erstellen jedoch nie eine andere Zuweisung: Sie verwenden die Liste auf Klassenebene nur über Methoden wie append, __setitem__ usw. Daher verwenden alle Instanzen dieselben Listen, die im Klassenobjekt definiert sind.

Um dies zu beheben, verschieben Sie die drei Listenzuordnungen innerhalb __init__:

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

Dadurch wird sichergestellt, dass jede Instanz eine eigene Liste bekommt. Tun Sie dies für alle veränderbaren Attribute wie Listen und Dicts als eine allgemeine Regel, um die gleiche Art von Problem in der Zukunft zu vermeiden.