Top  | Previous | Next

Scope and Import

The concept of scope is very important in all programming, and Python is no exception. Scope defines what names are directly accessible without any qualifiers. Another way to put this is that the scope determines what variables are defined.

 

Definition by Assignment

In Python, a variable is defined at the time that it is assigned. What scope it belongs to is also defined by where the assignment occurs.

 

doSomeWork() # on this line, there is no variable 'x' in scope

 

x = 5 # now 'x' is defined in our scope, because we've assigned a value to it

 

print x # This will work just fine, because x is in scope.

 

 

Function Scope

When you define a function, that function gets its own scope. Variables that are assigned within that function body will not be available outside of the function.

 

def myFunction():

   x = 15 # x is local to myFunction()

   print x # This will work, because it is part of the function

 

y = x + 10 # This will fail, because x is not available in the outer scope

 

Module or "global" scope

Note: The definition of global described in this section is as of Ignition 7.7.0. Prior to this version, Ignition used different scoping rules. See the section below about Legacy Scoping.

 

There are lots of places to write Python code in Ignition. In Python terminology, each of these spots is called a 'module'. If you're reading Python guides, you'll also see them called 'files', because if you were outside of Ignition, these would be *.py files.

 

Variables defined in a module are implicitly global. This means that sub functions may reference them, as long as the sub function does not also define a variable of the same name through assignment. There is a special keyword, global, that can be used within a function to let Python know that you're trying to reference the module-scoped version of a variable, and not create a private local variable.

 

Consider the following example module

 

x = 'hello'

 

def foo():

   print x

 

def bar():

   x = 'nope'

 

def baz():

   global x

   x = 'world'

 

foo() # will print 'hello'

bar() # does nothing, because x inside of bar() is local

foo() # will print 'hello' again

baz() # re-assigns x

foo() # will print 'world'

 

Note that the term 'global' here is somewhat misleading. Unlike in previous version of Ignition, variables marked global are not shared with other scripts. They are only global within the module that you're editing.

Using the import keyword

You can import the namespaces defined in other scopes into your scope with the import keyword. Most commonly, you'll import from global library sources, like system (the Ignition standard libraries), project (your project's script library), java (importing from the Java standard library), and the various python standard libraries. When you're writing component event handlers, system, shared, and project are imported for you automatically.

 

The import keyword can be used in a variety of forms:

import X
from X import Y

 

For example, suppose you wanted to use the java.util.Calendar class for some date manipulations. You could import this in a number of different ways. These examples are equivalent, printing out a date 8 hours before the current date.

 

import java

cal = java.util.Calendar.getInstance()

cal.add(java.util.Calendar.HOUR, -8)

print cal.getTime()

 

from java.util import Calendar

cal = Calendar.getInstance()

cal.add(Calendar.HOUR, -8)

print cal.getTime()

 

Legacy Scoping

In Ignition version 7.6 and prior, the scoping rules regarding the global keyword were different. In these versions, variables marked global were accessible from all scripts in the system. Also, module scope did not work the same way. Examples like this would not work

 

x = 5

def foo():

   print x

 

and instead had to be written like this:

 

x = 5

def foo(x=x):

   print x

 

Legacy scripting modules (app.*) continue to run under the old scoping rules for backwards compatibility purposes. Their replacements (shared.* and project.*) run under the new scoping rules. Other scripts such as component event scripts let the user pick which scoping rules to use. To recap, the choices are:

 

Legacy Scoping: Functions cannot access module variables, global means any script can access
Standard Scoping: Functions can access module variables, global only means within that one module.

 

If you have a project with mixed scope rules, you may have a need to access a legacy style global variable from a standard style script. To do this, you can use the system.util.getGlobals() method, which returns the global namespace as a dictionary. This provides access to the legacy style of global variables.