# Global objects in Perspective Scope

**URL:** <https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688>\
**Category:** Ignition\
**Tags:** ignition80\
**Created:** [December 2, 2021, 5:19pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688 "2021-12-02T17:19:01Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![phandc](https://avatars.discourse-cdn.com/v4/letter/p/ce73a5/32.png) [@phandc](https://forum.inductiveautomation.com/u/phandc)\
**Post date:** [December 2, 2021, 5:19pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/1 "2021-12-02T17:19:01Z")

</div>

Hi everyone, I am trying to figure out how global objects in Perspective Scope work.  
I have a view with a numeric entry field that will receive the input of the user. I also have a class TestGlobalScope which will take the value of the numeric entry field when its value has changed.

```auto
class TestGlobalScope:
      def setSetPoint(self, s):
        self.setpoint = s

```

On event configuration of the numeric field, I have configured it to initiate an instance of TestGlobalScope in the onStartup event. I also updated the instance object’s value when the input value had changed in onActionPerformed. But when I tried to execute the script, it raised the error ‘global name ‘g’ is not defined’.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/c/d/cd361b7c2b1d4d9f01a02088831965ddca42b637.png)

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/7/5/754ed98bb428b90889c0f1429ce9535886173ce1.png)

From the document [Perspective Event Types Reference] ([Perspective Event Types Reference - Ignition User Manual 8.0 - Ignition Documentation](https://docs.inductiveautomation.com/display/DOC80/Perspective+Event+Types+Reference)), it says that onStartUp and onShutDown events in System Events are similar to the componentDidMount and componetWillUnmount methods in React. I suppose that creating a global object via Python syntax in component events is actually creating a distinctive object in JavaScript. Because the events are separate, they don’t share info with each other.  
I also know a way to create a global object in Perspective via perspective. session.custom. However, we don’t want to assign the object in our Python scripts to it directly in some cases.  
I have tried another way to create a global TestGlobalScope object in python script. Then I tried to call it inside the events above. And it worked. I don’t really find the relation between the python code in the script project with the one in the component’s event.

![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/8/b83161f8f1ee4212ea842428f5d30ffb29220ee6.png)

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/1/f/1fc6d440ce597a54396fd358b73e3d671f9956ae.png)

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/a/2/a23f8cdd64ac91b31ca8b2524c589f009d379a61.png)

Thank you for your time!

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 2, 2021, 5:21pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/2 "2021-12-02T17:21:08Z")

</div>

Putting global data anywhere but tags, session props, or `system.util.globals() / system.util.getGlobals()` is either asking for trouble or simply won’t work.

(worth noting session props aren’t true global like the other 2 options if that’s not obvious)

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [December 2, 2021, 5:22pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/3 "2021-12-02T17:22:57Z")

</div>

Is it generally safe to put custom class instances inside `getGlobals()`, or do they need to be serializable?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 2, 2021, 5:24pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/4 "2021-12-02T17:24:33Z")

</div>

Looks okay to me, they aren’t ever persisted as far as I can tell, and they aren’t part of redundancy in any way.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 2, 2021, 6:35pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/5 "2021-12-02T18:35:43Z")

</div>

> [@kgamble](#):
>
> Is it generally safe to put custom class instances inside `getGlobals()` , or do they need to be serializable?

No. Unless the project script that defines the class includes code to replace any persistent instances whenever the script restarts. Jython class instances reference the code that defines them, which will be old code after the defining script restarts. That old code lives in an old interpreter, which leaks huge chunks of memory. Be absolutely sure you replace custom class instances in any persistent use. That isn't limited to just .getGlobals() or my `system .util.persistent()` function, but would include anywhere you've added a listener into Ignition's infrastructure.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 2, 2021, 6:37pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/6 "2021-12-02T18:37:38Z")

</div>

Oh, and I don’t think you can serialize jython class objects.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 2, 2021, 6:39pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/7 "2021-12-02T18:39:57Z")

</div>

Ooph, Phil I think you are correct. Don’t listen to me 🙂

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [December 2, 2021, 7:38pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/8 "2021-12-02T19:38:55Z")

</div>

Interesting,

So then that seems to get rid of any opportunities for singletons right? Or would it be possible to trigger off the script restart and replace the singleton with a new instance from the potentially updated code?

EDIT: Would checking the type like this work in a way that verifies its accurate to the current version prior to use? Obviously some work would be needed to make sure properties of the new one can be re-built from properties of the old one

