import importlib
import numpy as np
# Use a temporary directory, if it already exists then clean it first
%rm -rf temporary_work_directory
%mkdir temporary_work_directory
%cd temporary_work_directory
%pwd
This lecture treats how to
Reading material
#
in the code is a comment# This is a comment
print('This will be executed.') # This won't be executed
# This will not
be a good comment
for anyone in your team
# This will be a
# much better comment
# for everyone in your team!
Examlpe:
return b # Returns b
This is a typical W.E.T. comment, meaning
How can we make the comments in this code more DRY?
weights = np.array([85, 74, 56]) # weight in kg
heights = np.array([1.89, 1.77, 1.63]) # height in m
# create BMI array: BMI = mass / length^2
bmi = weights / heights**2
print(bmi)
Here is a DRYer version
weights = np.array([85, 74, 56]) # unit: kg
heights = np.array([1.89, 1.77, 1.63]) # unit: m
bmi = weights / heights**2 # Body Mass Index, unit: kg/m^2
print(bmi)
Good naming, requires less comments
What does this code do?
How does it do it?
How could it be made more
def chk_pr(i): # Check if i is a prime number
pf = True # Initial assumption True
for d in range(2, i): # Check for all i from 2 to d
if i % d == 0: pf = False # is i evenly divisible by d?
return pf # return pf
Suggested cleanup and renaming:
def is_prime(value):
prime_flag = True
for divisor in range(2, value): # Check all relevant smaller integers
if value % divisor == 0: # If evenly divisible, not a prime
prime_flag = False
return prime_flag
An important part of writing code is to document it,
The goal is to create
In Python code and documentation are written together
def is_prime(value):
"""Checks if the input `value` is a prime number. """ # <= This is a docstring!
prime_flag = True
for divisor in range(2, value): # Check all relevant smaller integers
if value % divisor == 0: # If evenly divisible, not a prime
prime_flag = False
return prime_flag
is_prime(3)
is_prime(9)
When we have provided a docstring to an object in Python,
help(...)
help(is_prime)
The function docscring is the place to document the function's
The syntax used in the docstring is not fixed by the Python standard.
However, there specific syntaxes for generating nice documentation
Three competing docstring formatting standards
For general info on docstrings, see:
def is_prime(value):
"""Checks if the input `value` is a prime number.
:param value: Integer whose prime number status should be checked.
:type value: int, float
:return: `True` if `value` is a prime number, else `False`.
:rtype: bool
"""
prime_flag = True
for divisor in range(2, value): # Check all relevant smaller integers
if value % divisor == 0: # If evenly divisible, not a prime
prime_flag = False
return prime_flag
help(is_prime)
typing
module¶typing
module adds partial type support to Pythontyping
module includes type objects for annotating function parameters.List
, Dict
etc.,Iterable
, andAny
andHave a look at the documentation of typing
for more info.
Lets see how the is_prime
function looks when adding type hits.
import typing
def is_prime(value: typing.Union[int, float]) -> bool:
"""Checks if the input `value` is a prime number.
:param value: Integer whose prime number status should be checked.
:return: `True` if `value` is a prime number, else `False`.
"""
prime_flag = True
for divisor in range(2, value): # Check all relevant smaller integers
if value % divisor == 0: # If evenly divisible, not a prime
prime_flag = False
return prime_flag
help(is_prime)
What happens if we use an input varaible that is not of int
or float
type?
is_prime("Hello world!")
PyCharm will let you automatically insert skeletons for documentation on functions etc.
Lets try to create and verify our simple example above using PyCharm!
To have PyCharm help you with adding type hints, mark the parameter or function name you want to add hints for and press ALT+Enter (Linux or Windows) or Option+Enter (Mac), and then choose the hint method you want to use from the menu that pops up.
print_tools
¶print_tools
print_two_objects
and task_done
,version
specifying the version number.To accomplish this we create a file named print_tools.py
with the functions and the variable.
!ls
%%writefile print_tools.py
""" Python module with useful printing functions!
Author: Emilia Emilsson (2020), emiemi@chalmers.se """
version = "0.0.0" # Module global variable
def print_two_objects(object1, object2):
"""Prints the two objects to stdout.
:param object1: The first object to print
:type object1: Any type convertible to str
:param object2: The second object to print
:type object2: Any type convertible to str
"""
print(f'The two objects are: "{object1}" and "{object2}".')
def taks_done():
"""Indicate that a task is done by printing a message."""
print('Task done.')
!ls
print_tools
¶We can now import and use our print_tools
module like any other module
import print_tools
print_tools.print_two_objects(12, "Blue")
We can also look at the documentation of our module using the help()
function
help(print_tools)
dir()
¶Python will automatically create a few variables when importing a module
__name__
contains the active module name, in our example above when we imported our module this is print_tools
__doc__
contains the module documentation,To inspect the contents of a module use dir()
dir(print_tools)
print(print_tools.__name__)
print(print_tools.version)
__name__
variable¶__name__ == "print_tools"
print_tools.py
using the Python command-line__name__ == "__main__"
__name__
is often used to detect if module is executed "stand alone"print_tools_v1
¶task_done
function in print_tools
__name__
variableprint_tools.py
is executed "stand alone"%%writefile print_tools_v1.py
""" Python module with useful printing functions!
Author: Emilia Emilsson (2020), emiemi@chalmers.se """
version = "1.0.0" # Module global variable
def print_two_objects(object1, object2):
"""Prints the two objects to stdout.
:param object1: The first object to print
:type object1: Any type convertible to str
:param object2: The second object to print
:type object2: Any type convertible to str
"""
print(f'The two objects are: "{object1}" and "{object2}".')
def task_done():
"""Indicate that a task is done by printing a message."""
print(f'Task done in the "{__name__}" module.')
if __name__ == "__main__":
print_two_objects("This is a test", "of print_two_objects")
task_done()
Running this in the lecture Jupyter notebook gives:
import print_tools_v1
print_tools_v1.task_done()
If we instead run our file directly in the Python interpreter from the command-line
(using !
in a cell runs the command on the command line)
!python print_tools_v1.py
if __name__ == '__main__': ...
?¶Using the syntax
def function1():
...
def function2():
...
if __name__ == '__main__':
# Use the functions to do something uselful.
when writing Python scripts, makes it possible to import the functions in other scripts.
When going beyond more than a few functions like above
Consider organizing your modules in a package using directoreis
A directory is also a module if it contains a __init__.py
file
The __init__.py
file is read when loading the (directory) module, and can be empty
emipy
¶Steps
emipy
__init__.py
in ./emipy/
emipy
modulehelp(emipy)
!mkdir emipy
!touch emipy/__init__.py
!tree
import emipy
help(emipy)
__init__.py
¶Lets add some contents to the __init__.py
module file
__name__
(Side note: After modifying files we have to explicitly reload the module here. This is not needed when deveolping in PyCharm.)
%%writefile emipy/__init__.py
"""EmiPy the friendly Python package.
EmiPy is a Python package with useful helper functions.
Author: Emilia Emilsson (2020), emiemi@chalmers.se """
print(f'Loading {__name__}.')
version = "2.0.0"
importlib.reload(emipy); # only needed in interactive mode after modifying module files
help(emipy)
emipy.printing
¶Lets make a sub-module called printing
in our emipy
module
emipy/printing.py
print_two_objects
function from before to printing.py
%%writefile emipy/printing.py
""" Python module with useful printing functions!
Author: Emilia Emilsson (2020), emiemi@chalmers.se """
def print_two_objects(object1, object2):
"""Prints the two objects to stdout.
:param object1: The first object to print
:type object1: Any type convertible to str
:param object2: The second object to print
:type object2: Any type convertible to str
"""
print(f'The two objects are: "{object1}" and "{object2}".')
!tree ./emipy
importlib.reload(emipy);
help(emipy)
dir(emipy)
Note: Our printing
submodule is missing in dir(emipy)
?!
What do we need to do to use the printing
sub-module to emipy
?
from emipy import printing
help(printing)
__init__.py
¶emipy
submodule printing
available as emipy.printing
directly when importing emipy
,emipy
module's __init__.py
file.__init__.py
imports¶dir(emipy)
%%writefile emipy/__init__.py
"""EmiPy the friendly Python package.
EmiPy is a Python package with useful helper functions.
Author: Emilia Emilsson (2020), emiemi@chalmers.se """
print(f'Loading {__name__}.')
version = "2.0.0"
from . import printing
importlib.reload(emipy);
dir(emipy)
emipy.printing.print_two_objects(
'Calling the function "print_two_objects"',
'from the module "emipy" and the sub-module "printing"')
When having many functions in a module
printing
module with more functionality./emipy/printing_extension.py
%%writefile emipy/printing_extension.py
""" Python module with extended set of useful printing functions!
To do:
- Write documentation for the new functions
- Hand in Computer Assignment 1, this weekend!!
Author: Emilia Emilsson (2020), emiemi@chalmers.se """
def print_one_object(obj):
print(obj)
def print_two_objects(obj1, obj2):
print(obj1, obj2)
def print_many_objects(*objects):
print(*objects, sep=' ')
!tree ./emipy
We want the function print_one_object
in printing_extension.py
to be available as emipy.printing.print_one_object
This is possible by importing these functions in printing.py
!
%%writefile emipy/printing.py
""" Python module with useful printing functions!
Author: Emilia Emilsson (2020), emiemi@chalmers.se """
from .printing_extension import print_one_object, print_two_objects, print_many_objects
def print_two_objects(object1, object2):
"""Prints the two objects to stdout.
:param object1: The first object to print
:type object1: Any type convertible to str
:param object2: The second object to print
:type object2: Any type convertible to str
"""
print(f'The two objects are: "{object1}" and "{object2}".')
importlib.reload(emipy.printing); importlib.reload(emipy.printing_extension);
emipy.printing.print_many_objects('Ada', 'Lovelace', 'was', 'the', 'world\'s', 'first', 'programmer!')
The concepts
are central to (good) programming.
As written in "The Zen of Python"
Namespaces are one honking great idea—let’s do more of those!
dir
inspects the names in a namespacePython comes with many namespaces
print
, dir
, etc.import numpy as np
the np
object refers to NumPy's namespaceWhen using a variable a
in Python,
the interperter looks at the current scope and its list of namespaces
a
is not found, the next namespace in the scope list is searchedWhen creating a variable b
in Python
a = 1 # in global namespace
b = 2
def print_a_and_b():
# each function has its own inner namespace
print(a) # no name "a" in the current namespace, look through all namespaces in the scope
b = 3 # New variable "b" in the local namespace
print(b) # "b" is defined in the current namespace and it is found first and used
print_a_and_b()
print(b) # The name "b" in the global namespace is however unchanged
a = 1
def print_a():
a = 10
print(a)
print_a()
print(a)
global
and nonlocal
¶You can override the scope of a variable using the global
and nonlocal
keywords.
global a
will let you modify a
directly in the global namespacenonlocal a
does the same, but only for a
in the next outer namespace of the current scopeNote: If you end up using this, you are probably better off redesigning your code.
global
and nonlocal
¶def myfunc():
def func_local():
a = "local"
def func_nonlocal():
nonlocal a
a = "nonlocal"
def func_global():
global a
a = "global"
a = "func"
func_local()
print("After func_local:", a)
func_nonlocal()
print("After func_nonlocal:", a)
func_global()
print("After func global:", a)
a = "main"
print("In global (main) scope, before call:", a)
myfunc()
print("In global (main) scope, after call:", a)
import
actually does¶Now we can express what the different forms of import
statements does!
import emipy
emipy
emipy
to the active namespaceemipy
contains the module namespaceimport emipy as ep
emipy
ep
to the active namespaceemipy
module namespacefrom emipy import printing
printing
from the emipy
module namespacefrom emipy.printing import print_two_objects
print_two_objects
from the emipy.printing
submodule namespacefrom emipy.printing import *
emipy.printing
submodule namespaceCommand line arguments can be obtained from the standard module sys
and the sys.argv
varaible.
%%writefile test_sys_argv.py
import sys
print('type(sys.argv) =', type(sys.argv))
print('Got command line arguments:\n', sys.argv)
!python test_sys_argv.py "First command line argument" "Second command line argument"
argparse
instead of parsing sys.argv
¶For parsing of command line parameters, use the argparse
module.
import argparse
help(argparse)
import this
import __hello__