Questions about script modules - global variables, scope, etc

I have a few questions about the finer details of how script modules work.

Part 1 ~

In a script module (shared.testing) I have the following:

x = 1
print 'before x=', x
def changeX():
	global x
	print 'before:', x,
	x += 1
	system.tag.write('x', x)
	print 'after:', x
print 'after x=', x

the first time I run the script I get the following output:

>>> shared.testing.changeX()
before x= 1
after x= 1
before: 1 after: 2

the second time I run the script I get the following output:

>>> shared.testing.changeX()
before: 2 after: 3

what is different about the first time I call a function from a script module than the other times? Why do the print statements get executed the first time and not any time after?

Part 2 ~

Condidering the same script above. If I call the script function changeX() from a button action performed event script on a window in the designer in preview mode, say 4 times (assuming right after the script was commited) then the output on the console window is:

before x= 1
after x= 1
before: 1 after: 2
before: 2 after: 3
before: 3 after: 4
before: 4 after: 5

now if I call the script function from the script console I get:

>>> shared.testing.changeX()
before x= 1
after x= 1
before: 1 after: 2

It seems the designer and script console each have their own instance of the global variable ‘x’. Does the designer have a different scope than the script console? I thought (at least with previous versions of Ignition) that the designer and script console had the same scope (I recently upgraded from 7.7.7 to 7.9.3)? It also seems that each client instance and the gateway all have their own scope for these scripts and thier variables. But that’s expected I suppose.

Part 3 ~

The first time I call the changeX() function the global variable ‘x’ is instantiated. Say I do this from an event script on a window. If I close the window and open it again the global variable persists. When does it go away? When the client is closed? What about in other scopes (ie. gateway and script console)?

Python and Jython import a module by executing it once and effectively loading the resulting module globals dictionary (including both 'x' and 'changeX' in your example) into RAM under the module name. Note that executing a def statement places the following function code in the module dictionary as a callable object -- it doesn't execute the function during import. Further imports simple reference or retrieve items from that symbol dictionary.

Yes, in current versions of Ignition, the script console is in its own context. Consider testing using actionPerformed events of generic buttons.

No, the global variable 'x' is instantiated when the script is imported the first time. If you didn't have 'global x' in your function, the += assignment would add one to the value of the global variable and save it in a function local variable 'x', leaving the module level 'x' unchanged. The 'global x' statement tells python to divert assignments to 'x' back to the module level.

1 Like

Part 3 ~

When the script is imported for the first time the global variable ‘x’ is instantiated. Now ‘x’ exists in RAM. When is ‘x’ deleted from RAM?

When the program terminates or when you delete it with “del x” in your code.

The program being the client or gateway for example?

Yes, the client, designer or gateway. Each one of those are a separate programs that can have Python code running in them.

1 Like

It’s really important to remember that the gateway and each client and designer have separate scripting contexts, just like the script console vs. the designer. They aren’t shared memory.

1 Like

There are different ways to share data between the different contexts:

  • Regular memory tags can be used to store simple values. Every time you read from it, it will request the value from the server. Do note that this isn’t thread-safe. If two clients write to it at the same time, only one write will result in the final value. Especially if you plan to store bigger amounts of data in a tag (f.e. a complete dataset) that often gets modified by multiple clients, this can cause problems.

Another thing to note is that when you update the script, all global variables will be reset. But if you use tags, the values will be kept. If your goal is to keep data in memory even over updates, but not share it between clients, then client tags are a good way to store the data.