Rename nodes according to their own variable in python script?

maya
python

#1

I’m not an advanced coder by any means, so sorry if this is dumb, but is there any way to “listen” for the variable name a node string is assigned to, when it’s created?

The core of this is an attempt to make the act of coding in maya less painful, similar to BigRoy’s awesome Nodex project from a few years ago. I’m working on a couple of wrapper functions around connectAttr, setAttr, etc, but I’m having trouble with createNode and the naming of specific nodes.

So for example, I can type:
radDiv = CN(“mddiv”)

and get a multiplyDivide node set to divide.
Not bad, but it still only has a default name, unless I type:

radDiv = CN(“mddiv”, n=“radDiv”)

That’s like half as much text again. I’m probably getting too hung up on this, but I’m going to type this command thousands of times over my career, and those keystrokes are going to add up. Ideally, I want to type in the python script:

radDiv = CN(“mddiv”)

and have a node generated and automatically renamed to the variable it is known as - “radDiv”.
Is that possible?
Thanks


#2

There’s no way to get away from typing in your example unless you want to get into deep Python magic. In the end it’s going to save you two quote marks, so it’s not a good use of your time. You could do this:

rad_div = 'raddiv'
rad_div = cmds.createNode('multiplyDivide, n=rad_div)

Which will work – but it’s bad practice to reuse the same variable name for different types of things. You can make it a little better like this:

def  mult_div(name= "mulitpliyDivide#"):
      return cmds.createNode('multiplyDivide', name):

rad_div = mult_div('some_name_here')
rad_div2 = mult_div('some_other_name_here')

Which will get you out of the string names for createNode. That’s a very common and legit use, it actually makes the code more readable because it’s easier to parse than “CN” plus a string. Even here you might find you want to pass in some command flags to maya and you’ll have to learn about how python handles keywords to do that – but for a lot of cases you can just manufacture some named functions to clean up maya’s rather ugly and wordy way of doing things.

A couple of things to consider:

  1. don’t worry about the typing. It’s a pain in the ass when you are experimenting in the listener, but future you will be glad if the code is clear and readable instead of so short that it is hard to parse

  2. you’re never guaranteed to get the name you ask for – maya can’t have two items with identical names so if you run the same code twice, you’ll get radDiv and `radDiv2’ So it’s better to always use this pattern:

    1. capture the name when you makes something: rad_div = cmds.createNode('multiplyDivide', n='radDiv')
    2. If you rename it, capture that too: rad_div = cmds.rename(rad_div, 'new_name')

If you really hate dealing with cmds, you might want to experiment with pymel. Cmds is definitely clunky, but it’s good to know what’s actually happening before you embrace the magic wrapper. You can definitely write code that will let you avoid getattr and setattr but it’s a good idea to understand the way the flow actually works first, otherwise when you run into something that’s not wrapped or is a bit non-standard you’re not helpless


#3

Thanks very much for your feedback! That nodule system looks very interesting, and thanks for the insight into the best practices, it seems like a good compromise.


#4

Do what Theodox says, because it’s the right thing to do. It’s readable, understandable by other people, and by you after you haven’t touched the code for months (or years).

Also, having programmed primarily in python for over 10 years, I have never done what I’m about to describe, which indicates it’s probably a bad idea. But maybe someone will stumble on this and they’ll have a problem and this will let them solve it perfectly.

Final warning: this is probably not a good idea, there are tons of issues, like not being able to handle name collisions well, or if you do explicitly name something, not clobbering it, and several things I haven’t thought of.

On to the bad idea…

I think the “easiest” way to do this would be to use the locals() function, which is a dict of all the variable names (as strings) and their values. It might look something like this:

from pymel.core import *

def yourFunction():
    
    # Each on of these variables will be reflected in locals(), including yVal        
    spine1 = joint()
    yVal = 30
    pelvisControl = polyCube()
    pelvisControl.ty.set(yVal)
    
    # ... Lots more work is done here
    
    renameFromVariable( locals() ) # Need to  pass your def's locals.
    
    
def renameFromVariable( localsDict ):
    
    for name, val in localsDict.items():
        try:  # Again, haven't tried this, anything could go wrong
            if objExists(val): # Check if the value is a maya obj since EVERY variable will be in this list, like 'yVal'
                val.rename( name )
        except Exception:
            pass

Again, I don’t recommend this, listen to Theodox.


#5

Lol, thank you for telling me exactly what not to do. I’m definitely not pursuing it any further as a feature, but this sort of stuff is still fascinating to me - it’s interesting to see all the behind-the-scenes working that (I assume) goes into making a language as free and fluid as python.


#6

There’s a working example of a similar technique here using inspect.currentframe() which is almost the same as locals; it also is strictly limited to a special class of target objects. But in that case the application has a very strictly delimited use case, building GUIs with a context manager syntax that provides a natural scope.

The real problem however is that it’s impossible to guarantee that variable X will ever contain an object named “X”, because maya will give you what it wants to give no matter what you ask for. So it’s an interesting mental exercise but a bad codiing strategy.

Simpler is better :slight_smile:


#7

So very true, your future self will hate you less if you don’t try to be overly clever.