Python in easy steps (2014)
5
Importing modules
This chapter demonstrates how to use Python modules in your programs.
Storing functions
Owning function names
Interrogating the system
Performing mathematics
Calculating decimals
Telling the time
Running a timer
Matching patterns
Summary
Storing functions
Python function definitions can, usefully, be stored in one or more separate files for easier maintenance and to allow them to be used in several programs without copying the definitions into each one. Each file storing function definitions is called a “module” and the module name is the file name without the “.py” extension.
Functions stored in the module are made available to a program using the Python import keyword followed by the module name. Although not essential, it is customary to put any import statements at the beginning of the program.
Imported functions can be called using their name dot-suffixed after the module name. For example, a “steps” function from an imported module named “ineasy” can be called with ineasy.steps().
Where functions stored in a module include arguments, it is often useful to assign a default value to the argument in the definition. This makes the function more versatile as it becomes optional for the call to specify an argument value.
Start a new Python module by defining a function that supplies a default string value to its argument for display
def purr( pet = ‘A Cat’ ) :
print( pet , ‘Says MEOW!’ )
cat.py
Next, add two more function definitions that also supply default string values to their arguments for display
def lick( pet = ‘A Cat’ ) :
print( pet , ‘Drinks Milk’ )
def nap( pet = ‘A Cat’ ) :
print( pet , ‘Sleeps By The Fire’ )
Now, save the file as “cat.py” so the module is named “cat”
Start a new Python script with a statement to make the “cat” module functions available
import cat
kitty.py
Next, call each function without supplying an argument
cat.purr()
cat.lick()
cat.nap()
Now, call each function again and pass an argument to each, then save the file
cat.purr( ‘Kitty’ )
cat.lick( ‘Kitty’ )
cat.nap( ‘Kitty’ )
Start another Python script by making the “cat” module functions available once more
import cat
tiger.py
Then, request the user enters a name to overwrite the default argument value
pet = input( ‘Enter A Pet Name: ‘ )
Finally, call each function, passing the user-defined value as the argument
cat.purr( pet )
cat.lick( pet )
cat.nap( pet )
Save the file in your scripts directory then open a Command Prompt window there and run these programs - to see output from the imported module
You can create an alias when importing a module using import as keywords. For example import cat as tom allows you to use tom as the function prefix in calls.
Owning function names
Internally, each Python module and program has its own “symbol table” which is used by all functions defined in that context only. This avoids possible conflicts with functions of the same name in another module if both modules were imported into one program.
When you import a module with an import statement, that module’s symbol table does not get added to the program’s symbol table - only the module’s name gets added. That is why you need to call the module’s functions using their module name prefix. Importing a “steps” function from a module named “ineasy” and another “steps” function from a module named “dance” means they can be called without conflict as ineasy.steps() and dance.steps().
Where you import individual function names, the module name does not get imported - so it cannot be used as a prefix.
Generally, it is preferable to avoid conflicts by importing the module name and calling its functions with the module name prefix but you can import individual function names instead with a from import statement. The module name is specified after the from keyword, and functions to import are specified as a comma-separated list after the import keyword. Alternatively, the * wildcard character can be specified after import to import all function names into the program’s own symbol table. This means the functions can be called without a module name prefix.
Start a new Python module by defining a function that supplies a default string value to its argument
def bark( pet = ‘A Dog’ ) :
print( pet , ‘Says WOOF!’ )
dog.py
Next, add two more function definitions that also supply default string values to their arguments
def lick( pet = ‘A Dog’ ) :
print( pet , ‘Drinks water’ )
def nap( pet = ‘A Dog’ ) :
print( pet , ‘ Sleeps In The Sun’ )
Save the file as “dog.py” so the module is named “dog”.
Start a new Python script with a statement to make individual “dog” module functions available
from dog import bark , lick , nap
pooch.py
Next, call each function without supplying an argument
bark()
lick()
nap()
Now, call each function again and pass an argument value to each then save the file
bark( ‘Pooch’ )
lick( ‘Pooch’ )
nap( ‘Pooch’ )
Start another Python script by making all “dog” module functions available
from dog import *
fido.py
Then, request the user enters a name to overwrite the default argument value
pet = input( ‘Enter A Pet Name: ‘ )
Finally, call each function, passing the user-defined value as the argument
bark( pet )
lick( pet )
nap( pet )
Save the file in your scripts directory then open a Command Prompt window there and run these programs - to see output from the imported functions
For larger programs you can import modules into other modules to build a module hierarchy.
Interrogating the system
Python includes “sys” and “keyword” modules that are useful for interrogating the Python system itself. The keyword module contains a list of all Python keywords in its kwlist attribute and provides an iskeyword() method if you want to test a word.
You can explore the many features of the “sys” module and indeed any feature of Python using the Interactive Mode help system. Just type help() at the >>> prompt to start the help system then type sys at the help> prompt that appears.
Perhaps most usefully, the “sys” module has attributes that contain the Python version number, interpreter location on your system, and a list of all directories where the interpreter seeks module files - so if you save module files in any of these directories you can be sure the interpreter will find them.
Start a new Python script by importing the “sys” and “keyword” modules to make their features available
import sys , keyword
system.py
Next, add a statement to display the Python version
print( ‘Python Version:‘ , sys.version )
Now, add a statement to display the actual location on your system of the Python interpreter
print( ‘Python Interpreter Location:’ , sys.executable )
Then, add statements to display a list of all directories where the Python interpreter looks for module files
print( ‘Python Module Search Path: ‘ )
for dir in sys.path :
print( dir )
Finally, add statements to display a list of all the Python keywords
print( ‘Python Keywords: ‘ )
for word in keyword.kwlist :
print( word )
Save the file in your scripts directory then open a Command Prompt window there and run this program - to see details of the Python version on your system
The first item on the Python search path is your current directory - so any file within there or within any subdirectories you make there will be found by the Python interpreter.
Spend a little time with the Interactive Mode help utility to discover lots more about Python.
Performing mathematics
Python includes a “math” module that provides lots of methods you can use to perform mathematical procedures once imported.
The math.ceil() and math.floor() methods enable a program to perform rounding of a floating point value specified between their parentheses to the closest integer - math.ceil() rounds up and math.floor() rounds down but the value returned, although an integer, is a float data type rather than an int data type.
Integers can be cast from the int data type to the float data type using the float() function and to the string data type using the str() function.
The math.pow() method requires two arguments to raise a specified value by a specified power. The math.sqrt() method, on the other hand, simply requires a single argument and returns the square root of that specified value. Both method results are returned as a numeric value of the float data type.
Typical trigonometry can be performed using methods from the math module too, such as math.sin(), math.cosin() and math.tan().
Additionally, Python includes a “random” module that can be used to produce pseudo random numbers once imported into a program.
The random.random() method produces a single floating-point number between zero and 1.0. Perhaps more interestingly, the random.sample() method produces a list of elements selected at random from a sequence. This method requires two arguments to specify the sequence to select from, and the length of the list to be produced. As the range() function returns a sequence of numbers this can be used to specify a sequence as the first argument to the random.sample() method - so it will randomly select numbers from that sequence to produce a list in which no numbers repeat.
Start a new Python script by importing the “math” and “random” modules to make their features available
import math , random
maths.py
Next, add statements to display two rounded values
print( ‘Rounded Up 9.5:‘ , math.ceil( 9.5 ) )
print( ‘Rounded Down 9.5:‘ , math.floor( 9.5 ) )
Now, add a statement to initialize a variable with an integer value
num = 4
Add statements to display the square and square root of the variable value
print( num , ‘Squared:‘ , math.pow( num , 2 ) )
print( num , ‘Square Root:‘ , math.sqrt( num ) )
Then, add a statement to produce a random list of six unique numbers between one and 49
nums = random.sample( range( 1, 49 ) , 6 )
Finally, add a statement to display the random list
print( ‘Your Lucky Lotto Numbers Are:‘ , nums )
Save the file in your scripts directory then open a Command prompt window there and run this program - to see math results and random samples
All the math methods here return floating-point numbers of the float data type.
The list produced by random.sample() does not actually replace elements of the sequence but merely copies a sample, as its name says.
Calculating decimals
Python programs that attempt floating-point arithmetic can produce unexpected and inaccurate results because the floating-point numbers cannot accurately represent all decimal numbers.
Start a new Python script by initializing two variables with floating-point values
item = 0.70
rate = 1.05
inaccurate.py
Next, initialize two more variables by attempting floating-point arithmetic with the first two variables
tax = item * rate
total = item + tax
Now, add statements to display variable values formatted to have two decimal places so trailing zeros are shown
print( ‘Item:\t’ , ‘%.2f’ % item )
print( ‘Tax:\t’ , ‘%.2f’ % tax )
print( ‘Total:\t’ , ‘%.2f’ % total )
Save the file in your scripts directory then open a Command Prompt window there and run the program - to see the output display an inaccurate addition
Here, the variable values are formatted using a string substitution technique to show two decimal places - described in more detail here.
To help understand this problem, edit all three print statements to display the variable values expanded to twenty decimal places, then run the modified program
print( ‘Item:\t’ , ‘%.20f’ % item )
print( ‘Tax:\t’ , ‘%.20f’ % tax )
print( ‘Total:\t’ , ‘%.20f’ % total )
expanded.py
This problem is not unique to Python - Java has a BigDecimal class that overcomes this problem in much the same way as the decimal module in Python.
It is now clear that the tax value is represented numerically slightly below 0.735 so gets rounded down to 0.73. Conversely, the total value is represented numerically slightly above 1.435 so gets rounded up to 1.44, creating the apparent addition error.
Errors in floating-point arithmetic can be avoided using Python’s “decimal” module. This provides a Decimal() object with which floating-point numbers can be more accurately represented.
Add a statement at the beginning of the program to import the “decimal” module to make all features available
from decimal import *
decimals.py
Next, edit the first two variable assignment to objects
item = Decimal( 0.70 )
rate = Decimal( 1.05 )
Save the changes then run the modified program to see both tax and total representations will now get rounded down - so the output will show accurate addition when string formatting is changed back to two decimal places
Always use the Decimal() object to calculate monetary values or anywhere that accuracy is essential.
Telling the time
The Python “datetime” module can be imported into a program to make use of times and dates. It provides a datetime object with attributes of year, month, day, hour, minute, second, microsecond.
A datetime object has a today() method that assigns the current date and time values to its attributes and returns them in a tuple. It also has a getattr() method that requires two arguments specifying the datetime object name and attribute to retrieve. Alternatively, the attributes can be referenced using dot notation such as datetime.year.
As the datetime object is in a module of the same name, simply importing the module means it would be referenced as datetime.datetime. Use from datetime import * so it can be referenced just as datetime.
All values in a datetime object are stored as numeric values but can, usefully, be transformed into text equivalents using its strftime() method. This requires a single string argument that is a “directive” specifying which part of the tuple to return and in what format. The possible directives are listed in the table below:
Directive: |
Returns: |
%A |
Full weekday name (%a for abbreviated day name) |
%B |
Full month name (%b for abbreviated month name) |
%c |
Date and time appropriate for locale |
%d |
Day of the month number 1-31 |
%f |
Microsecond number 0-999999 |
%H |
Hour number 0-23 (24-hour clock) |
%I |
Hour number 1-12 (12-hour clock) |
%j |
Day of the year number 0-366 |
%m |
Month number 1-12 |
%M |
Minute number 0-59 |
%p |
AM or PM equivalent for locale |
%S |
Second number 0-59 |
%w |
Week day number 0(Sunday)-6 |
%W |
Week of the year number 0-53 |
%X |
Time appropriate for locale (%x for appropriate date) |
%Y |
Year 0001-9999 (%y for year 00-99) |
%z |
Timezone offset from UTC as +HHMM or -HHMM |
%Z |
Timezone name |
As the strftime() method requires a string argument, the directive must be enclosed between quote marks.
Start a new Python script by importing the “datetime” module to make its features available
from datetime import *
today.py
Next, create a datetime object with attributes assigned to current date and time values then display its contents
today = datetime.today()
print( ‘Today Is:‘ , today )
Add a loop to display each attribute value individually
for attr in \
[ ‘year’,‘month’,‘day’,‘hour’,‘minute’,’second’,’microsecond’ ] :
print( attr , ‘:\t’ , getattr( today , attr ) )
Now, add a statement to display time using dot notation
print( ‘ Time:‘ , today.hour , ‘:’ , today.minute , sep = ‘‘ )
Then, assign formatted day and month names to variables
day = today.strftime( ‘%A’ )
month = today.strftime( ‘%B’ )
Finally, add a statement to display the formatted date
print( ‘Date:‘ , day , month , today.day )
Save the file in your scripts directory then open a Command Prompt window there and run this program - to see the date and time values get displayed
Notice how the \ backslash character is used in this loop to allow a statement to continue on the next line without causing an error.
You can assign new values to attributes of a datetime object using its replace() method, such as today = today.replace(year=2015)
Running a timer
Getting the current time both before and after an event means that the duration of the event can be calculated by their difference. The Python “time” module can be imported into a program to provide various time-related functions.
Current system time is usually counted as the number of seconds elapsed since the Epoch at 00:00:00 GMT on January 1, 1970. The time module’s time() method returns the current time in seconds since the Epoch as a floating point number when called.
The gmtime() method converts elapsed time from the Epoch to a struct_time object at UTC with the Daylight Saving Time always set to zero, whereas localtime() converts to a struct_time object at your local system time.
The figure returned by the time() method can be converted into a “struct_time” object using gmtime() or localtime() methods. This object has attributes of tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_yday and tm_isdst that can be referenced using dot notation. For example,struct.tm_wday.
All values in a struct_time object are stored as numeric values but can be transformed into text equivalents using the strftime() method. This requires an argument that is a format “directive” followed by the name of the struct_time object. The possible directives include those listed in the table herefor the datetime object. For example, strftime( ‘%A’ , struct ) for weekday.
Usefully, the time module also provides a sleep() method that can be used to pause execution of a program. Its argument specifies the amount of time in seconds by which to delay execution.
Start a new Python script by importing the “time” module to make its features available
from time import *
timer.py
Next, initialize a variable with a floating point number that is the current elapsed time since the epoch
start_timer = time()
Now, add a statement to create a struct_time object from the elapsed time value
struct = localtime( start_timer )
Then, announce that a countdown timer is about to begin from the current time starting point
print( ‘\nStarting Countdown At:’ , strftime( ‘%X’ , struct ) )
Add a loop to initialize and print a counter variable value then decrement the counter by one and pause for one second on each iteration
i = 10
while i > -1 :
print( i )
i -= 1
sleep( 1 )
The argument to the sleep() method may be a floating point number to indicate a more precise sleep pause time.
Next, initialize a variable with a floating point number that is the current elapsed time now since the Epoch
end_timer = time()
Now, initialize a variable with the rounded seconds value of the time difference between the two timed points
difference = round( end_timer - start_timer )
Finally, add a statement to display the time taken to execute the countdown loop
print( ‘\nRuntime:’ , difference , ‘Seconds’ )
Save the file in your scripts directory then open a Command Prompt window there and run this program - to see the loop pause on each iteration and elapsed time
Do not confuse the time.strftime() method used in this example with the datetime.strftime() method used in the previous example.
Matching patterns
The Python “re” module can be imported into a program to make use of Regular Expression patterns that describe a particular string of characters. Regular Expressions are useful for text validation and for search-and-replace operations within text by matching their specified pattern to a section of the text.
The topic of Regular Expressions is extensive and beyond the remit of this book - but a brief introduction is provided here for completeness.
A Regular Expression pattern may consist entirely of “literal characters” describing a character string to match within some text. For example, the Regular Expression “wind” finds a match in “windows” - the pattern literally matches the string in the text. More typically, a Regular Expresssion pattern consists of a combination of literal characters and these “metacharacters”:
Metacharacter: |
Matches: |
Example: |
. |
Any Characters |
py..on |
^ |
First Characters |
^py |
$ |
Final Characters |
....on$ |
* |
Zero Or More Repetitions |
py* |
+ |
One Or More Repetitions |
py+ |
? |
Zero Or One Repetitions |
py? |
{ } |
Multiple Repetitions |
a{ 3 } |
[ ] |
Character Class |
[ a-z ] |
\ |
Special Sequence |
\s |
| |
Either Optional Character |
a | b |
( ) |
Expression Group |
( ... ) |
The character class [a-z] matches only lowercase characters but [a-z0-9] also matches digits.
A combination of literals and metacharacters defining a pattern to be matched can be specified to the re.compile() method to return a pattern object. This object has a match() method to specify a string within its parentheses to compare against the pattern.
When a match() comparison succeeds, a match object is returned containing information about the match, otherwise a None value is returned when the comparison fails.
A match object has start() and end() methods, which return the position of the match, and a group() method that returns the string matched by the comparison.
Start a new Python script by importing the “re” module to make the regular expression methods available
from re import *
regex.py
Next, initialize a variable with a regular expression object
pattern = \ compile( ‘(^|\s)[-a-z0-9_.]+@([-a-z0-9]+\.)+[a-z]{2,6}(\s|$)’ )
Now, begin a function definition by requesting user input and attempt to match that with the pattern
def get_address() :
address = input( ‘Enter Your Email Address: ‘ )
is_valid = pattern.match( address )
Then, add indented statements to display an appropriate message describing whether the attempt succeeded
if is_valid :
print( ‘Valid Address:’ , is_valid.group() )
else :
print( ‘Invalid Address! Please Retry...\n’ )
Finally, add a statement to call the defined function
get_address()
Save the file in your scripts directory then open a Command Prompt window there and run this program - to see that only a complete email address will validate
You can discover more about Regular Expressions in the Library Reference section of the Python documentation at docs.python.org/3/library/re.html
Summary
•Functions can be stored in modules that are named as the file name without the “.py” file extension
•An import statement makes module functions available in a program by dot-suffixing their name after the module name
•A from import statement makes module functions available in a program without the need to dot-suffix their name
•The sys module has attributes that contain the Python version number, interpreter location, and path to search for modules
•The keyword module has a kwlist attribute that contains a list of all current Python keywords
•The math module provides methods to perform mathematical procedures such as math.ceil() and math.floor()
•The random module provides a random() method that produces pseudo random numbers and a sample() method that produces a list of elements selected at random from a sequence
•The decimal module provides a Decimal() object with which floating-point numbers can be accurately represented to calculate monetary values
•The datetime module provides a datetime object with year, month, day, hour, minute, second, microsecond attributes that can be referenced by dot-suffixing or with the getattr() method
•A datetime object has a strftime() method that can specify a directive to return a formatted part of the object
•The time module provides a time() method that returns the current elapsed time in seconds since the Epoch
•The gmtime() and localtime() methods return a struct_time object that has attributes containing date and time components
•The re module provides a compile() method to create a Regular Expression pattern and a match() method to compare a pattern to a specified string