PyMel is absolutely the way to go if you are going to program tools and pipelines in Maya Python.
Let me show you why I prefer it over maya.cmds.
Object Oriented vs Procedural
I think the below example illustrates the usage difference perfectly. In the comments, I am only stating what I experienced myself when switching from MEL to PyMel in 2009.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# To get the shape of selected object in maya.cmds import maya.cmds selected = maya.cmds.ls(sl=True)[0] shape = maya.cmds.listRelatives(selected, shape=True)[0] # -- VS. -- # To get the shape of selected object in pymel import pymel.general.core selected = pymel.general.core.selected()[0] shape = selected.getShape() # Kicker is that you can stay in the comfort zone of maya.cmds with pymel # IF you really prefer the below to the above style. # Inevitably, you will start using the object oriented approach # because it is more accessible and results in less code. shape = pymel.general.core.listRelatives(selected, shape=True)[0] |
PyMel
- Object oriented – results in code that is shorter and more readable.
- Open source and maintained on GitHub
- Wraps all MEL commands
- It also contains everything maya.cmds does so you can mix and match between procedural and object oriented – if you want to.
maya.cmds
- Procedural
- Maintained privately by Autodesk
- Wraps all MEL commands
Some more examples
If you just overview the following 2 code sections, you get a glimpse of what your code files will start to become. You write a ton of code right?
PyMel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# safe to import into main namespace (but only recommended when scripting interactively) from pymel import * for x in ls( type='transform'): # object oriented design print x.longName() # make and break some connections x.sx.connect(x.sy) x.sx.connect(x.sz) # disconnect all connections to .sx x.sx.disconnect() # add and set a string array attribute with the history of this transform's shape x.setAttr('newAt', x.getShape().history(), force=1) # get and set some attributes x.rotate.set([1, 1, 1]) trans = x.translate.get() # vector math: trans *= x.scale.get() # ability to pass list/vector args x.translate.set(trans) # call a mel procedure mel.myMelScript(x.type(), trans) |
maya.cmds
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
if objs is not None: for x in objs: print mm.eval-('longNameOf("%s")' % x) # make and break some connections cmds.connectAttr('%s.sx' % x, '%s.sy' % x) cmds.connectAttr('%s.sx' % x, '%s.sz' % x) # disconnect all connections to .sx conn = cmds.listConnections(x + ".sx", s=0, d=1, p=1) # returns None when it finds no match: if conn is not None: for inputPlug in conn: cmds.disconnectAttr(x + ".sx", inputPlug) # add and set a string array attribute with the history of this transform's shape if not mm.eval-('attributeExists "newAt" "%s"' % x): cmds.addAttr(x, ln='newAt', dataType='stringArray') shape = cmds.listRelatives(x, s=1 ) if shape is not None: history = cmds.listHistory( shape[0] ) else: history = [] args = tuple(['%s.newAt' % x, len(history)] + history) cmds.setAttr(*args, type='stringArray' ) # get and set some attributes cmds.setAttr('%s.rotate' % x, 1, 1, 1) scale = cmds.getAttr('%s.scale' % x) # maya packs the previous result in a list for no apparent reason: scale = scale[0] # the tuple must be converted to a list for item assignment: trans = list(cmds.getAttr('%s.translate' % x )[0]) trans[0] *= scale[0] trans[1] *= scale[1] trans[2] *= scale[2] cmds.setAttr('%s.scale' % x, trans[0], trans[1], trans[2]) # call a mel procedure mm.eval-('myMelScript("%s",{%s,%s,%s})' % (cmds.nodeType(x), trans[0], trans[1], trans[2])) |
The cost of awesome
The casting the pymel does to create the internal link to dag object has a slight performance cost.
Justin Israel set up a test that he recently ran in Maya 2015. The test iterated over 20 000 verts and transformed each slightly. Below you can see the results:
- Python API – 0.2959 sec
- maya.cmds – 0.5757 sec
- pymel – 1.6670 sec
What I do 99% of the time when writing tools, is casting way less than 20 000 api connections via PyMel, so for what you get, I would say that this cost is negligible, but it is good to be aware of in case you need to iterate 100k+ verts – you should do this via API….
Spread the knowledge