← All courses
IVYXSTUDIO · COURSE

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.

beginner450 min8 lessonsen
#python#classes#modules#packaging#programming#ai-series#beginner

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

Objects4 lessons

A class, its instances, and the state each one owns

  1. 1A class with a purpose55 min

    Define a class with __init__, hold state on self, and make two instances that share nothing

  2. 2Methods and state55 min

    Write methods that change state and methods that answer questions, and say which is which

  3. 3Shared state60 min

    Catch the class attribute and the mutable default argument that every instance shares

  4. 4Dunder methods55 min

    Give a class __repr__, __eq__ and __len__, and predict what == and in do without them

Reuse1 lesson

Two ways to build on a class you already have

  1. 5Inheritance and composition55 min

    Subclass with super(), then pick composition when is a is a lie

Files that import2 lessons

A program split into files, and what import really does

  1. 6Modules60 min

    Write a .py file, import it, and find out why editing it changes nothing

  2. 7Packages55 min

    Build a folder with an __init__.py, import from it, and catch the stdlib name you shadowed

Shipping1 lesson

Code another project can import

  1. 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.