PYTHON 102
python-102 · v1.0.0
ivyx✓
Classes, modules and your own package: PYTHON 101 ends at functions, so this is where a program stops being a script. Write a class that owns its state, split one file into modules, and package the result so another project can import it.
What this course is for
By the end of this course you can write a class with a purpose, split a program into modules, and package your own code so another project can import it.
What you will be able to do
- Write a class whose instances own their own state, and predict what changing one does to another
- Tell a method that changes state from one that answers a question, and catch the method that changes a local instead
- Find the list every instance shares by accident, on the class and in a default argument, and move it where it belongs
- Give a class a repr, an equality and a length, and say what == and in did before you wrote them
- Subclass with super() and choose composition when is a is a lie
- Write a module, import it, and explain why editing the file changes nothing until you reload
- Build a package with an __init__ and catch the file that shadowed a standard library module
- Package two modules with a pyproject.toml so a project in another folder can import them
Who it is for
Learners who finished PYTHON 101 and can write a function, a loop and a file, and anyone whose scripts have grown past one file and started sharing state by accident.
Before you start
- PYTHON 101, for functions, dictionaries, loops and writing a file
Lesson path
A class, its instances, and the state each one owns
- 1A class with a purpose55 min
Define a class with __init__, hold state on self, and make two instances that share nothing
- 2Methods and state55 min
Write methods that change state and methods that answer questions, and say which is which
- 3Shared state60 min
Catch the class attribute and the mutable default argument that every instance shares
- 4Dunder methods55 min
Give a class __repr__, __eq__ and __len__, and predict what == and in do without them
Two ways to build on a class you already have
- 5Inheritance and composition55 min
Subclass with super(), then pick composition when is a is a lie
A program split into files, and what import really does
- 6Modules60 min
Write a .py file, import it, and find out why editing it changes nothing
- 7Packages55 min
Build a folder with an __init__.py, import from it, and catch the stdlib name you shadowed
Code another project can import
- 8Your own package55 min
Build a two-module package with a pyproject.toml that a project in another folder can import
About this course
PYTHON 102 · Classes, modules and your own package
PYTHON 101 ended at functions and files, with a car on the lot kept as a
dictionary and every function obliged to know its keys. This course is where a
program stops being a script. A Car class owns its fields and refuses a bad
one in __init__, its methods are sorted into commands that write to self
and queries that do not, and by lesson 5 a truck inherits from it while a lot
is composed of it. Then the code leaves the notebook: a module in a file, a
package in a folder with an __init__.py, and a project with a
pyproject.toml that a script in another folder can import.
Nothing here needs a library. The course runs on the language PYTHON 101
already taught, plus importlib, subprocess and pathlib from the standard
library, and every file it writes carries the py102 prefix so nothing
collides with a student's own work. The last lesson removes them.
How this course teaches
Every lesson is the same twenty six cells, and nine of them are yours.
- A prediction you commit to before the cell runs. It is graded on the reasoning, not the guess, and being wrong here is the point.
- Warmups: a one line blank or a two to four line exercise under the theory it practices, each with a four rung hint ladder behind it, where the last rung explains and still does not hand over the code.
- An exercise that is broken when you open it.
- A diagnose cell: code that runs, prints a confident and plausible answer, and is wrong. Something below it refuses the answer by computing the same thing a second way, so nothing is taken on trust.
- A challenge that ends in a sentence you write. The tutor grades the sentence, which means a green tick you earned for the wrong reason can be taken back.
No cell in this course passes in the state it ships. That is deliberate, and it is checked mechanically before the course is published.
The particular danger of this subject is code that runs cleanly and changes
the wrong thing, or nothing. A misspelled attribute creates a new field and
the discount vanishes. A method computes the new price into a local and the
car keeps the old one. A list in the class body is one list for every
instance, so one car's history reports another car's discount. == on two
identical cars is False until you define it, and defining it silently takes
away hashing. A second import ignores your edit, a name copied with from
keeps its old body across a reload, and a file named random.py beside a
script wins over the standard library and blames the module you meant. Every
diagnose cell in this course is one of those, and every cross check is the
second route that refuses it: the object's own vars, its own price against
its own starting price, is where == was redefined, the file on disk against
the module in memory.
What you will be able to do
- Write a class whose instances own their own state, build a lot of them from
raw rows, and tell an alias from a copy with
is. - Sort methods into commands and queries, catch the command that writes to a local, and catch the query that sorts a list on its way to the answer.
- Read a class body and say which names are safely shared, move a list into
__init__when it is not, and fix a mutable default argument. - Give a class
__repr__,__eq__,__hash__,__len__,__iter__,__lt__and__add__, and know that__eq__is a definition of what the thing is. - Extend a class with
super(), put an object inside another and delegate to it, and choose between the two with a question about meaning. - Write a module, import it both ways, explain why a second import ignores an
edit, reload the right object, and ship a file with a
__main__guard. - Build a package with a public face and a
__main__.py, run it with-m, find out which file a name resolved to, and name files so nothing shadows the standard library. - Lay out a project with a
pyproject.toml, prove it imports from another folder, check its version in both places, and say which copy of a package answered and why.
The lessons
1. A class with a purpose. class Car: with an __init__ that stores four
fields on self, a default damaged=False, and a guard that refuses a
negative odometer. Two calls make two objects; c = a makes one object with
two names. The diagnose writes a discount to pirce and the print reports the
old price with complete confidence.
2. Methods and state. car.drive(120) is Car.drive(car, 120). A command
writes to self and returns None; a query returns and writes nothing. The
prediction cell's mark_down returns 16500 twice and changes nothing, and the
diagnose's cheapest answers correctly by sorting the lot in place.
3. Shared state. count = 0 and history = [] side by side in a class
body, updated the same way through self, go opposite ways: the number stays
private and the list is shared, because += rebinds and append mutates. The
same trap in a default argument, __defaults__ to see it, and is to prove
sharing. The Ravon reports 1500 in discounts after one markdown of 1000.
4. Dunder methods. print(car) is an address until __repr__; == is
is until __eq__; and defining __eq__ makes the class unhashable until
__hash__ matches it. __len__, __iter__, __lt__ and __add__ for a lot.
Equality by price finds the Ravon when asked for the Mirai, refused by is.
5. Inheritance and composition. class Truck(Car): inherits everything;
a child __init__ replaces the parent's until super().__init__ is called,
and the truck without it is built, is a Car, and has no odometer. A lot has
cars and inheriting from list hands it extend, which walks past the guard
in append.
6. Modules. A .py file written from the notebook and imported. The
second import is a lookup in sys.modules; editing the file and importing
again changes nothing, importlib.reload reruns it into the same object, and a
function copied out with from keeps its old body across the reload, quoting
12000 against the module's 12250. A __main__ guard, and subprocess.run
with sys.executable to run a file the way a terminal would.
7. Packages. A folder with __init__.py, relative imports with a leading
dot, __init__ as the public face, __main__.py and -m. A dice project's
random.py shadows the standard library for every script beside it and the
error blames random. A re-exported number is a copy: the package says 0.18
while total charges 10 percent.
8. Your own package. A project folder with pyproject.toml, a stand in
"other project" that cannot import it, and the three exits: PYTHONPATH,
sys.path.insert, and the install this lesson explains but does not run.
Appending the project to sys.path imports the stale 0.1.0 beside the
notebook, because the notebook's folder is first. Tests run with -m from the
root, the version checked in both places, and a challenge that builds a
garage project from nothing and runs it from elsewhere.
What you need
- A Python kernel, 3.9 or later. No packages.
- About 450 minutes across the eight lessons, at 55 to 60 each.
- PYTHON 101, for functions, dictionaries, loops and writing a file.