```auto
def getMyClass():
	if 'myClassInstance' not in system.util.globals:
		print("Adding new instance")
		system.util.globals['myClassInstance'] = Test.myClass()
	elif not isinstance(system.util.globals['myClassInstance'], Test.myClass):
		print("Replacing existing instance")
		system.util.globals['myClassInstance'] = Test.myClass(system.util.globals['myClassInstance'])
		
	return system.util.globals['myClassInstance']

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 2, 2021, 7:54pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/9 "2021-12-02T19:54:46Z")

</div>

You have to end up with no references to the old instance. Anywhere. A singleton sounds like a good solution. The key is to not accidentally hang on to references elsewhere. The weakref module can help in some cases.

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [December 2, 2021, 7:56pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/10 "2021-12-02T19:56:39Z")

</div>

Does the edit I added above make sense to cover this issue?

In a project I would likely do this by overriding ` __new__ ` but I made this a function here for easy example

Glad you’re helping clarify this, as I was about to need to add this in a project!

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 2, 2021, 7:58pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/11 "2021-12-02T19:58:00Z")

</div>

> [@kgamble](#):
>
> Would checking the type like this work

No idea. Test. Or better, just replace it unconditionally in the top level of the defining script. If that runs, you know it will be new code.

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [December 2, 2021, 8:00pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/12 "2021-12-02T20:00:49Z")

</div>

I did test it before I asked, was mostly asking from a memory leak standpoint. It works from a code standpoint.

I am not exactly sure how Jython handles memory in this case, or if I am missing some other horrible practice here.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 2, 2021, 8:24pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/13 "2021-12-02T20:24:55Z")

</div>

Replace it unconditionally in the top level of the defining script. Something like this:

```auto
class myClass():
	__init__ (self, prior):
		# Copy important values from prior version, as long as they
		# are platform data types. Stop any threads stored in prior
		# and remove any of its listeners from the platform.
		pass

# Get the persistent global dictionary
_g = system.util.getGlobals()

# Protect the swap with a lock. Locks are defined by
# the jython stdlib, so do not have to be replaced on restarts.
# Use setdefault for assignment to ensure atomicity.
singletonLock = _g.get('singletonLock', None)
if singletonLock is None:
	import thread
	singletonLock = _g.setdefault('singletonLock', thread.allocate_lock())

# Swap old and new under the lock. This prevents
# races amongst multiple scripting contexts importing this script
# simultaneously. Just note that a new version might be replaced by
# another script context as soon as the lock is released.
with singletonLock:
	_g['singletonKey'] = myClass(_g.get('singletonKey', None))

# Use the following pattern in functions where you need to use the
# singleton. Whatever you do, never sleep or do long calculations
# while holding the lock.

# with singletonLock:
# c = _g[singletonKey]
# # Do something with c

```

---

<div class="post-metadata">

**Author:** ![phandc](https://avatars.discourse-cdn.com/v4/letter/p/ce73a5/32.png) [@phandc](https://forum.inductiveautomation.com/u/phandc)\
**Post date:** [December 3, 2021, 3:23pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/14 "2021-12-03T15:23:41Z")

</div>

@pturmel , @Kevin.Herron , @kgamble Thank you very much for the information.  
However, I still don’t have the full answer to my question. Why did it work in my  
second scenario?

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [December 6, 2021, 5:11pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/15 "2021-12-06T17:11:30Z")

</div>

My guess is that its related to scripting restarts during a save/preview update and something to do with local variables in the `runScript` functions, vs using the actual `global` library to set the variable inside the `runScript` function vs not.

However I am not really positive, that’s just a guess incase one of the others tagged knows a more detailed answer…

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [December 10, 2021, 4:48pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/16 "2021-12-10T16:48:53Z")

</div>

A post was split to a new topic: [Adding listeners to Ignition](https://forum.inductiveautomation.com/t/adding-listeners-to-ignition/53997)

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [February 4, 2022, 7:19pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/17 "2022-02-04T19:19:20Z")

</div>

Where should the singleton lock code execute? Inside the actual init method of the class? I see that you didnt put it in there in this example.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 4, 2022, 8:33pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/18 "2022-02-04T20:33:56Z")

</div>

Use it everywhere you work with the singleton class. That prevents replacement of the instance you are working with until you release the lock. As long as every locked section leaves the singleton in a consistent state, you can’t break it.

The lock is not needed in the init method of the class because that is only ever called from the bit of code inside the lock at the top level of the script module. Only one instance is allowed to exist–that’s what a singleton is.

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [February 4, 2022, 9:00pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/19 "2022-02-04T21:00:19Z")

</div>

Okay, so say I want to use it in a function, is below a close representation of how I would get the instance and verify it isn’t locked? Then I presume if it is I would need to try again in X seconds, or raise an exception, or something.

```auto
def myFunction():
	_g = system.util.getGlobals()
	singletonLock = _g.get('singletonLock', None)
	if singletonLock is None:
		singletonLock = _g.setdefault('singletonLock', thread.allocate_lock())
		with singletonLock:
			_g['singletonKey'] = myClass(_g.get('singletonKey', None))
                        
			myInstance = _g['singletonKey']
			myInstance.performSomeAction()
	else:
		# Singleton is currently in use
		# try this again in a sec to see if it gets unlocked

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 4, 2022, 9:17pm UTC](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688/20 "2022-02-04T21:17:53Z")

</div>

You’re making it too hard. Just this, when the function is in the same project script:

```auto
def myFunction():
	with singletonLock:
		myInstance = _g['singletonKey']
		myInstance.performSomeAction()

```

Anywhere else, do this:

```auto
with path.to.script.singletonLock:
	myInstance = path.to.script._g['singletonKey']
	myInstance.performSomeAction()

```

[Next page](https://forum.inductiveautomation.com/t/global-objects-in-perspective-scope/53688.md?page=2)
