Reusing code with import
A module is a Python file whose names (functions, constants, classes) other code can use. import math loads the module math from the standard library and makes it available under that name: you then write math.sqrt(2). Python ships with hundreds of modules, and anything you install later (for example numpy) is imported the same way. Put imports at the top of the file so a reader sees at once what the file depends on.
import math
import statistics
# Use a name from a module with module.name
print(math.sqrt(252)) # 15.874507866387544
print(round(math.sqrt(252), 2)) # 15.87
returns = [0.01, -0.02, 0.015, 0.0]
print(round(statistics.stdev(returns), 4)) # 0.0155from ... import and aliases
from datetime import date brings just one name in, so you write date(2025, 1, 2) without the prefix. import numpy as np gives a module a shorter alias, a convention you will see everywhere. Avoid from module import *: it dumps unknown names into your file and can silently replace your own. Prefer clear names, and use the prefix when it makes the origin obvious.
from datetime import date
from math import sqrt as square_root
import statistics as stats
# Only the names you asked for are imported
start = date(2025, 1, 2)
end = date(2025, 3, 3)
print((end - start).days) # 60
print(square_root(16)) # 4.0
print(stats.mean([1.0, 2.0, 3.0])) # 2.0Your own modules
Any .py file is a module. If fees.py sits next to main.py and defines commission, then main.py can say import fees and call fees.commission(...). When a file is run directly, Python sets its __name__ to "__main__"; when it is imported, __name__ is the module name. So the guard if __name__ == "__main__": makes code run only when the file is executed, not when it is imported, which keeps demos and tests out of the way.
# fees.py
RATE = 0.001
def commission(notional):
return notional * RATE
if __name__ == "__main__":
print(commission(10000)) # runs only with: python fees.py
# main.py (next to fees.py)
import fees
print(fees.commission(50000)) # 50.0
print(__name__) # __main__Where Python looks, and a classic trap
On import name, Python searches the folder of the running script first, then the standard library and installed packages (the list is sys.path). The first match wins. That is why a file of yours named random.py or statistics.py shadows the real module, and import random then loads your file and fails in confusing ways. Never name your files after standard-library modules. Also avoid two modules that import each other at the top (a circular import); move the shared piece into a third module.
import sys
import random
# Imported modules are remembered in sys.modules; sys.path is the search list
print("random" in sys.modules) # True
print(random.__name__) # random
print(len(sys.path) > 0) # True
# A quick tour of useful standard-library modules
import collections, datetime, itertools, pathlib
print(collections.Counter("AAPL")["A"]) # 2
print(datetime.date(2025, 1, 2).weekday()) # 3 (Thursday; Monday is 0)datetime, statistics, csv, json, collections, itertools, pathlib). Tested library code is almost always safer than a quick homemade version, and the lab marks hand-parsing of dates as a technique error.import modulethenmodule.name;from module import namefor one name;import module as shortfor an alias.- Imports go at the top; avoid
import *. - Do not name your files like standard-library modules; use
if __name__ == "__main__":for code that should only run directly.
Next up: packages and project layout, how to organise several modules into folders that import cleanly.
Lab · what's graded
- Measure volatility with
daily_vol25 pts - Scale volatility to a year with
annualize_vol25 pts - Count the days between two dates with
days_between25 pts - Tell weekdays from weekends with
is_business_day25 pts