Python structure help

Hey guys,

New to writing Python and would like some advice on structure.

I am defining a bunch of variables at the start of my script. These are useful in various definitions that follow - hence trying to do them at the top is handy - however there is a problem I foresee.

These variables are defined at the import or load of the py. They relate to the current file and it’s path, contents of the scene, etc. If I build a IU and import that .py, and start doing work, it is quite likely that the variables will not be relevant for very long - and will need redoing. Refreshing them with each definition defeats the attempt of repeatedly creating the variables. I had considered that each defination refreshes via reload the entire .py but that all feels hacky. I feel like neither is proper and as I am still with basics, don’t know if I have yet to learn the correct method or if I’m just being dumb.

Advice on how I should sort my scripts?

Cheers,
Ollie

It sounds like you should probably look at using a class given that you’re talking about per-instance usage (class instance per scene etc).

Using module level globals in the way you describe is a little dangerous for anything other than static variables.

I would consider either :
[ul]
[li]instancing a class on a new scene event using MSceneMessage.addCallback
[/li][li]creating a wrapper function (or a singleton) which tests whether it needs to return a new class, or re-use the existing one
[/li][/ul]

An example of the latter might be:


# -- Access Maya
import pymel.core as pm

# -- Global variable to store an instance of the current
# -- scene class to prevent re-calling the class each time
_CURRENT_INSTANCE = None


class SceneData(object):

    def __init__(self):
        self.scene_path = pm.sceneName()

        # -- Store some data specific to this scene
        self.some_scene_specific_data = None



def get_scene_data():
    
    # -- Access the global variable as a global
    global _CURRENT_INSTANCE

    # -- If we have a cached class and it is for the
    # -- current scene, utilise that rather than re-instance
    if _CURRENT_INSTANCE and _CURRENT_INSTANCE.scene_path == pm.sceneName():
        return _CURRENT_INSTANCE

    # -- Instance a new class and return it
    _CURRENT_INSTANCE = SceneData()
    return _CURRENT_INSTANCE

If you want to take the singleton approach (which is probably nicer from a calling perspective) this shows you how to do that:

If you have a set of related operations that need to share data, that’s a great case for a class. You create the class instance and fill out it’s fields and then all the methods know about ‘their’ copy; you can just make a new instance to use for different data.

OTOH If you have a bunch of data you need to share for lots of unrelated operations, a singleton will work but a more python-friendly approach is simply to store the ‘singleton’ data in a module-level variable, since modules are effectively singletons. But you DONT want to change module level vars dynamically (usually you don’t want want to do this in a singleton either, since you don’t know who’s using your singleton or why).

Thank Mike,

Although I don’t understand a lot of that, you answered my question perfectly. Simply a case of not knowing of what one does not yet know.

Goes away to learn about classes, wrappers, singletons, and those funny _underscores that no tutorial has yet explained…

:D:

EDIT: Thanks as well Theodox!