Language Internals
Part 6 of 6 · Python Language ProficiencyPackaging, Imports, venv/uv/poetry, Profiling & Perf Pitfalls
Environments, import graphs, wheels, and profiles before a rewrite.
- 1Gist
- 2Maps
- 3Q&A
- 4Sandbox
Voice readout needs Web Speech Synthesis in this browser.
Question ladder
L1
Why not install dependencies into the system interpreter?
Answer
Projects then share one site-packages and break each other. A venv, or uv's environment, gives this project one interpreter.
L2
What is a wheel compared with an sdist?
Answer
A wheel is a built artifact and installs by unpacking. An sdist is source and may need a compiler or a build backend.
L3
What does pyproject.toml decide?
Answer
Project metadata, dependencies, and which build backend produces the artifact. PEP 621 is the metadata table.
L4
Why does from x import y freeze a binding?
Answer
The name y in this module is bound to the object that was looked up at import time. Rebinding x.y later does not update it.
L5
How do you break a circular import?
Answer
Move the shared piece to a third module, postpone the import to the function, or keep typing-only imports under TYPE_CHECKING.
L6
Which profiler for a CPU function versus a production stall?
Answer
cProfile for a deterministic function-level run. py-spy for a low-overhead sample of a live process. A blocked loop wants the asyncio page, not a tighter inner loop.
L7
What language-level costs show up before a C rewrite?
Answer
Quadratic string building, repeated global lookups, materializing huge lists, pickle in a process pool, and import side effects on cold start.
Failure modes
System-site installs
CI and laptops drift because nothing pins the environment.
Import side effects
Opening networks or building huge tables at import dominates CLI and serverless cold start.
sys.path hacks
Inserting directories hides a real package layout and breaks once the working directory changes.
Optimizing the wrong function
A rewrite lands beside the hotspot the profile already named.
Misconceptions
A lockfile is optional if versions are pinned in a sentence in the README.
CI should install from a lock. Ranges without a lock resolve differently next month.
Import is free after the first call in a long-running server.
The first import still taxes cold start, tests, and CLI tools. Keep module bodies cheap.
py-spy and cProfile answer a stalled event loop.
They show CPU. A loop stuck in a blocking call needs the asyncio checklist first.
Interviewer traps
Rewriting a function in C before showing a profile.
Name cProfile or py-spy and the function that owns the time.
Treating poetry, uv, and venv as mutually exclusive religions.
venv is the isolation idea. uv and poetry are workflows that produce a lock and an environment.
Explaining wheels as a JavaScript bundler.
A wheel is an install artifact for Python. The comparison is lockfile and environment, not a chapter on bundlers.
Design scenario
Same prompt for every reader.
Requirements
One lockfile, wheels in production installs, an src layout, and a profile that names the function before any rewrite.
Traffic / scale
Short-lived CLI invocations plus a long-running service.
Latency
Import time is part of CLI latency. The service budget is the profiled function, not the import.
Consistency
CI installs the locked set, including wheels when they exist.
Availability
A missing compiler on the production image must not be required at startup.
Failure assumptions
- Dependencies were installed into the base image's system Python.
- An sdist-only package compiles during deploy.
- Someone is rewriting a function that is 2 percent of cProfile's cumulative time.
Constraints
- Stay on packaging, imports, and measurement.
- Send a blocked loop back to the asyncio page instead of micro-optimizing it.
Prompt
A CLI and a service share a library. Cold start is slow, CI sometimes compiles a dependency, and a hot path is suspected but unmeasured.
Overview
Shipping Python is an environment, an import graph, and a measurement. The interview is whether you can explain a wheel, a lockfile, and why a function is hot.
Environments
| Tool | Role | Interview note |
|---|---|---|
venv plus pip | Stdlib isolation | Baseline |
| uv | Fast resolver, installer, and venv | A common modern default |
| poetry | Dependencies and a build workflow | Lockfile plus packaging |
| pip-tools | Compile a lock from ranges | Still common in CI |
Never install project dependencies into the system interpreter. Pin CI to a lockfile.
# uv venv && source .venv/bin/activate
# uv pip install -r requirements.lock
# uv run pytestFrom source to an installed environment
Flow
- 1
pyproject.toml
- nextBuild backend
- 2
Build backend
- nextsdist source
- 3
sdist source
- nextWheel artifact
- 4
Wheel artifact
- nextInstall into the venv
- 5
Install into the venv
Lesson map
Packaging, Imports, venv/uv/poetry, Profiling & Perf Pitfalls
Environments, import graphs, wheels, and profiles before a rewrite.
Architecture. Architecture
Select a node to see why it exists, or an edge to see the protocol, direction, effect, and consequence.
Mermaid export
flowchart TB meta["pyproject.toml"] backend["Build backend"] sdist["sdist source"] wheel["Wheel artifact"] meta -->|pyproject.toml to Build backend| backend backend -->|Build backend to sdist source| sdist sdist -->|sdist source to Wheel artifact| wheel
- A wheel is built. Install unpacks it.
- An sdist is source. Something must build it.
- Editable installs (
pip install -e .or the uv equivalent) point the environment at your checkout. Know that the import path is your tree, not a copy in site-packages. - An
src/layout avoids importing the checkout by accident because the current directory sits onsys.path.
Imports
Press Run. Snippets must be self-contained — no network, files, or native modules.
from x import y is that pattern. This module's y is the object from import time. A later assignment to x.y does not move the local name.
| Pitfall | Fix |
|---|---|
| Circular imports | A third module, a function-local import, or TYPE_CHECKING |
| Work at import | Lazy init. Keep the module body cheap |
sys.path inserts | A real install. PYTHONPATH only for local dev |
| Star imports | Explicit names so checkers and readers can see the binding |
The cache is sys.modules. The first import executes the body. Later imports return the same module object.
Profile, then rewrite
| Tool | Use |
|---|---|
cProfile and pstats | Function-level CPU in a run you control |
py-spy | Sampling a live process with low overhead |
| asyncio debug mode | Loop stalls. See the asyncio page |
tracemalloc | Allocation sites |
time.perf_counter | A microbenchmark you do not trust alone |
Press Run. Snippets must be self-contained — no network, files, or native modules.
Language-level costs that show up before a new runtime:
- String concatenation in a loop. Build a list and join, or use a buffer.
- Global and attribute lookups inside a tight loop. Bind locals.
- Lists where an iterator would do.
- Pickle and JSON on a process boundary. The GIL page owns that choice.
- Blocking the asyncio loop. That is not a CPU rewrite.
Packaging compared with JS
| Concern | Python | JS/TS |
|---|---|---|
| Lock | uv.lock, poetry, or a compiled requirements file | package-lock or pnpm-lock |
| Isolation | A venv per project | node_modules per project |
| Native code | Wheels and manylinux tags | Prebuilds |
| Publish | PyPI | npm |
The hub keeps the longer runtime comparison. This table is only the install path.
Interview Q&A
Wheel or sdist?
Answer
Prefer a wheel in production so install does not compile. An sdist is what you publish when the artifact must be built on the target, or what a backend consumes to produce the wheel.
Why is import time a latency number?
Answer
CLI tools and serverless cold starts pay it on every process. Heavy imports and import-time work dominate before your function runs.
How do you chase a 300 millisecond stall in an async service?
Answer
Look for a blocking call on the loop first. Then sample with py-spy or time the request. Algorithm work comes after the profile names a function.
What does editable install change?
Answer
The environment imports your source tree. Edits show up without a reinstall. You can also import a different copy than the wheel you think you shipped.
uv, poetry, or venv?
Answer
venv is the isolated interpreter. uv and poetry are tools that create an environment and a lock. Pick one workflow and make CI use its lock.
Why does src layout matter?
Answer
Running from the repo root puts the current directory on sys.path. A package sitting next to your tests can shadow the installed one. src/ keeps the checkout off that path.
What is a red-flag performance answer?
Answer
A rewrite, a new cache, or a C extension with no profile and no before-and-after number.
What do you measure on a cold CLI?
Answer
Time to import the entry module, then time inside the command. Fix import side effects before you touch the algorithm.
Pitfalls
- "Works on my machine" without a lockfile.
- Compiling an sdist on a slim production image.
sys.path.insertin application startup.- Quadratic string building in a loop the profile already flagged.
- Micro-optimizing a function that is not the hotspot.
- Treating a blocked event loop as a CPU problem.
A CLI takes two seconds before it prints help. List the first three measurements (import time, a profile, a lockfile diff) and the one change you would refuse to make before those numbers exist.