LightMySky

Interfaces, coupling and what a module promises

A module's interface states the public names and behavior callers may rely on. Coupling describes dependencies between modules. Depending on private details can increase the work caused by a change. A compatible public contract can let a module change its implementation without caller edits.

No account needed. Progress saves in this browser.

What a learner can do afterwards

  • State the promise of a module without describing how it is implemented
  • Find the place where one module reaches past another's interface
  • Predict which of two designs makes a stated future change cheaper

1 · Read

You have written testable requirements and assigned responsibilities to classes. A module groups related code behind an interface. That interface states the public names and documented behavior callers may rely on: accepted inputs, results, errors and promised effects. Private helpers and storage are implementation details. Internal changes must keep the public contract compatible.

Try it together

A stock module accepts a product ID and returns its available quantity or an unknown-product error. That describes observable behavior. Searching a private list with a loop describes one implementation. The module could use another storage method while keeping its contract. To write a behavior-only promise, state what callers supply and observe without choosing private storage or an algorithm.

Caller supplies product IDModule checks its recordsReturn quantity or error

The request and result are public behavior. The module owns the record lookup.

In Python, the first ordinary import of a module executes its top-level statements. Later imports usually reuse the cached module. Defining a function does not call its body. To keep a demo from printing on import, indent it under `if __name__ == "__main__":`. The block runs when the file runs directly as a script, and is skipped on ordinary import. Keep reusable definitions outside it. The guard does not stop other top-level code.

Ordinary import__name__ is module nameGuarded demo skipped

After `import shapes`, use `shapes.Circle()`. After `from shapes import Circle`, use `Circle()`. After `import shapes as sh`, use `sh.Circle()`. A module prefix or its alias shows the origin at each qualified use. All three forms can use the same public class. Direct import alone does not mean dependence on private internals. A public rename can affect callers using any of these forms.

Coupling describes dependencies between modules. Reading private `_items` depends on that storage attribute. Calling public `total()` depends on its documented contract. Removing `_items` breaks a caller that reads it. A compatible `total()` can hide the storage change from its callers. Public names alone are not enough: changing promised results or errors also changes the interface.

Caller calls total()Module reads its storageModule returns total
The caller requests the total through a public operation instead of reading private storage.
Try it together

Compare designs against a specific change. Suppose a private `_lookup` helper is renamed while public `quantity()` keeps its name and behavior. A caller of `_lookup` needs an edit; a caller of `quantity()` does not need one for that rename. Separate caller edits from work inside the module. Dependencies affect change cost, but testing, implementation work and other factors also matter.

If an approved feature needs access the interface does not offer, request a documented public operation. For a tally reset, define the operation's effects and errors so the module can update its own counter. A caller that writes a private counter depends on its current representation. Copying the storage code into callers also spreads that dependency.

Rely on documented names and behavior. Keep private state behind public operations. Compare dependencies against a stated change, and guard demos that should run only as scripts.

Lesson, questions and flashcards written for this dataset. Answer choices revised for this edition. Python textbook records on top-level code and using modules with classes informed the concept and exercise study; their prose and figures are not reproduced.

The readings Separate a reusable module from its demonstration and Check the dependency before predicting a break were independently written for this dataset. Python textbook records informed factual and exercise-structure study; no textbook prose is reproduced.

More to read

Separate a reusable module from its demonstration

Imagine a module containing a reusable temperature converter and a demonstration that asks for input. Another program needs the converter but cannot stop to answer the demonstration's questions. If importing the module starts that demonstration, the module does not meet this caller's stated need for an import without prompts.

Python normally executes a module's top-level statements when it first loads the module through an ordinary import. A function definition creates the function; it does not run the function's body. A top-level call to the demonstration does run. Later ordinary imports in the same process usually use the cached module instead of executing its top-level statements again.

Keep the converter's definition outside the main guard. Place the demonstration call in an indented block under `if __name__ == "__main__":`. During an ordinary import, `__name__` is the module's import name, so that block is skipped. Running the file directly as a script gives `__name__` the value `"__main__"` and permits the demonstration to run.

This guard does not cancel other top-level statements. A print or file update elsewhere can still happen during loading. Review those effects against the module's documented contract. The presence of a guard alone does not prove that importing the module is silent.

Check the dependency before predicting a break

Two callers use the same documented public Circle class. One writes `import shapes` and then `shapes.Circle()`. The other writes `from shapes import Circle` and then `Circle()`. A third could use `import shapes as sh` followed by `sh.Circle()`. Qualification shows the module name or an alias at the use site. It does not, by itself, prove that one caller knows more about private implementation details.

Now specify an update. If the module replaces a private storage structure while preserving Circle's public contract, that storage change need not require edits to these callers. If the public class is renamed, callers using any of the three forms may need changes. The proposed update determines which dependency matters.

Names are only part of a contract. Callers may also depend on documented accepted inputs, returned results, error responses and effects. Keeping a function name while changing a promised result does not preserve that promise.

For a change review, list what each caller uses and identify which of those dependencies the update changes. Distinguish edits to callers from edits inside the module. A design that avoids one private dependency can avoid the caller repair caused by changing that detail. It does not guarantee that every future update will cost less.

2 · Watch

Take it off screen

Print a worksheetA4 with an answer key page for grown-ups. No screen, no internet.

Where it sits

Then practise

8 questions wait behind this lesson, each with its answer explained. Every answer feeds the sky: stars light as they are learned, and dim when it is time to come back.

Spotted a problem on this page? Tell us
Interfaces, coupling and what a module promises · Computing, ages 19 to 20 · LightMySky