Python Primer¶
This section will provide a short introduction to namespaces in Scorpion and Python. These concepts are important for everybody who wants to exploit the power of Python in Scorpion.
Coding style guides are important for code readability and maintenance, like importing modules and naming conventions see more on Python recommended style guide.
Variables and namespaces¶
All variables in Python, and every other programming language, are created and exist in a namespace. What is a namespace?
A namespace is a system that has a unique name for each and every object in Python. An object might be a variable or a method. Python itself maintains a namespace in the form of a Python dictionary.
Using PythonWin, an integral part for Python Extension for Windows, or Idle - yet another Python environment, one can play with namespaces.
An assignment is a statement of type a=b where a is a variable and b another variable, constant, constructor or function.
Vaiables and class methods should always start with a lowercase letter.
a=100
b=1.03
c=’spam’
e=[]
f={}
g=eggs()
are assignments where:
a is assigned an integer value,
b a floating point value,
c a string
e an empty list
f an empty dictionary
g the value of function or a reference to an instance of a class
When Python is initialized, a namespace is created. It is available for declaration of variables, functions and objects.
Declarations:
a=100
def foo(b):
print ‘a=’,a,’b=’,b
The statement:
foo(200)
Will yield the output:
a=100 b=200
Python searches for a local definition of a in foo(). If not found Python search in the global namespace. If a local variable is defined in foo() the result will be as follows:
Declarations:
a=100
def foo(b):
a=300
print ‘a=’,a,’b=’,b
The statement:
foo(200)
Will yield the output:
a=300 b=200
The statement:
print ‘a=’,a
Will yield the output:
a=100
Functions and name spaces can be nested:
a=100
def foo(b):
a=300
def spam(b):
a=400
print ‘a=’,a,’b=’,b
spam(500)
print ‘a=’,a,’b=’,b
The statement:
foo(200)
Will yield the output
a=400 b=500
a=300 200
The statement:
print ‘a=’,a
Will yield the output:
a=100
Lets modify this slightly:
a=100
def foo(b):
def spam(b):
print ‘a=’,a,’b=’,b
spam(500)
print ‘a=’,a,’b=’,b
The statement:
foo(200)
Will yield the output:
a=100 b=500
a=100 b=200
The statement:
print ‘a=’,a
Will yield the output:
a=100
Python finds the value of a by searching in the nested namespaces. To change a global variable we can instruct Python to do so.
a=100
def foo(b):
def spam(b):
global a
a=b
print ‘a=’,a,’b=’,b
spam(500)
print ‘a=’,a,’b=’,b
The statement:
foo(200)
Will yield the output:
a=500 b=500
a=500 b=200
The statement:
print ‘a=’,a
Will yield the output:
a=500
A Script - An ordered collection of statements¶
A script is an ordered collection of Python statements. Scripts are stored in a text format. This can be a file. The file is given the .py extension and is called a module. It can also be named a Script. To get access to the variable, classes and functions we use the import directive.
When loading the module all definitions and assignments are executed. Functions, classes and variables must be imported to get into scope. The module cannot access methods and functions defined outside the module unless the import statement is used.
How do we access the content of a module?
We create a module named OneModule.py with content:
a='One Module'
z='Another Module'
def foo(c):
print 'What happens next?'
Lets store the module in the directory c:\PythonPrimer. This is a directory Pyhton does not know. It can be added to the Python system path with the following statements:
import sys
sys.path.append(’c:\\pythonprimer’)
sys is a standard module in Python. path is a property in the sys module. More information about sys and path is found in the Python Help file.
Qualified Import
import OneModule
a = 100
print a
100
print OneModule.a
’OneModule’
We see that the two a variable are in different name spaces. We get access to OneModule.a using dot notation.
Unqualified Import
What happens if we import OneModule using the import * syntax?
from OneModul import *
print a
’One Module’
The global variable a is assigned by the OneModule script. Calling foo() will show that foo() is redefined or destroyed?
foo(100)
’What happens next?’
Unqualified import can be dangerous - it will redefine functions and possibly overwrite variables when names are identical.
Hint: Use qualified import to avoid accidents
Classes have their own namespaces
A way to protect your functions and variables is to use a class to create a protected name space. Another benefit is that one can create multiple instances of the class - which is a powerful feature making life easier and more fun for a lazy programmer (lazy programmers = efficient programmers).
We create another module AnotherModule.py. Then define a class named ASimpleClass and store it in C:\PythonPrimer
class ASimpleClass:
def __init__(self):
self.a=’A Simple Class’
def foo(self,b):
print ‘a=’,self.a,‘b=’,b
Statements and output:
from AnotherModule import *
m=ASimpleClass()
print m. a
’A Simple Class’
m.foo(’spam’’)
a=’A Simple Class’ b=’spam’
m.a=a
print m.a
a=100
You can protect variables using a class definition this way:
class Glob:
a=100
glob=Glob()
print glob.a
100
glob.b=200
print glob.b
200
As you can see you can add new variables to the class - on the fly! - and get the protection and scoping you need.
Python and Scorpion¶
Python is integrated in Scorpion. You may write Python code in
Tools
Central
Central.Start
Central.Stop
Central.Scripts
Scorpion Central¶
Central.Start is the starting point for all Python execution within Scorpion.
Central.Start is run by Scorpion during startup which means that this is THE place to put global declarations of classes, functions and variables. Anything declared within Central.Start is available to PythonTools and Central.Scripts.
Good programming practice in Scorpion:
- Declare all variables, functions and classes that are ment to be global in Central.Start
- Use the global directive in all scripts referring to global variables, even though if the variables are only ReadOnly. Tell yourself and any other user of your profile that you know exactly what you are doing.
- Any variable declared in a PythonTool should be regarded as local to this script. They will become global after the first assignment - but this is bad practice.
- Do not import your own modules with the from module import * statement if the module contains global assignments. The consequence is that previous declared global vaiables with equal names will be overwritten. Use the import statement instead.
- Try rewriting modules containing variables and functions into classes.
Scorpion Tool scripts¶
TBD
Working with files¶
All paths in Python scripts should be relative to either profile folder, storage folder or executable folder unless absolute path given, else the resulting folder may depend of current working folder.
import os
path = os.path.join(GetString('System.Profile'), <filename>) # profile local file
path = os.path.join(GetString('System.Profile'), 'Python') # local profile python folder
path = os.path.join(GetString('System.ScorpionDir'), 'Python') # Scorpion's Runtime\Pyjhon folder
path = os.path.join(GetString('System.Storage'), 'Data') # local profile storage Data folder
path = os.path.expanduser(r'~\Documents\<path>) #returns Documents folder for current user
Another ‘hot’ tip for safer file read/write operations, using the with statements, secures the opened file always to be closed when execution leaves scope, no need to call close().
with open(os.path.join(GetString('System.Profile'), 'error.log', 'w') as f:
f.write(message)
This is safer than below code in case of exceptions as the close() may never be called…
f = open(os.path.join(GetString('System.Profile'), 'error.log', 'w')
f.write(message)
close(f)