Global vars are bad, but how else can I get what I want? (PyMEL)

Scenario:

I’ve created a scriptJob which triggers a function called checkSel(), and it does this on SelectionChange. It is a function which checks a certain condition (if a mesh is selected) and then returns data from the mesh.
And since the user might already have a mesh selected upon starting my tool (thus, avoiding triggering the scriptJob) I have to run checkSel() manually in the code. Anyway, my problem is the returned variables comming from checkSel. I don’t know how to basicly make the scriptJob call this function and have a set of variables overwritten. Maybe the code explains it better:


    # Tool functions

    # Tool UI

    # Display the window
    pm.showWindow( window )

    # Selection check and core variable creation
    varA, varB, varC = checkSel()
    
    # Create scriptJob
    pm.scriptJob(
        event=["SelectionChanged", lambda *args: varA, varB, varC = checkSel()], ## WARN: Syntax Error
        parent=window

toolUI()

Works: Running my tool with a mesh selected (and by avoiding the syntax error in the scriptJob by just calling checkSel without trying to assign the returned data to variables)

Doesn’t work: Running my tool without a mesh selected, then selecting a mesh, and running a core feature.

Why it doesn’t work: Core feature requires varA, varB and varC to be updated by the scriptJob

So now I’m sitting here actually considering making varA, varB and varC into global variables and just avoid passing variables around. But global variables are evil (or that’s pretty much what everyone says!).

Best approach here?

I usually follow this pattern:


class MyWin(QtGui.QMainWindow):
    def __init__(...):
        self.__selectedObject = None
        self.scriptjob = cmds.scriptJob(parent='MayaWindow|myWin', 
                                        event=['SelectionChanged', self.updateUI])
       
        self.updateUI()


...

    def updateUI(self):
        selection = cmds.ls(sl=True)
        self.__selectedObject = selection[0]


it sounds like you want to update some Class variables each time the Selection Changes, this is pretty easy since any method of the class instance can access and update any of the local variables. No need to pass them around.

Class variables is the way to go, that lets you grab thing like a current list or registry without knowing which instance may have updated it.

Thanks a bunch!
Making the entire tool into a class is a solid solution.
I thought at first that this was a syntax error -issue but later realized that it’s about scope: Nested functions can access - but not modify - variables from outer functions. And I have been trying to modify such variables, but ended up passing variables around (which ofc failed when I came to the creation of the script job!).
I found out there are alternative ways to using a class though: you can use the “nonlocal” statement to access non-local, non-global scopes from inside a nested function. But that’s for Py3 only

But for Py2 you can do use a mutable object and update the members of that object, like:

def someFunc():
    someVar= [0] # List or dict is fine

    def nestedFunc():
        someVar[0] += 1 # Modifying member of the outer var instead of the var itself

closures can be an elegant solution but be careful with them : it’s easy for state to ‘leak’ from one place to another invisible. Classes are slightly clunkier but much more explicit.

Alright, I’ll keep that in mind. Thanks!