Scripting with import, Libraries, and Files
Contents
8. Scripting with import
, Libraries, and Files#
8.1. Lesson overview#
In a previous lesson, we covered how we can use functions to bundle up reusable code blocks. These functions will work in the JupyterLab notebook or the Python file where we defined it, but what if we want to use it in another notebook or Python file? Are we forced to copy and paste these functions over to the new location if we plan on reusing them in another program?
An important “Pythonic” style convention is to avoid duplication of code whenever possible,
and with the import
built-in keyword we can import Python code from one program into another, whether that is a
separate Python file or a JupyterLab notebook. In this lesson, we will demonstrate this ability by first creating a
basic Python code file that contains a function and then import this function into a JupyterLab notebook. Then we will
import and explore other built-in libraries, including the external library NumPy
. Finally, we will cover how to
read and write to external files with Python.
8.2. The import
keyword#
The import
built-in keyword is used to import code
from a module (i.e., a file that contains Python code) into your
code. To learn how this all works, we will first create a Python file that contains a function definition (a.k.a. a
module!), and then we will import the module into a JupyterLab notebook using import
.
Definition: module
Another name for a file that contains Python code.
8.2.1. Creating the module#
Open up Spyder, the Python IDE that we covered in Getting Started. Create a new file and copy the following example code:
def resistance(i, v):
# return resistance
return i * v
Save the file as “resistor.py” to a convenient working folder.
8.2.2. Loading the module into JupyterLab using import
#
Now launch JupyterLab from Anaconda Navigator as covered in Getting Started. Use the JupyterLab file manager to navigate to the folder where you saved “resistor.py”. In this folder create a new Jupyter notebook and in the first code cell, type the following:
import resistor
The import resistor
statement will scan for any files in the current directory that are named “resistor.py” and will
import the entire file as a module object named resistor
(i.e., it names the module object based on the filename).
The resistance
function can then be called through the imported resistor
module:
import resistor
r = resistor.resistance(i = 10, v = 5)
Note how we call resistor.resistance()
to access the resistance()
function. To cut down on keystrokes, we can
alternatively import just resistance()
function from the resistor
module via the command:
from resistor import resistance
r = resistance(i = 10, v = 5)
The from
keyword can only be used with the
import
keyword to import specific code from a Python module. The from resistor import resistance
import pattern
means that the module resistor
will be inspected to find some Python code that is named resistance
, which will then
be imported. You can import any Python code from a module, like a variable, function, class, or in fact another module.
Let us create a new Python file in the same folder as the “resistor.py” file. Open up Spyder, type the following code, and save it as “ohms_law.py”:
from resistor import resistance
def voltage(i, r):
# return voltage
return i * r
def current(v, r):
# return current
return v / r
CU_CONDUIT = 58.0
Now we can import multiple things from the “ohms_law.py” file as a module:
from ohms_law import resistance, voltage, CU_CONDUIT
r = resistance(i = 10, v = 5)
v = voltage(i = 10, r = r)
print(r, v, CU_CONDUIT)
In this example, resistance()
is imported via a two-step route: it is first called via the ohms_law
module import
(“ohms_law.py”), which then imports resistance()
from “resistor.py”. We also imported another function and variable
from theohms_law
module by typing their names using the statement import resistance, voltage, CU_CONDUIT
. Notice
that we use a comma to separate the various objects we wished to import. We did not import current
from ohms_law
,
so that function is unavailable to our code. It is usually a good practice to import the specific functionality you
need from a module with from
- import
pattern instead of importing the top level module, but that is by no means a
hard rule.
8.2.3. Example: Importing your work#
Let’s try importing two functions from a previous lesson. First, create a Python file called
importExample.py
and copy the functions my_name()
and convert_force()
to this file. Next, open up a JupyterLab session in the same folder as your importExample.py
file and import both
functions using the from
- import
structure. Finally, demonstrate that both functions work by running them in the
interactive shell.
Solution:
A copy of importExample.py
can be found here
. This file was made in JupyterLab by
creating a new PY file and copying the two functions into the file. From here, a new IPython notebook file is created
and the two functions are imported with the following command:
from importExample import my_name, convert_force
The ,
character allows us to list multiple objects to be imported from a common module. We could have written the
from
- import
scheme two times over with each function, but the above example is more concise.
From here, we can call the two functions to ensure they are working properly. For my_name()
, no input arguments
are needed. For convert_force()
, let’s convert 20 N to pounds-force. The code below issues the function calls:
my_name()
converted_force, converted_units = convert_force(initial_force=20, initial_units="N", converted_units="lbf")
print(f"The converted force is {converted_force} {converted_units}")
My name is Goldy Gopher!
The converted force is 4.5 lbf
As seen above, both functions work and now are deployable in other code!
Note
Remember that we could have imported both functions through the import call import importExample
. If we went this
route, we would need to include the library name to each function. So our function calls would now be
importExample.my_name()
and importExample.convert_force()
.
8.3. Python libraries#
So far, we have created a useful module “ohms_law.py” which lets us import functions instead of duplicating the function in our code. Instead of constantly creating new functions for our needs, we can also import additional modules into Python made by other people.
A Python library is a collection of modules that are gathered into one package. There are two types of Python libraries, the first are “built-in” libraries which are bundled along with Python, and second are “external” libraries which are available online to download. There are over 400,000 external libraries which can be installed with a Python Package Manager (e.g., Anaconda). In this section, let us explore some popular libraries.
Definition: library
A collection of modules that are gathered into one package.
8.3.1. The random
library#
The random
library is useful for generating random numbers. It is
a built-in library found in Python. Let us try importing random
and utilizing some functions from it:
from random import randint, random, gauss
print("Random integer 0 - 75:", randint(0, 75))
print("Random float 0 - 1:", random())
print("Random float from gauss distribution with mean = 10 and std = 5:", gauss(10, 5))
Random integer 0 - 75: 51
Random float 0 - 1: 0.8010090432893598
Random float from gauss distribution with mean = 10 and std = 5: 17.933945409951637
In the code above, we try out a few functions from random
. The first function used,
randint()
, returns a random integer from the
range of the passed min and max values. Next, the function
random()
is used to return a random float between
0 - 1. The last function used is gauss()
, which
returns a random float from a Gaussian (normal) distribution.
8.3.2. The math library#
The math library is a simple and useful built-in library
that contains multiple functions and mathematical constants. The code below shows an example of importing the
constant pi
(i.e., \(\pi\)) and the function log()
(i.e., log base 10, \(\log_{10}\)):
from math import pi, log
van_der_pauw_constant = pi / log(2)
print("VDP constant:", round(van_der_pauw_constant, 4))
VDP constant: 4.5324
8.3.3. Example: Random trigonometry#
Using both the random
and math
libraries, create a simple code block that displays the cosine of five random
numbers between 0 - 2\(\pi\). Output values should be floating point numbers with three significant figures after the
decimal point. You will need to look at math
library’s documentation to see how to implement a cosine function in
Python.
Solution:
There are a few ways one can do this depending on your overall Python knowledge. Since we have not covered
object-oriented programming or the NumPy library yet, we will use a for
loop to take the
cosine of five random numbers between 0 - 2\(\pi\). An example code block is shown below:
from random import random
from math import cos, pi
for i in range(5):
value = random() * (2 * pi)
output = cos(value)
print(f"The cosine of {value:.3f} is {output:.3f}.")
The cosine of 1.063 is 0.486.
The cosine of 6.050 is 0.973.
The cosine of 3.405 is -0.966.
The cosine of 1.303 is 0.264.
The cosine of 3.149 is -1.000.
8.3.4. The time library#
The time built-in library has useful functionality for getting
the current time or sleeping a python program to pause execution. The code below imports
time()
and
sleep()
from the time
library and then runs a for loop
where the program delays for one second and then prints out a timestamp:
from time import time, sleep
start_time = time()
for i in range(4):
# sleep 1 second
sleep(1)
# get a timestamp
timestamp = time() - start_time
print("timestamp:", round(timestamp, 4))
timestamp: 1.0012
timestamp: 2.0027
timestamp: 3.0042
timestamp: 4.0057
8.3.5. The datetime library#
Similar to the time library, the built-in datetime
library has useful functionality to parse and work with dates. The example below creates a datetime
object named
today
and then formats the object into a string with the .strftime()
datetime method.
from datetime import datetime
today = datetime.today()
print("Datetime object:", today)
today_string = today.strftime("%B %d %Y")
print("Formatted date string:", today_string)
Datetime object: 2024-08-08 09:10:03.980956
Formatted date string: August 08 2024
8.3.6. The NumPy library#
NumPy is not a built-in Python library, but it is included in the default Anaconda base
environment. It is an open source library that focuses on scientific computing. NumPy is a commonly used library for
many scientific applications, and we will explore this library further in a later chapter. For now,
let us rewrite our example code from the math
library example, but now using NumPy:
import numpy as np
van_der_pauw_constant = np.pi / np.log(2)
print("VDP constant:", round(van_der_pauw_constant, 4))
VDP constant: 4.5324
Notice in this example we introduce the as
keyword in conjunction with import
. The import
- as
pattern
allows you to import something using an alias name. Here, we import the numpy
library using the alias np
, which
is commonly done with this library to cut down on keystrokes. Therefore, we do not have to type out numpy.pi
to
utilize the value of \(\pi\), but instead we can simply type np.pi
.
8.4. Finding documentation#
There are a few ways we can investigate what functions and constants a library offers. One way we can do this
is to first import the library into Python and then pass its name through the help()
function. For example, we can
do this to the math
library with the following commands:
import math
help(math)
Furthermore, Python modules are simply Python code files, so we can look at the source file to understand how a
library works. For example, the random
source file can be in the
Python GitHub repository. This file also exists on your
computer, and when you call from random import random
, you are importing the random.py
file as a module.
Alternatively, you can search online to understand a library (e.g., “python docs library name”). Online documentation
often will include “Getting Started” guides and tutorials to get you familiar with the library. Since many libraries
have documentation that is unwieldy to display with the help()
command, reading a library’s documentation is
often best suited through a web browser.
8.5. Working with files#
Often you will want to read a text file as input or write a text file as output of your Python program.
The basic functionality of opening a file for reading or writing is done with the
open()
built-in function.
The open()
function takes in one required positional argument and many optional keyword arguments:
open(file, mode = "r", buffering = -1, encoding = None, errors = None, newline = None, closefd = True, opener = None)
The file
positional argument specifies the path to the file to be opened. Of the optional keyword arguments,
the mode
argument is the one you will use the most. The mode
specifies how open()
should treat the file that
is being opened. There are several modes, and you can read up on all the modes in the documentation,
but the most common are r
for read, w
for write, a
for append. By default, the mode
is set to r
to
simply read the file. Below is a summary of the behavior, and we will try each out in the following examples.
Mode |
Behavior |
---|---|
|
Creates file or clears the file contents, opens it for writing. |
|
Opens the file only for reading, writing is not allowed. |
|
Opens the file for writing, appends content to the end of the file |
As a reminder, you can check out all the arguments and modes of open()
with the help()
function:
help(open)
8.5.1. File paths#
A file path is a string that contains a listing of the folders and subfolders to where the file is located
followed by the name of the file. For example, we can generate the file path of a file called tutorial_test.txt
with the following commands:
# generate a file path with current directory
directory = "./"
filename = "tutorial_test.txt"
file_path = directory + filename
print(file_path)
./tutorial_test.txt
The directory ./
is shorthand for the current directory that the Python shell is operating in. If you are unsure of
what directory you are in, you can use the convenience function %pwd
that is available in JupyterLab to get the
absolute folder path of the current working folder:
# generate a file path using JupyterLab command
directory = %pwd
filename = "tutorial_test.txt"
file_path = directory + "/" + filename
print(file_path)
/srv/docs/intro/CEMS_Python_Toolkit/tutorial_test.txt
Notice that %pwd
will not include a trailing slash, so if we want to include our filename
in file_path
we need
to add a /
between directory
and filename
.
We can also get the absolute file path for a file in Python using the os.path
built-in module:
# generate a file path with absolute path using os.path
from os import path
directory = path.abspath(".") # get absolute path from the current directory
filename = "tutorial_test.txt"
file_path = directory + "/" + filename
print(file_path)
/srv/docs/intro/CEMS_Python_Toolkit/tutorial_test.txt
Hey! Listen!
The words “directory” and “folder” are often used interchangeably; they both refer to file containers in a computer file system.
8.5.2. Writing to a file#
Danger
In the examples below, we will be using the w
mode that will clear contents of a file being opened. We will be
running code blocks with “tutorial_test.txt” as the file path. If you happen to have data saved with that file name,
make sure you change the file name before trying out the code below. Do not blame this tutorial for eating your
homework.
Let us first try writing to a file. The following code block will open the file called “tutorial_test.txt” in the current directory:
# write data to a file called "tutorial_test.txt" in current directory
f = open("./tutorial_test.txt", "w")
f.write("hello world")
f.close()
This is the most basic using the open()
function to write a file. We pass the file path to the function as the
first argument, "./tutorial_test.txt"
, and then specify the mode we want to open the file (in this case w
) as the
second argument. We assign f
to be the file object that
represents the opened file. We then run the write()
function to write contents to the now empty file. Finally, we
close the file object with f.close()
to make sure the file is released from editing. If you use a text editor
like TextEdit on macOS or Notepad on Windows to open the file “tutorial_test.txt”, you should see “hello world”
printed out.
Hey! Listen!
If the file does not already exist, w
mode will create it. Therefore, w
mode will either create a file or
clear out the contents of a pre-existing file.
8.5.3. Using with
with files#
This simple way of editing files works, but it does require keeping track of all the open files and making sure
they are closed. The recommended way to work on files is to utilize the
with
keyword to edit
a file through the with open() as f:
statement followed by a code block that contains the write()
function.
Let us re-open our “tutorial_test.txt” file and write some different text:
# write data to a file called "tutorial_test.txt" in current directory
with open("./tutorial_test.txt", "w") as f:
f.write("goodbye world")
Notice that the code block above does not have the command f.close()
anywhere. That is because f.close()
gets
automatically run at the end of the with
code block. Using the with open() as f:
pattern is useful for containing
all the logic around writing or reading to a file in one code block. We will be using this pattern for the rest of the
examples.
If you open up “./tutorial_test.txt” again in a text editor, you will see the content of the file has changed. It is now
only “goodbye world”, as “hello world” was deleted when the file was opened using the w
mode.
8.5.4. Reading a file#
Now instead of using a text editor to open a file, let us use Python to read the contents of a file:
data = ""
# read data from "./tutorial_test.txt"
with open("./tutorial_test.txt", "r") as f:
data = f.read()
print("File data:", data)
File data: goodbye world
When a file is opened in r
mode (i.e., read mode), you can use the f.read()
function to read the entire contents of
the file. In this case, “goodbye world” was printed out due to our previous write command. Let us try to
put “hello world” back at the beginning of the file using two simple steps:
data = ""
# read data from "./tutorial_test.txt"
with open("./tutorial_test.txt", "r") as f:
data = f.read()
print("Initial file data:", data)
with open("./tutorial_test.txt", "w") as f:
f.write("hello world")
f.write(data)
with open("./tutorial_test.txt", "r") as f:
data = f.read()
print("File data after writing:", data)
Initial file data: goodbye world
File data after writing: hello worldgoodbye world
Well we got halfway there, we were able to put “hello world” in the file, but it is not in its own line.
To fix this, let us use the newline escape character (\n
) that we introduced in an earlier lesson to
insert an additional blank output line between the two strings:
with open("./tutorial_test.txt", 'w') as f:
f.write("hello world" + "\n")
f.write("goodbye world")
data = ""
with open("./tutorial_test.txt", 'r') as f:
data = f.read()
print("file data after writing:", data)
file data after writing: hello world
goodbye world
8.6. Using CSV files with the csv
and numpy
libraries#
So far we have shown a few simple ways to open, write, and read strings of data to files. In science and engineering applications, strings of data are often stored in an “array-style” format consisting of rows and columns. In order to be able separate out these data strings from one another, a “delimiter character” is often placed between these strings. Commonly used delimiters include commas (,), semicolons (;), quotes (“ ” or ‘ ’), pipes ( | ), slashes ( / or \ ), and tabs.
In particular, comma delimiters are a very popular choice in separating tabulated data. This has led to the creation
of the Comma Separated Value (CSV) file format. We have already gone over how we can parse and write files
using the open()
function and the .read()
and .write()
methods. These simple commands are somewhat cumbersome
in handling strings of data separated with delimiters (e.g., 2.0, 52.1, -73.2
). Fortunately, there are both
built-in and external libraries that can handle the CSV file format. In this section we will go over two of these
libraries.
8.6.1. Writing a file with the csv
library#
The built-in csv
library is a simple, but powerful library designed
to read, write, and modify CSV files. The library has two primary functions when working with CSV files: csv.reader()
and csv.writer()
. Let us first demonstrate how to write to a CSV file using the `csv.writer() function with the
example below:
import csv
from random import gauss
data = []
# generate array of random gaussian distribution (mean 10, std 3) in format of
# [ increment, random_float ]
for i in range(20):
data.append([i, gauss(mu = 10, sigma = 3)])
# write data to "./tutorial_txt.csv" in current directory
with open("./tutorial_txt.csv", "w", newline = "") as f:
writer = csv.writer(f, delimiter = ',')
writer.writerow(["Timestamp", "Data"])
for i in data:
writer.writerow(i)
In this example, we demonstrate how csv.writer()
works by creating a file that contains data calculated from a
Gaussian distribution. We first declare an empty list called data
. Next, we utilize a for
loop to generate a list
of two numbers (i.e., i
and the number resulting from the gauss()
function call), which are then appended to
data
using the .append()
method.
Afterwards, we open our file using the familiar with open() as f:
pattern, but now include the optional argument
newline = ""
. This optional argument ensures that no additional line returns are placed after writing a
comma delimited row of data and is
recommended when working with CSV files.
Next, we create a writer
object that is instantiated by calling csv.writer()
. The function csv.writer()
takes in
a file object as a required first argument, and allows for many optional
formatting options.
In our example, we specifically specify that delimiter = ","
, which is technically redundant since the CSV file
format uses ,
as its delimiter. We have added this for educational purposes in order to show how an optional format
can be included.
After creating the writer
object, we call the writer.writerow()
method with a list that contains the
names of each column we want in our file. This will be placed in the first row of our data file, so we can identify
each data column. In general, it is highly recommended to include a header row in your data files for readability!
We then loop through each entry list entry of data
and use .writerow()
to write each entry to the file.
8.6.2. Reading a file with the csv
library#
Now that we have written a file with csv.writer()
, we can try to read it with the csv.reader()
function:
data = []
with open("./tutorial_txt.csv", "r", newline = "") as f:
reader = csv.reader(f, delimiter = ',')
for i in reader:
data.append(i)
print("Data from file:", data)
Data from file: [['Timestamp', 'Data'], ['0', '8.752231021598503'], ['1', '10.44377105259593'], ['2', '9.774241368892826'], ['3', '16.16364942783288'], ['4', '10.337361596182236'], ['5', '7.607600277776483'], ['6', '7.060097702321116'], ['7', '11.73182015799266'], ['8', '5.076299345672038'], ['9', '8.133984123827288'], ['10', '13.577547142365455'], ['11', '8.687951112429399'], ['12', '1.8212427912863518'], ['13', '8.620258848069469'], ['14', '7.8440773748233115'], ['15', '12.636184221177668'], ['16', '9.56996571490079'], ['17', '9.813435529607816'], ['18', '9.182642778463114'], ['19', '12.970390973691483']]
Similar to before, we have an empty list called data
, and we use the with open() as f:
pattern to open our file for
reading (again adding the additional newline = ""
to the open()
function). We call the csv.reader()
function to
create a reader
object which we can use to read the file. We then iterate through the reader
object to loop through
the rows in the file, and we append each row to the data
list.
We can see from the print()
command that data
is a nested list (i.e., a list of lists) made up of strings. Our
current implementation of csv.reader()
casts all data as str
objects, which may not be desirable since we are
expecting our values to be float
objects. There are a few different ways we can fix this. The modified code below
shows how a simple post-processing step after reading the CSV file can remove the header row and casts the rest of
the entries as float
objects:
data = []
with open("./tutorial_txt.csv", "r", newline = "") as f:
reader = csv.reader(f, delimiter = ",")
for i in reader:
data.append(i)
headers = data.pop(0)
data = [[float(i[0]), float(i[1])] for i in data]
print("Data from file:", data)
Data from file: [[0.0, 8.752231021598503], [1.0, 10.44377105259593], [2.0, 9.774241368892826], [3.0, 16.16364942783288], [4.0, 10.337361596182236], [5.0, 7.607600277776483], [6.0, 7.060097702321116], [7.0, 11.73182015799266], [8.0, 5.076299345672038], [9.0, 8.133984123827288], [10.0, 13.577547142365455], [11.0, 8.687951112429399], [12.0, 1.8212427912863518], [13.0, 8.620258848069469], [14.0, 7.8440773748233115], [15.0, 12.636184221177668], [16.0, 9.56996571490079], [17.0, 9.813435529607816], [18.0, 9.182642778463114], [19.0, 12.970390973691483]]
After reading our CSV file, we “pop” out the first element with the
.pop()
built-in method for lists. The
command .pop(0)
will pop out the passed index (i.e., 0
) and remove it from the list. Then we use
list comprehension to loop through the data, cast the first and second elements of each sublist
as a float
object, and reassign the whole thing back to data
.
Another solution is to change when writer
objects generate quotes for data (i.e., making them str
objects).
According to the csv
documentation, we can pass the
formatting argument
quoting = csv.QUOTE_NONNUMERIC
to our csv.writer()
and csv.reader()
calls to add quotes to all data EXCEPT numerical-based data, which
instead will be represented as float
objects. This modification is done in the code below:
data = []
# generate array of random gaussian distribution (mean 10, std 3) in format of
# [ increment, random_float ]
for i in range(20):
data.append([i, gauss(mu = 10, sigma = 3)])
# write data to "./tutorial_txt.csv" in current directory
with open("./tutorial_txt.csv", "w", newline = "") as f:
writer = csv.writer(f, delimiter = ",", quoting = csv.QUOTE_NONNUMERIC)
writer.writerow(["Timestamp", "Data"])
for i in data:
writer.writerow(i)
data = []
with open("./tutorial_txt.csv", "r", newline = "") as f:
reader = csv.reader(f, delimiter = ",", quoting = csv.QUOTE_NONNUMERIC)
for i in reader:
data.append(i)
print("Data from file:", data)
Data from file: [['Timestamp', 'Data'], [0.0, 12.174863823786264], [1.0, 8.329739925527115], [2.0, 4.00039748716941], [3.0, 11.901080993775455], [4.0, 9.219681978472881], [5.0, 6.7469067964017215], [6.0, 16.573850134436814], [7.0, 10.94091444263089], [8.0, 12.252527074507826], [9.0, 7.078531246520325], [10.0, 5.364872216646133], [11.0, 13.02571898988545], [12.0, 12.236918776356195], [13.0, 12.449399391420256], [14.0, 7.957243008825316], [15.0, 4.320703748030059], [16.0, 6.849109500988111], [17.0, 12.478602677986562], [18.0, 12.33658456801999], [19.0, 14.241707920111716]]
8.6.3. Reading a CSV file with the numpy
library#
Yet another solution in regard to casting data in the proper class utilizes the function numpy.load_txt()
from the
NumPy library to read our text file, skip the header, and cast the entries as floats. Even though we have
briefly discussed loading the NumPy library earlier in this lesson and will hold
off discussing this library in much more detail in a later lesson, let us use the
numpy.loadtxt()
function from the
numpy
library to load our CSV file:
from numpy import loadtxt
data = loadtxt("./tutorial_txt.csv", delimiter = ",", skiprows = 1)
print("Data from file:", data)
Data from file: [[ 0. 12.17486382]
[ 1. 8.32973993]
[ 2. 4.00039749]
[ 3. 11.90108099]
[ 4. 9.21968198]
[ 5. 6.7469068 ]
[ 6. 16.57385013]
[ 7. 10.94091444]
[ 8. 12.25252707]
[ 9. 7.07853125]
[10. 5.36487222]
[11. 13.02571899]
[12. 12.23691878]
[13. 12.44939939]
[14. 7.95724301]
[15. 4.32070375]
[16. 6.8491095 ]
[17. 12.47860268]
[18. 12.33658457]
[19. 14.24170792]]
This call is remarkably short compared to the other examples. The only required argument for numpy.loadtxt()
is the
path to the file that will be read. The numpy.loadtxt()
function is used to load any type of text file, not just CSV
files, so the default delimiter is a space character " "
. The delimiter = ","
arguments sets the single comma
character as the delimiter in our CSV file, and the skiprows = 1
argument skips over the first row that
contains our column headers of "Timestamp", "Data"
.
8.7. Conclusion#
Extending on what we learned when writing functions, we can now import
our Python code from one
file to another as a Python module. By developing a code base of Python files / modules, we can import common
functionality throughout our programs and JupyterLab notebooks. This can cut down on development time and make a
more manageable centralized code base. We can also import
many built-in and external libraries in Python. We looked
at the random,
math,
time,
and datetime built-in libraries,
and briefly introduced the external library NumPy.
We worked on how to write and read files
with Python, how to write and read CSV files with the csv
library, and how to read text files with the
numpy.loadtxt()
function.
There are a lot of Python libraries out there, and it can be difficult to figure out
which library is the best to use or how we can go about writing our own library. But we can always run the command
import this
to remind ourselves of how to write beautiful Python code.
import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
8.8. Want to learn more?#
Python Software Foundation - The Random Library
Python Software Foundation - The Math Library
Python Software Foundation - The Time Library
Python Software Foundation - The Datetime Library
NumPy - Documentation
NumPy - GitHub Repository