Sticky variable alternative

Hey,

Is there a better way to have python remember variables between recomputes than using sticky variables? I have been working on a CNC project where I generate motor movement commands through grasshopper. I also wrote a component in python that will simulate the motion/position of the machine. I “animate” the simulation by stepping through each line of the commands by using recompute/F5. And I use sticky variables to hold a bunch of different things that I want to carry through between each recompute (is there a better word for this). The script works, I am just curious if there is a better solution than sticky variables. I found having to type the extra brackets and quotation marks kind of tedious. Is there a work around? Sticky class?

from scriptcontext import sticky as st
st['myvariable']="works, but does not look natural"

Lawrence Yun

1 Like

I prefer to use the if “foo” not in globals(): method for making persistent (or “static mutable” I suppose) variables. These are also local to the individual GHPython component in which they are instantiated, simplifying things quite a lot (if you do not need them to be global across Grasshopper/Rhino).

1 Like

Can you elaborate? I am not familiar with the globals() method.

I’m on my phone, so can’t provide an example right now, but have a look at the links in the second point here:

@lawrenceyy, you could create your own class (instance), and put that into one single sticky value. So it survives between sessions while Rhino is open and you can avoid typing the brackets and quotation marks. If you want to remember it after Rhino has been closed, the sticky dict or the class with all properties can be written / loaded using pickle.

_
c.

I think I understand what you are doing. By default, python seems to remember variables declared at the highest level. You are exploiting this and testing to see if they exist by doing if something not in globals(). This script counts up with each recompute (there is also a button that resets to 0):

if reset==True or "counter" not in globals():
    counter=0
else:
    counter+=1
    print(counter)

The only downside is that sticky variables seem to be editable at all levels, like in functions. With these regular variables you have to use global.

def setup():
    global counter
    counter=0

def main():
    global counter
    counter+=1
    print(counter)

if reset==True or "counter" not in globals():
    setup()
else:
    main()

Thanks for the tip. This seems cleaner than sticky variables.

Interesting idea. Sounds like you are suggesting that I essentially save everything to the sticky variable at the end of the script and somehow unpack them at the beginning of the script. That could certainly work.

Yes, initialize an empty class and make this instance a global variable. At the end of the script, store it in sticky so you can get it back once you start the script the next time.

_
c.

Yes that’s exactly correct, I find it much simpler for encapsulating local persistent/dynamic logic (than sticky).

I’d advice against using global and instead either have class methods/functions input, return and overwrite (append, manipulate, whatever you need) persistent variables you’ve instantiated within the if "foo" not in globals(): scope. Remember, this data can be anything. Leading to the second option: instantiating instances of your custom class as persistent variables, and then calling methods on these. I use this design a lot for writing dynamic system such as this one:

Where the car “agents” is a list of class instances i’ve instantiated using this method, and than I call a drive() method on these each time the component updates. When resetting the system I then wipe/re-instantiate all the cars like so:

2 Likes

Thanks for the advice. I am aware that its not good to manipulate global variables within functions. It’s a bad habit from writing quick and dirty python scripts. I am glad you pointed me this in direction. I had noticed before that python seemed to retain variables between recomputes. I just did not know it did so reliably. I really only noticed it before when I would decide rename a variable halfway through a writing script, accidentally leave some not renamed, and find that the script worked anyway. Obviously the script would fail after restarting Rhino since the global variables are cleared. Thanks for your help.

I too used to think of these phanthom variables as a bug, but have come to appreciate them as a really useful feature :nerd_face:

I ran into a problem the other day. Initially I created the global variable com in setup(), but later moved it outside. com is edited later in setup(), but I forgot this fact. What confused me most was that traceback pointed me to a line 7 where I reference com when it should have pointed me to line 11 where I actually try to edit a global variable. I understand that python probably perceives the com in line 7 as a local variable because the com in line 11 is edited. All I am trying to say is that traceback should have pointed to line 11, or both 7 and 11. That would have saved me a lot of time in remedying this error.