07. Modules, Packages, Exception, and Assertion#
For the sample code of this chapter, please refer to here.
Last time#
Recursion
Global variable
Dictionaries
Functions with multiple input arguments
Today#
Modules#
As your program gets larger, you might want to divide them into several files that allows you to manage or maintain them conveniently.
To use the variables, functions, etc. in those files, you need to use a special function called
import
.
Example: nycudopcs2023.py#
A self-defined module
def youfool(): print("HoHoCheng:") print(" You fool!!!") def gossip(idx=0): print("Something is calling me.") if idx == 0: print("大二的某人:") print(" 作業量太少,為了使下屆能夠充分學習Python知識,建議作業改成每日一份,且加入上機考,使同學能夠養成規律複習的習慣") elif idx == 1: print("大二的某人:") print(" 我覺得作業量有點少,每份homework不用多久就寫完了,希望下一屆可以出20份HW,每週練習2份作業才有充分且實在的體驗到程式的練習,讓coding能力更上一層樓。") else: print("大二的某人:") print(" 我覺得下次請給學弟妹更多的作業") student_id = ["112514001", "112514002", "112514003",] print("This is nycudopcs.py. __name__:", __name__)
# import module "nycudopcs2023"
from scripts import nycudopcs2023
# call function in "nycudopcs2023"
nycudopcs2023.youfool()
# call variables in "nycudopcs2023"
print(nycudopcs2023.student_id)
# call another function in "nycudopcs2023"
for i in range(3):
nycudopcs2023.gossip(idx=i)
This is nycudopcs.py. __name__: scripts.nycudopcs2023
HoHoCheng:
You fool!!!
['112514001', '112514002', '112514003']
Something is calling me.
大二的某人:
作業量太少,為了使下屆能夠充分學習Python知識,建議作業改成每日一份,且加入上機考,使同學能夠養成規律複習的習慣
Something is calling me.
大二的某人:
我覺得作業量有點少,每份homework不用多久就寫完了,希望下一屆可以出20份HW,每週練習2份作業才有充分且實在的體驗到程式的練習,讓coding能力更上一層樓。
Something is calling me.
大二的某人:
我覺得下次請給學弟妹更多的作業
Rename your module#
For simplicity and convenience, you can rename the module.
# import module "nycudopcs2023" as "dopcs"
from scripts import nycudopcs2023 as dopcs
# call functions in "dopcs"
dopcs.youfool()
# call variables in "dopcs"
print(dopcs.student_id)
HoHoCheng:
You fool!!!
['112514001', '112514002', '112514003']
Import specific objects from module#
You can only import some specific objects from module.
# from module "nycudopcs2023" import "youfool" as "yf"
from scripts.nycudopcs2023 import youfool as yf
# call function "yf"
if __name__ == "__main__":
yf()
HoHoCheng:
You fool!!!
Packages#
Again, as your program gets larger, you might want to divide them into several files that allows you to manage or maintain them conveniently.
This time, we have multiple modules in the same directory. Additional techniques are required for efficient management.
scripts
├─ example1 # "example1" package
| ├─ __init__.py # Initialization of "example1" package
| ├─ module1.py # Module1 in the "example1" package
| └─ module2.py # Module2 in the "example1" package
|
├─ example2
| ├─ ...
|
├─ main_example1.py # Main script 1
├─ main_example2.py # Main script 2
└─ nycudopcs2023.py
The
__init__.py
file is required to make Python treat directory containing the file as package.
Example: Example1
package#
Run this in terminal
python main_example1.py
from scripts.example1.module1 import hello
hello()
哩後!
from scripts.example1 import module1
module1.hello()
print(dir(module1))
print(module1.__name__)
print(module1.__package__)
哩後!
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'hello']
scripts.example1.module1
scripts.example1
Another way to use modules in packages (not recommended)#
from scripts import example1
example1.module1.hello()
哩後!
Subpackages#
Sometime, package consists of several subpackages.
scripts
├─ example1 # "example1" package
| ├─ __init__.py # Initialization of "example1" package
| ├─ module1.py # Module1 in the "example1" package
| └─ module2.py # Module2 in the "example1" package
|
├─ example2 # "example2" package
| ├─ sub1 # "sub1" sub-package
| | ├─ __init__.py # Initialization of "sub1" sub-package
| | └─ moduleX.py # ModuleX in the "sub1" sub-package
| |
| ├─ sub2 # "sub2" sub-package
| | ├─ __init__.py # Initialization of "sub2" sub-package
| | └─ moduleY.py # ModuleX in the "sub2" sub-package
| |
| ├─ __init__.py # Initialization of "example2" package
| ├─ main_sub1.py # Main script for sub1
| └─ main_sub2.py # Main script for sub2
|
├─ example3 # "example3" package
| ├─ sub1 # "sub1" sub-package
| | ├─ __init__.py # Initialization of "sub1" sub-package
| | ├─ moduleX.py # ModuleX in the "sub1" sub-package
| | ├─ moduleY.py # ModuleY in the "sub1" sub-package
| | └─ moduleZ.py # ModuleZ in the "sub1" sub-package
| |
| ├─ sub2 # "sub2" sub-package
| | ├─ __init__.py # Initialization of "sub2" sub-package
| | ├─ moduleA.py # ModuleA in the "sub2" sub-package
| | └─ moduleB.py # ModuleB in the "sub2" sub-package
| |
| └─ __init__.py # Initialization of "example3" package
|
├─ main_example1.py # Main script 1
├─ main_example2.py # Main script 2
├─ main_example3.py # Main script 3
└─ nycudopcs2023.py
Example: Example2
package#
Run this in terminal
python main_example2.py
Example: Example3
package#
Run this in terminal
python main_example3.py
Get organization#
So far we have learned…
Use conditionals to control the flow of program
Use loops to complete the routine task
Create functions to hide the details and simplify the program
Use modules to store different portions of your program
Use packages to organize your program
All these concepts and tools will help you deal with those computational problems, understand the programs written by other programmers, and most importantly, get yourself organized.
Exception#
When we run something like this…
testList = [1, 2, 3]
print(testList[0])
print(testList[3])
print("The End.")
1
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[7], line 3
1 testList = [1, 2, 3]
2 print(testList[0])
----> 3 print(testList[3])
4 print("The End.")
IndexError: list index out of range
Syntax try
/except
#
In python, you can use try/except block to avoid the program terminating itself as it encounters an error.
testList = [1, 2, 3]
try:
print(testList[0])
print(testList[3])
except IndexError:
print("Index out of range!")
print("The End.")
1
Index out of range!
The End.
Common exceptions#
AttributeError
IndexError
IOError
NameError
SyntaxError
TypeError
ValueError
ZeroDivisionError
…
Trivia#
Signal-to-noise ratio (SNR) is a very important criterion to quantify the performance of a system. In practical, noise always exists in every system, and the noise level might be infinitesimal in some cases.
import math
def snr(sigLevel, nLevel):
try:
output = 10 * math.log10(sigLevel/nLevel)
print("SNR = {:.2f} dB".format(output))
except ZeroDivisionError:
print("SNR = infinite")
except:
print("Something is going wrong.")
snr(100, 10)
snr(100, 0)
Exceptions as a control flow mechanism#
Using exceptions for controlling flow
def getRatios(L1, L2):
"""
Assumes L1 and L2 are equal length lists of numbers
Returns a list containing the ratio of L1[i]/L2[i]
"""
ratio = []
for idx in range(len(L1)):
try:
ratio.append(L1[idx]/L2[idx])
except ZeroDivisionError:
ratio.append(float("NaN"))
except:
raise ValueError("Something is going wrong!")
return ratio
print(getRatios([9,5,2,7], [9,4,8,7]))
print(getRatios([9,5,2,7], [0,4,8,7]))
print(getRatios([9,5,2,7], [4,8,7]))
try:
print(getRatios([9,5,2,7], [9,4,8,7]))
print(getRatios([9,5,2,7], [0,4,8,7]))
print(getRatios([9,5,2,7], [4,8,7]))
except ValueError as msg:
print(msg)
Exercise 7.1#
Implement a function that meets the specification below. Use a
try
/except
block.
def sumDigits(s):
"""
Assume s is a string
Return the sum of the decimal digits in s
For example, if s is "n994v5", it returns 27
"""
# 自己想
return output
Test your function with different inputs
s
, for example,sumDigits("n994v5")
.
Assertion#
An useful tool for confirming the state of computation is as expected.
def findGCD(n1, n2):
"""
Assumes n1 and n2 are two positive integers
Returns the greatest common divisor of them
"""
assert type(n1) == int and type(n2) == int
L, S = max(n1, n2), min(n1, n2)
if L%S == 0:
return S
else:
return findGCD(S, L%S)
print(findGCD(36, 144))
print(findGCD(7, 144))
print(findGCD(3.6, 144))
try:
print(findGCD(36, 144))
print(findGCD(7, 144))
print(findGCD(3.6, 144))
except AssertionError:
print("Something is going wrong!")
def findGCD(n1, n2):
"""
Assumes n1 and n2 are two positive integers
Returns the greatest common divisor of them
"""
assert type(n1) == int and type(n2) == int, "Variables n1 and n2 must be integers."
L, S = max(n1, n2), min(n1, n2)
if L%S == 0:
return S
else:
return findGCD(S, L%S)
print(findGCD(36, 144))
print(findGCD(7, 144))
print(findGCD(3.6, 144))
Exercise 7.2#
Implement a function that meets the specification below. It should pop out an AssertionError instead of TypeError as you running the code.
def findAnOdd(L):
"""
Assumes L is a list of integers
Returns the first odd number in L
Raises ValueError if L does not contain an odd number
"""
# 自己想
return output
Test your function with different inputs
L
, for example,findAnOdd([4, "v"])
.
Argument parser#
You may have a question about this:
How?
Use
argparse
module
import argparse
from Pick.PickSys import pickStudent
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="NYCUDOPCS Random Pick System")
parser.add_argument("--num", default=3, type=int, help="How many student do you want to pick today? (default: 3)")
parser.add_argument("--csv_dir", default="1121-515401.csv", type=str, help="Directory of CSV file")
opt = parser.parse_args()
pickStudent(num=opt.num, path=opt.csv_dir)
Exercise 3: Taylor series of \(\sin\) and \(\cos\)#
Please write a function called
sin
that aims to return you \(sin\) by Taylor series.
def sin(x, n=100):
# 自己想
return output
Please write a function called
cos
that aims to return you \(cos\) by Taylor series.
def cos(x, n=100):
# 自己想
return output