Tuesday, October 16, 2007

Some thoughts on Python in Maya

Today I figured it was about time I learned how to program Python in Maya and so I went to the task of reading the docs and converting a MEL script I had to Python. And it couldn't have been easier or more awesome, haha. Seriously, it was great. Very, verrrrrry smooth process. There are a couple of weird oddities that I ran into, but when you think about how Python is written and the general Python syntax it's pretty clear why this was the best option.

I'm pretty excited about this cause it was actually really easy to learn. I have programmed in MEL now for about 4 and a half years, so I've run into tons and tons of weird MEL syntax issues and intricacies with MEL UI layouts and so on that take a long time to figure out. Looks like all that knowledge is easily transferable to the new Python system, since you are using exactly the same commands!! I keep wanting to say it's like you're calling Python MEL commands, but that's not really the right, um, "nomenclature", dude. :) Technically, MEL is calling the Maya Command Engine, and it's doing whatever it needs to do to run a command. Now, Python is just doing the same thing. So I think about all those commands as "MEL Commands" (ls, floatSliderGrp, window, columnLayout, etc.) but really I think it's better to now think of them as simply "Maya Scripting Commands" - since you actually have access to those exact same commands, no matter if you're calling them from MEL or Python.

Anyway, with some decent Python programming experience, plus a pretty large knowledge of MEL, the learning curve (if you can even call it that) to learn how to program Python in Maya was about 45 minutes. :) Seriously, it's that straightforward, and Autodesk has beautifully documented it as usual. That's one thing about Maya that's really always been top-notch. Man that documentation is AWESOME. Anyway, I was impressed by how simple it was. There were maybe 5 subsections of documentation about Python in Maya, and a couple of those were about threading and using MEL global variables in Python which I skipped. So like 20-30 minutes of reading, and looking at a few examples in the new Maya Python Documentation, and that was it!! Awesome!!!

There is just one issue I assumed would be a bit confusing, and that's typing. Since in MEL you had to specify types (and literally there aren't many to choose from, you've got floats, ints, float arrays, int arrays, strings and string arrays, and that's about it), and in Python everything is using a strong dynamic type, I thought it might get a bit confusing. But it looks awesome and was clear and the documentation was stellar. Everything is just handled very nicely. Like sets of int arrays (like the XYZ positions from a set of points) are returned as a tuple of tuples or something to that effect. Very slick. This allows you to use Python's underlying power when dealing with tuples and lists and all the methods that come along with that. As well it looks like Autodesk did not supply the string array functions to Python, which was also a great idea, since obviously Python's string utilities are pretty fantastic and by not supplying the Maya Scripting version of these, they are implying that the user/programmer should really get to know (and learn) the Python ones instead. I think the same thing goes for some of those Math libraries, like abs() and other stuff that I hardly ever used in MEL. Good call on that for sure.

Let's see what else. Something that made me laugh (yes, I am a nerd, but I thought this was kinda funny and cool), was the changes needed due to zero-argument tags in MEL being converted to Python commands. It's kindof obvious when you think about it, but at first glance, I was like, "Whhhaaaaaat?!??!!" :)

The issue is that in MEL, there are a bazillion flags to commands which take no arguments. A classic example (I think this is what they use in the documentation) is the MEL command:

ls -sl;

Now at first glance, you don't for a second think that the -sl (selection) flag has any arguments. But actually it does, and it's hidden. If it's *NOT THERE*, i.e. you just call ls(), it's the same as saying "call ls() with selection set to False." So, the inverse, when you supply the flag, is essentially turning on the selection boolean attr, i.e. "call ls() with selection set to True."

This was a confusing point in the documentation that I didn't quite get on the first reading of it. But as I started to program and convert a MEL script to Python, it became quite clear. It does get pretty verbose and kindof hard to read (at least, less readable I think than MEL) when you have to then supply the "True" option to other stuff like the -q (query) flag. This feels redundant but it's obvious why this was necessary just based on the syntax and structure of Python. So it's kinda messy, and sortof hard to read. But I don't see how they could have any simple alternatives. So I guess this was the decision they had to make, and hopefully it won't have *that* much of an effect on readability of code and so on. An example of what I mean is here in the mc.window() command.

import maya.cmds as mc

def mainScriptMethod():
#Check to see if the window exists
if mc.window("mainScriptMethodWindow", q=True, ex=True):

Note that in MEL, this is much more direct and clear:

if (`window -q -ex mainScriptMethodWindow`) {
// Do something

Now obviously the Python code isn't terrible, I'm just used to the lack of verbosity in the MEL version of the code. I can imagine a list of flags on a Python Maya Command with a ton ton ton ton of these flag1=True, flag2=True, flag3=True, etc. That would eventually get pretty unreadable (already I prefer the MEL method for this with only 2 flags, image 10 flags), but still, I see why this was necessary in the Python implementation. And it's not a *huge* deal. Just a little verbose unfortunately. Oh well. Pretty much everything else about the Python stuff I've seen so far is just totally awesome.

Another place this is kinda weird to get used to is such a simple command like ls.

In Python: selectedObjects = mc.ls(sl=True)
In MEL: string $selectedObjects[] = `ls -sl`;

Haha, well I guess I'm kindof putting my foot in my mouth here. I see that MEL command and it looks completely natural and makes total sense. The need to define a string array (at least for readability purposes), those confusing backticks, I suppose in reality the strange and new (sl=True) argument is worth never having to worry if I need backticks or not anymore. :)

All in all, I am totally impressed.

The best part *by far* about the Python integration into Maya is... it took me a grand total of about 30 minutes to learn it. Beautiful. This is the way every new language should be!!!

I think the Autodesk people should really applaud/buy beer for the Docs team on this one too. It was really, reaaaaaaaaaally easy to pick it up. And I've been putting this off for ages because I was concerned about how long it was going to take or that there weren't going to be enough examples and so on.

Also... putting the Python Commands in EXACTLY the same format as the MEL commands was a very good move. I feel like Maya Developers really know those MEL Commands Docs like the back of their hand, and changing that minimally (and also keeping MEL and Python separate in the docs) was an absolutely fantastic plan. Well done!

Anyhoo, off to bed. But I'll be dreaming of import statements and being able to have classes in my Maya Scripts now. :)


Unknown said...

omg maya.cmds is a total mess :)
you should have a look at pymel

_that_ is something powerfull to convert mel to python, and simply working with maya in python

Matt Ostgard said...

Yes... look at pymel.. it's so much better.