I want to do something like this,
things = [ node().path = x for x in cmds.ls(sl=1,l=1)]
but I'm getting an invalid syntax error. So I've had to use this instead,
things = []
for i, thing in enumerate(cmds.ls(sl=1,l=1)):
things.append(node())
things[i].path = thing
The first invalid code is nice clean and short. The second one is tedious. How can I get some code that allows me to assign a class variable in the same creation line WITHOUT using an initialization. I'm avoiding initialization because this class is going to be inherited into many other classes across multiple files, and my previous version that uses initializations breaks horrible when imported into too many packages, causing unbound method errors.
The reasons for the original question are related to this problem: Maya Python: Unbound Method due to Reload(). The solution I've found is essentially to rework my tracking method to not need an initialization, and then, to avoid the unbound error, I create the initialization sequence nearest to its use.
trackingMethod file:
import maya.cmds as cmds
import maya.OpenMaya as om
class pathTracking(object):
def setPathing(self, instance):
sel = om.MSelectionList()
sel.add(instance.nodeName)
try:
instance.obj = om.MObject()
sel.getDependNode(0, instance.obj)
except:
cmds.warning(instance.nodeName + " is somehow invalid as an openMaya obj node.")
try:
instance.dag = om.MDagPath()
sel.getDagPath(0,instance.dag)
except:
pass
def __set__(self, instance, value):
if isinstance(value,dict):
if "dag" in value:
instance.dag = value["dag"]
if "obj" in value:
instance.obj = value["obj"]
if "nodeName" in value:
instance.nodeName = value["nodeName"]
self.setPathing(instance)
else:
if isinstance(value, basestring):
instance.nodeName = value
self.setPathing(instance)
def __get__(self, instance, owner):
if instance.dag and instance.dag.fullPathName():
return instance.dag.fullPathName()
return om.MFnDependencyNode(instance.obj).name()
class exampleNode(object):
path = pathTracking()
dag = None
obj = None
nodeName = ""
someVar1 = "blah blah"
def initialize(self,nodeName,obj,dag):
if obj or dag:
self.obj = obj
self.dag = dag
elif nodeName:
self.path = nodeName
else:
return False
return True
other file:
import trackingMethod as trm
circleExample(trm.exampleNode):
def __init__(self,nodeName="",dag=None,obj=None):
if not self.initialize(nodeName,obj,dag)
self.path = cmds.circle()[0]
and with this method I can do
circles = [circleExample(nodeName=x) for x in cmds.ls(sl=1,l=1)]
PS. I ran into some stuff that required the class to be initialized before some of its bits could be created. Below is a custom dict that required I pass an instance of self to it at the time the dict is created. Recreating these dict structures in every class that interacts with a transform would have been tedious. The solution was to put these dependent class initializations into a function in the transform class. That way the final class inherits the function to create the dicts and can call it in their init. This avoids a whole russian nesting doll of init statements that breaks when you have multiple files inheriting from a single class.
While this solution may seem obvious to some, I was just about pulling out hair to think of a way around a chicken egg situation of needing to init the class to get self, but not being able to init class due to unbound method errors.
class sqetDict(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(thing,(connection,Attribute,xform)):
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(thing,(connection,Attribute,xform)):
thing.__set__(self.instance,value)
else:
dict.__setitem__(self,key,value)
These dicts would be initialized like this:
def enableDicts(self):
self.connection = sqetDict(self, {"txyz": connection("translate"), "tx": connection("tx"),
"ty": connection("ty"), "tz": connection("tz"),
"rxyz": connection("rotate"),
"rx": connection("rx"), "ry": connection("ry"), "rz": connection("rz"),
"sxyz": connection("scale"),
"sx": connection("sx"), "sy": connection("sy"), "sz": connection("sz"),
"joxyz": connection("jointOrient"),
"jox": connection("jox"), "joy": connection("joy"), "joz": connection("joz"),
"worldMatrix": connection("worldMatrix"),
"worldInvMatrix": connection("worldInverseMatrix"),
"parentInvMatrix": connection("parentInverseMatrix")})
self.value = sqetDict(self, {"txyz": Attribute("translate", "double3"),
"tx": Attribute("tx", "float"), "ty": Attribute("ty", "float"),
"tz": Attribute("tz", "float"),
"rxyz": Attribute("rotate", "double3"),
"rx": Attribute("rx", "float"), "ry": Attribute("ry", "float"),
"rz": Attribute("rz", "float"),
"sxyz": Attribute("scale", "double3"),
"sx": Attribute("sx", "float"), "sy": Attribute("sy", "float"),
"sz": Attribute("sz", "float"),
"joxyz": Attribute("jointOrient", "double3"),
"jox": Attribute("jox", "float"), "joy": Attribute("joy", "float"),
"joz": Attribute("joz", "float"),
"rotOrder": Attribute("rotateOrder", "string"),
"worldMatrix": Attribute("worldMatrix", "matrix"),
"worldInvMatrix": Attribute("worldInverseMatrix", "matrix"),
"parentInvMatrix": Attribute("parentInverseMatrix", "matrix"),
"rotatePivot": Attribute("rotatePivot", "double3"),
"visibility": Attribute("visibility", "long")})
self.xform = sqetDict(self, {"t": xform("t"), "ro": xform("ro"), "s": xform("s")})
my connection class does the cmds.connectAttr when sent a value, and it returns the various attributes of a connection as a dict like {"in": "in connection", "out":["outConn1","outCon2",etc..], "path":"fullpath name to attribute"}. So you could do something like, thingA.connection["txyz"] = thingB.connection["txyz"]["path"] to connect the relative translates of two objects.
My Attribute class allows set and get of attribute values, like temp = thing.value["txyz"] results in temp = (value,value,value), and thing.value["txyz"]=(0,0,0) would zero the translate.
xform does the values thing but in absolute world space values.