Packages and Modules (Libraries)¶
Summary: Import external libraries and organize your code into functional chunks.
The html version of this notebook is hosted at https://hydro-informatics.github.io/hypy_pckg.html.
Import packages or modules¶
Importing a package or module in Python makes external functions and
other elements (such as objects) of modules accessible in a script. The
functions and other elements are stored within another Python file
(.py
) in some /site_packages/ folder of the interpreter
environments. Thus, in order to use a non-standard package, it needs to
be downloaded and installed first. Standard packages (e.g., os
,
math
) are always accessible and other can be added with conda
(read the installation
instructions).
Note: There is a difference between modules and packages. Modules are single or multiple files that can be imported as one import (e.g.,
import a_module
). Packages are a collection of modules in a directory with a defined package hierarchy, which enables the import of individual modules (e.g.from a_package.module import a_function
). Packages are therefore also modules, but with a hierarchy definition (i.e., a__path__
attribute and a__init__.py
file). Sounds fuzzy? Read this page down to the bottom and come back here to re-read this note.
The os
package provides some useful system-terminal like commands,
for example, to manage folder directories. So let’s import this
essential package.
import os
print(os.getcwd()) # print current working directory
print(os.path.abspath('')) # print directory of script running
C:Usersschwindtjupyternb-lectures C:Usersschwindtjupyternb-lectures
Overview of import options¶
Here is an overview of options to import packages or modules (hierarchical parts of packages):
Command |
Description |
Usage of attributes |
---|---|---|
|
Import an original module |
|
``import pac kage-name as
|
Import module and rename (alias) it in the script |
|
|
Import only a function, class or other items |
|
|
Import all items |
|
Example¶
import matplotlib.pyplot as plt # import pyplot from the matplotlib module and alias it with plt
import math as m
x = []
y = []
for e in range(1, 10):
x.append(e)
y.append(e**2)
plt.plot(x, y)
[<matplotlib.lines.Line2D at 0x15f7594b388>]
What is the best way to import a package or module?¶
There is no global answer to this questions. However, be aware that
from package-name import *
overwrites any existing variable or other
item in the script. Thus, only use *
when you are aware of all
contents of a module.
pi = 9.112 # define a float called pi
print("Pi is not %1.3f." % pi)
from math import pi # this overwrites the before defined variable pi
print("Pi is %1.3f." % pi)
Pi is not 9.112. Pi is 3.142. Tip: Define default import packages for JupyterLab’s IPython kernel (read more on the Python installation page).
What items (attributes, classes, functions) are in a module?¶
Sometimes we want to explore modules or to check variable attributes.
This is achieved with the dir()
command:
import sys
print(sys.path)
print(dir(sys.path))
a_string = "zabaglione"
print(", ".join(dir(a_string)))
['C:\Users\schwindt\jupyter\nb-lectures', 'C:\Users\schwindt\Anaconda3\python37.zip', 'C:\Users\schwindt\Anaconda3\DLLs', 'C:\Users\schwindt\Anaconda3\lib', 'C:\Users\schwindt\Anaconda3', '', 'C:\Users\schwindt\AppData\Roaming\Python\Python37\site-packages', 'C:\Users\schwindt\Anaconda3\lib\site-packages', 'C:\Users\schwindt\Anaconda3\lib\site-packages\win32', 'C:\Users\schwindt\Anaconda3\lib\site-packages\win32\lib', 'C:\Users\schwindt\Anaconda3\lib\site-packages\Pythonwin', 'C:\Users\schwindt\Anaconda3\lib\site-packages\IPython\extensions', 'C:\Users\schwindt\.ipython'] ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] __add__, __class__, __contains__, __delattr__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __getitem__, __getnewargs__, __gt__, __hash__, __init__, __init_subclass__, __iter__, __le__, __len__, __lt__, __mod__, __mul__, __ne__, __new__, __reduce__, __reduce_ex__, __repr__, __rmod__, __rmul__, __setattr__, __sizeof__, __str__, __subclasshook__, capitalize, casefold, center, count, encode, endswith, expandtabs, find, format, format_map, index, isalnum, isalpha, isascii, isdecimal, isdigit, isidentifier, islower, isnumeric, isprintable, isspace, istitle, isupper, join, ljust, lower, lstrip, maketrans, partition, replace, rfind, rindex, rjust, rpartition, rsplit, rstrip, split, splitlines, startswith, strip, swapcase, title, translate, upper, zfill
Create a module¶
In object-oriented programming and code factorization, writing own, new modules is an essential task. In order to write a new module, first create a new script. Then, open the new script and add some parameters and functions.
# icecreamdialogue.py
flavors = ["vanilla", "chocolate", "bread"]
price_scoops = {1: "two euros", 2: "three euros", 3: "your health"}
welcome_msg = "Hi, I only have " + flavors[0] + ". How many scoops do you want?"
`icecreamdialogue.py
<https://github.com/hydro-informatics/icecream/raw/master/single-scripts/icecreamdialogue.py>`__
can now either be executed as script (nothing will happen visibly) or
imported as module to access its variables (e.g.,
icecreamdialogue.flavors
).
import icecreamdialogue as icd
print(icd.welcome_msg)
scoops_wanted = 2
print("That makes {0} please".format(icd.price_scoops[scoops_wanted]))
Hi, I only have vanilla. How many scoops do you want?
That makes three euros please
Make a script stand-alone¶
As an alternative, we can append the call to items in
`icecreamdialogue.py
<https://github.com/hydro-informatics/icecream/raw/master/single-scripts/icecreamdialogue.py>`__
in the script and run it as a stand-alone script by adding the called
item in to a if (__name__ == '__main__'):
statement:
# icecreamdialogue_standalone.py
flavors = ["vanilla", "chocolate", "bread"]
price_scoops = {1: "two euros", 2: "three euros", 3: "your health"}
welcome_msg = "Hi, I only have " + flavors[0] + ". How many scoops do you want?"
if (__name__ == '__main__'):
print(welcome_msg)
scoops_wanted = 2
print("That makes {0} please".format(price_scoops[scoops_wanted]))
Hi, I only have vanilla. How many scoops do you want?
That makes three euros please
Now we can run
`icecreamdialogue_standalone.py
<https://github.com/hydro-informatics/icecream/raw/master/single-scripts/icecreamdialogue_standalone.py>`__
in the terminal (e.g., PyCharm’s Terminal tab at the bottom of the
window).
C:\temp\ python icecreamdialogue_standalone.py
**Note**: Depending on the definition of system variables used in the
*Terminal* environment, the *Python* must be called with a different
variable name then ``python`` (e.g., ``python3`` on many *Linux*
platforms).
Make standalone script with input parameter¶
To make the script more flexible, we can define scoops_wanted
as an
input variable of a function.
# icecreamdialogue_standalone_withinput.py
flavors = ["vanilla", "chocolate", "bread"]
price_scoops = {1: "two euros", 2: "three euros", 3: "your health"}
welcome_msg = "Hi, I only have " + flavors[0] + ". How many scoops do you want?"
def dialogue(scoops_wanted): #formerly in the __main__ statement
print(welcome_msg)
print("That makes {0} please".format(price_scoops[scoops_wanted]))
if (__name__ == '__main__'):
# import the terminal function emulator sys
import sys
if len(sys.argv) > 1: # make sure input is provided
# if true: call the dialogue function with the input argument
dialogue(int(sys.argv[1]))
Now we can run icecreamdialogue_standalone_withinput.py
in the
terminal.
C:\temp\ python3 icecreamdialogue_standalone.py 2
Initialization of a package (hierarchically organized module)¶
Good practice involves that one script does not exceed 50-100 lines of
code. In consequence, a package will most likely consist of multiple
scripts that are stored in one folder and one master script serves for
the initiation of the scripts. This master script is called
__init__.py
and Python will always invoke this script name in a
package folder. Example structure of a module called icecreamery
:
icecreamery
(folder name)__init__.py
- package initiation Python scripticecreamdialogue.py
- dialogue producing Python scripticecream_maker.py
- virtual ice cream producing Python script
In order to automatically invoke the two relevant scripts (sub-modules)
of the icecreamery
module, the __init__.py
needs to include the
following:
# __init__.py
print(f'Invoking __init__.py for {__name__}') # not absolutely needed ..
import icecreamery.icecreamdialogue, icecreamery.icecream_maker
Invoking __init__.py for __main__
Invoking __init__.py for icecreamery
# example usage of the icecreamery package
import icecreamery
print(icecreamery.icecreamdialogue.welcome_msg)
Hi, I only have vanilla. How many scoops do you want?
Do you remember the dir()
function? It is intended to list all
modules in a package, but it does not do so unless we defined an
__all__
list in the __init__.py
.
# __init__.py with __all__ list
__all__ = ['icecreamdialogue', 'icecream_maker']
The full example of the icecreamery_all
package is available in the
icecream repository.
# example usage of the icecreamery package
from icecreamery_all import *
print(icecreamdialogue.welcome_msg)
Hi, I only have vanilla. How many scoops do you want?
Package creation summary¶
A hierachically organized package contains a __init__.py
file with
an __all__
list to invoke relevant module scripts. The structure of
a module can be more complex than the above example list (e.g., with
sub-folders). When you write a package, remember to use meaningful
script and variable
names,
and to document it.
Tip: Implement a custom logger in your module with
logger = logging.getLogger(__name__)
(replace__name__
with for examplemy-module-log
).
Reload (re-import) a package or module¶
Since Python3 reloading a module requires to import the importlib
module first. Reloading makes only sense if you are actively writing a
new module. To reload any module type:
import importlib
importlib.reload(my-module)