Python class 中的词典列表未按预期运行
Python list of dictionaries in class not behaving as expected
我似乎遇到的问题是,当我 运行 一个代码多次使用 plusMinusAverage class(在我的例子中是一个 for 循环)时,class 保留对之前 plustMinusAverage 创建的 pmaDicts 列表的引用,并添加到它的末尾。
含义
(导致此结果的代码在下面进一步)
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..}]
让我明白这一点的是,它似乎打印出了对象,但随后列表似乎指向原始对象,但包含更多条目。我不明白为什么列表不是唯一的。
对于下面大量发布的代码,我深表歉意,但我认为这个问题有足够的细微差别,试图制作一个更简单的版本可能会邀请不适合我的情况的解决方案,因为我不确定在哪里问题所在,我将包括所有可能出错的相关部分。
..加上也许在 maya 工作的人可以使用它来构建他们自己的 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]
在单独的 py 文件中,其中包含连接的 class 作为 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()
问题行就在这里:
class plusMinusAvg(attr.shaderNode):
type = "plusMinusAverage"
values1D = []
values2D = []
values3D = []
您正在将列表分配为 class 属性。您通常习惯于这样的赋值,因为如果您要在方法调用中执行类似 values1d = blah
的操作,赋值将隐式地在 self
上进行。但是,您永远不会进行其他分配:您只需通过 append
、__setitem__
等方法使用 class 级列表。因此,所有实例都使用相同的列表,定义在 class对象。
要修复,请将三个列表分配移动到 __init__
:
内
self.values1D = []
self.values2D = []
self.values3D = []
这将确保每个实例都有自己的列表。作为一般规则,对所有可变属性(例如列表和字典)执行此操作以避免将来出现相同类型的问题。
我似乎遇到的问题是,当我 运行 一个代码多次使用 plusMinusAverage class(在我的例子中是一个 for 循环)时,class 保留对之前 plustMinusAverage 创建的 pmaDicts 列表的引用,并添加到它的末尾。
含义 (导致此结果的代码在下面进一步)
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..}]
让我明白这一点的是,它似乎打印出了对象,但随后列表似乎指向原始对象,但包含更多条目。我不明白为什么列表不是唯一的。
对于下面大量发布的代码,我深表歉意,但我认为这个问题有足够的细微差别,试图制作一个更简单的版本可能会邀请不适合我的情况的解决方案,因为我不确定在哪里问题所在,我将包括所有可能出错的相关部分。 ..加上也许在 maya 工作的人可以使用它来构建他们自己的 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]
在单独的 py 文件中,其中包含连接的 class 作为 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()
问题行就在这里:
class plusMinusAvg(attr.shaderNode):
type = "plusMinusAverage"
values1D = []
values2D = []
values3D = []
您正在将列表分配为 class 属性。您通常习惯于这样的赋值,因为如果您要在方法调用中执行类似 values1d = blah
的操作,赋值将隐式地在 self
上进行。但是,您永远不会进行其他分配:您只需通过 append
、__setitem__
等方法使用 class 级列表。因此,所有实例都使用相同的列表,定义在 class对象。
要修复,请将三个列表分配移动到 __init__
:
self.values1D = []
self.values2D = []
self.values3D = []
这将确保每个实例都有自己的列表。作为一般规则,对所有可变属性(例如列表和字典)执行此操作以避免将来出现相同类型的问题。