Code reuse is the practice of naming a piece of logic once and calling it from many places. Python gives you three main units of reuse, listed from smallest to largest: functions (a named block of statements), modules (a .py file full of functions, classes and constants), and packages (folders of modules). Every real program is a balance of these three.
Start at the function level. Any block of code you copy twice is probably a function in disguise. A good function has one clear responsibility, a descriptive name, and a short parameter list; it returns a value rather than relying on side effects. The unit tests are short and name one behavior each. That discipline alone fixes a lot of code-quality problems.
Move up to the module level when a group of functions naturally belong together. A module provides a namespace: from myproj import auth lets you call auth.login() without colliding with a login function elsewhere. Modules are also where you put module-level constants, type aliases, and "factory" helpers that produce configured objects.
Finally, use packages to group related modules once the module count passes a handful. A package's __init__.py can re-export the most important names so consumers import from the top level rather than from deep paths. Think of the package as the public face of a feature; the sub-modules are its implementation detail.
The right-sized function
Guideline: a function should fit on a single screen and do one thing. If you catch yourself describing it with "this function does X and Y", split it. Docstrings ("""one-line summary.""") pay for themselves within a month.
Parameters beat globals. A pure function (inputs only through arguments, outputs only through the return value) is dramatically easier to test and reuse than one that reaches out to module-level state.
Modules and the import graph
Imports form a directed graph. Keep it acyclic: a imports b, b imports c, and nothing goes backwards. Circular imports usually indicate that two modules want to be one, or that a shared helper should live in a third module that both can import.
When you're unsure where a function belongs, look at what it depends on. A function that only uses primitives belongs in a low-level helper module; one that ties together several features belongs higher up in the graph.
Mechanisms that support reuse at each scale.
| Tool | Purpose |
|---|---|
def fn(...)statement | Declares a function, the smallest reuse unit. |
import modulestatement | Makes another file's names available by namespace. |
__init__.pyfile | Marks a folder as a package. |
functools.partialfunction | Fixes some arguments to build a specialized callable. |
typingmodule | Type aliases keep function contracts readable. |
""" docstring """convention | One-line summary + details; shown by help(). |
pydocmodule | Generates docs from your modules and functions. |
PEP 8style guide | Naming and formatting conventions. |
Organizing Code into Reusable Units code example
The script below shows how a single reusable helper can live at three scales — function, module, and package re-export.
# Lesson: Organizing Code into Reusable Units
import textwrap
from functools import partial
from pathlib import Path
from tempfile import TemporaryDirectory
import importlib
import sys
def normalize_name(value: str) -> str:
"""Trim whitespace and lowercase a name."""
return value.strip().lower()
print("direct call:", normalize_name(" Ana Ng "))
# Specialize via partial: same logic, different default shape
prefix_norm = partial(lambda p, s: normalize_name(f"{p}-{s}"), "user")
print("specialized:", prefix_norm(" Ana Ng "))
# Same function living in a tiny package
with TemporaryDirectory() as tmp:
pkg = Path(tmp) / "lib"
pkg.mkdir()
(pkg / "__init__.py").write_text(
"from .text import normalize_name\n__all__ = ['normalize_name']\n",
encoding="utf-8",
)
(pkg / "text.py").write_text(textwrap.dedent('''
def normalize_name(value: str) -> str:
"""Trim and lowercase a name."""
return value.strip().lower()
''').strip(), encoding="utf-8")
sys.path.insert(0, str(tmp))
try:
lib = importlib.import_module("lib")
print("package call:", lib.normalize_name(" Ben AL "))
print("docstring :", lib.normalize_name.__doc__)
finally:
sys.path.pop(0)
for key in [k for k in sys.modules if k.startswith("lib")]:
del sys.modules[key]
The three calls are the same idea at three scales:
1) Plain function call: the smallest reuse unit.
2) `functools.partial` specializes a function without copying the logic.
3) Importing from a package: same function, now sharable across projects.
4) The docstring is visible through `help()` and IDE tooltips.
Try factoring a one-liner into a reusable function.
# Before: repeated inline
def total_a(xs): return sum(x for x in xs if x > 0)
def total_b(ys): return sum(y for y in ys if y > 0)
# After: one helper, two callers
def positive_total(values):
"""Sum only the strictly positive numbers."""
return sum(v for v in values if v > 0)
print(positive_total([-1, 0, 3, 5]))
print(positive_total([10, -2, 7]))
Small contract-level checks.
from functools import partial
def add(a, b): return a + b
add5 = partial(add, 5)
assert add5(3) == 8
def f(x): """doc"""; return x
assert f.__doc__ == "doc"
assert callable(f)
Running prints:
direct call: ana ng
specialized: user- ana ng
package call: ben al
docstring : Trim and lowercase a name.