AlgoMaster Logo

from...import

High Priority25 min readUpdated June 6, 2026
Listen to this chapter
Unlock Audio

The plain import module form is the safest shape of import, but it isn't always the most convenient. When you call pricing.cart_total ten times in a function, the prefix adds noise. from...import pulls specific names out of a module and binds them straight into your scope, so the prefix is no longer needed. This lesson covers the full mechanics of from...import, including renames with as, the import * form, what __all__ does, relative imports inside packages, and circular-import problems.

from module import name: What Actually Changes

from module import name does two things. It loads the module the same way import module would, and then it binds only the named attribute (not the module itself) into your scope. The second half is what makes the rest of the lesson clear.

A small example using the standard library:

Two things happened during that import. Python ran the math module's body and cached the module object in sys.modules. Then Python looked up the attribute sqrt on that module object and bound the name sqrt in the current file's scope.

The name math did not get bound. Calling math.pi right after that import raises NameError: name 'math' is not defined. The module is loaded and cached, but the only name your scope has is the one requested:

That's the core distinction from import math, which binds math (the whole module) and contents are reached through math.sqrt. Both forms run the module body. The difference is what ends up named in your scope.

The same rule holds for your own modules. Consider a pricing.py next to your main script:

Importing only cart_total:

In shop.py, the names pricing, TAX_RATE, and apply_discount are not bound. Only cart_total is. The module is fully loaded and visible in sys.modules, but the file only has the single name requested.

The diagram shows the four steps. The load and cache happen regardless of which import form is used. The difference comes in the binding step: a plain import binds the module name; from...import binds the requested attribute and leaves everything else in the module unreachable from your scope.

This matters when reading someone else's code. A cart_total(...) call deep in a function doesn't reveal where cart_total came from. With import pricing and pricing.cart_total(...), the source is in the call. Both styles are valid; the trade-off is between brevity and traceability.

Importing Multiple Names at Once

A single from statement can import multiple names, separated by commas:

All three names are bound in one statement. Python loads pricing once (or reuses the cache if it's already loaded) and looks up each attribute in turn.

When the list gets long, wrap it in parentheses so it can span multiple lines:

The parentheses are pure syntax. They aren't a tuple, and they don't change behavior. They let the statement break across lines without a backslash continuation. This style is common once the import list gets past about three names, because it's easier to read and produces cleaner diffs when imports get added or removed.

Formatters like black and ruff format reflow imports into this style automatically. isort and ruff's import sorter sort the names alphabetically inside the parentheses. None of this is required by Python, but it appears in most maintained projects.

Importing five names from one module is no more expensive than importing one. The module body runs once on first import; the rest is attribute lookups, which are cheap. Trim imports for clarity, not performance.

Renaming on Import with as

The as keyword renames the binding at import time. The original name isn't bound; only the alias is.

A common convention is in data libraries:

import numpy as np loads numpy and binds it under the name np. The name numpy itself isn't bound, so calling numpy.mean raises NameError. This alias is a widely followed convention; matching it makes the code familiar to other readers.

as works the same way inside from...import. Each name in the list can have its own alias:

Two reasons to do this in code: the original name is awkwardly long, or it clashes with something else in your scope. The clash case is the more common one. Consider a file that already defines a function called apply_discount with its own coupon-code logic, and also wants the simpler percentage version from pricing.py:

Without the alias, the import would clobber the local apply_discount (or the other way around, depending on order). The alias keeps both names alive: the local apply_discount and the imported apply_pricing_discount it delegates to.

Aliasing also helps when importing the same name from two different modules and keeping them distinct:

Both modules call their function total, a reasonable name inside each module. The aliases let the importer keep both around without conflict.

from module import *: The Star Import

A fourth form, from module import *, pulls every public name from the module into your scope at once.

At first glance, this looks like a shortcut. Listing names is skipped; everything is available. In practice, star imports cause problems in larger codebases, and PEP 8 discourages them.

Three things go wrong with star imports.

Problem 1: The source of names is hidden. A reader who sees cos(0) halfway through a 300-line file can't tell whether cos came from math, from a third-party library, or from a local function. With import math and math.cos(0), the source is in the call.

Problem 2: Shadowing without warning. Two import * statements can clobber each other without any warning:

Both math and cmath define sqrt. The second star import replaced math.sqrt with cmath.sqrt. Code that wrote sqrt(-1) expecting the math version to raise (which it does for negative input) now gets the complex-number version instead. The bug is invisible because there's no error and no warning.

Problem 3: Tools struggle. Linters, type checkers, and IDEs have a harder time analyzing files that use import *. They can't always tell which names are defined, which makes "undefined name" warnings unreliable and code completion noisier than it should be.

For these reasons, treat from module import * as a smell. It's tolerable in interactive REPL sessions and throwaway scripts. Any file that will be read again should use named imports.

One place star imports are common: at the top of a package's __init__.py, where the author has deliberately curated what to re-export. For application code, prefer explicit names.

Beyond style, import * can introduce bugs as a codebase grows. A new module added later might export a name that shadows something the code depended on. Explicit imports make that impossible.

Controlling import * with __all__

A module author can influence what a star import pulls in even if star imports are discouraged. The hook is __all__: a list of strings defined at module level that controls which names import * exports.

Without __all__, import * pulls every name in the module that doesn't start with an underscore. With __all__, it pulls only the names listed there, regardless of underscores.

INTERNAL_CONSTANT doesn't start with an underscore (so the default rule would normally export it), but it's not in __all__, so the star import skips it. _internal_helper would be excluded either way: it starts with an underscore.

__all__ is the closest Python comes to a "this is the public API" declaration. Even when no one uses import * against the module, defining __all__ documents intent. Linters and type checkers read it to know which names are public. Documentation generators use it to decide what shows up in the rendered API reference.

A rule of thumb: a module that will be imported by other code should define __all__. List the names that are part of the public API. Anything not in the list is "internal" by convention, and callers that use it have no guarantee across refactors.

__all__ is a regular list. Python doesn't enforce anything about its contents at import time; misspelling a name inside __all__ doesn't raise an error until something tries import *. Some linters catch the typo, which is one more reason to run a linter.

Relative Imports: from . import x and from .. import y

Everything above used absolute imports, which spell out the full module name from the top of the package tree (from shop.pricing import apply_discount). Inside a package, there's a second option: relative imports, which reference modules by their position relative to the current file.

A relative import starts with one or more dots. A single dot means "the current package." Two dots mean "the parent package." Three dots mean "grandparent," and so on.

Consider this package layout:

Inside shop/cart/checkout.py, the current package is shop.cart. So:

The single dot in from .items import CartItem resolves to shop.cart.items because that's "items inside the current package, which is shop.cart." The two dots in from ..pricing import apply_discount walk up one level to shop and look at pricing there.

The dashed arrows show what each relative import resolves to. .items stays inside cart/. ..pricing walks up to shop/ and finds pricing.py there.

The appeal of relative imports is rename-resilience. Renaming the top-level shop package to ecommerce means every absolute import from shop.something import x has to change. The relative imports inside the package keep working, because they reference structure, not names.

One limitation: relative imports only work inside packages. Running a file directly as a script (python checkout.py) leaves Python without a "current package," so the relative import fails:

The fix is either to use absolute imports or to run the file as a module from the project root: python -m shop.cart.checkout. The -m flag tells Python to treat this as a module being imported from the top of the package tree, which is the context relative imports need.

PEP 8 recommends absolute imports as the default, with relative imports acceptable for sibling imports inside a package when they shorten the line meaningfully. Avoid going more than one level up (... or ....) because the result becomes hard to read and usually signals a layout problem.

StyleExampleWhen to use
Absolutefrom shop.cart.items import CartItemClearest for one-off imports, always unambiguous, works in scripts
Relativefrom .items import CartItemSibling imports inside a package, especially when the top-level name might change

Pick one style per project and stick with it. Mixing the two heavily in one file is harder to read than either alone.

Circular Imports

Two modules importing from each other is a common import problem in larger codebases. Module A imports from B, and B (during its own loading) imports from A. At the moment B runs, A is only partially loaded, so some of A's names don't exist yet, and the import fails.

A minimal reproduction:

Running python cart.py:

Read the traceback in order: cart.py started loading, hit from pricing import apply_discount on line 1, which triggered pricing.py to start loading, which hit from cart import calculate_total on its own line 1. At that moment, cart was registered in sys.modules but only partially executed. The calculate_total function hadn't been defined yet. The from cart import calculate_total line found the half-loaded module and couldn't find the name.

The diagram shows the loop. cart is mid-load when pricing starts loading; pricing then tries to reach into cart for a name that hasn't been defined yet.

There are three ways out, in order of preference.

Fix 1: Restructure. Circular imports usually point to a design issue. If cart and pricing depend on each other, there's a third concept hiding in there that should live in its own module. Pull the shared piece out:

Now cart depends on discounts, and pricing depends on both. Neither cart nor pricing depends on the other. The cycle is gone.

Fix 2: Use `import module` instead of `from module import name`. A plain import works even when the target module is partially loaded, because the module object is already in sys.modules and no names on it are accessed at import time. Access happens later, after both modules have finished loading.

At import time, neither file tries to read attributes from the other. The lookups happen inside function bodies, which run after both modules are fully loaded. The cycle still exists in the dependency graph, but Python tolerates it now because it doesn't require partially loaded names.

Fix 3: Move the import inside the function. When restructuring isn't quick and the module-form fix doesn't fit, the last resort is to move the import line inside the function that needs it.

By the time calculate_total is called, both modules have finished initializing, so the import succeeds. The trade-off is a small per-call cost (a dict lookup in sys.modules) and a less obvious dependency graph. For occasional use, it's fine. For a hot path, prefer fix 1 or 2.

Lazy imports inside functions hide circular-import problems instead of solving them. They run a sys.modules lookup on every call, which is cheap but not free. They also obscure the file's real dependencies, which makes the code harder to reason about. Frequent use of this fix usually means the layout is the real problem.

Best Practices

A short list of habits that prevent most import-related pain.

Put imports at the top of the file. After the module docstring and from __future__ imports, before any module-level code. A reader scanning the top of a file should see every external dependency in one glance. The exceptions (lazy imports inside functions, conditional imports for platform-specific code) are rare enough to call out with a comment.

Group imports into three sections, in order: standard library, third-party, local. Separate each group with a blank line. Within each group, sort alphabetically. Tools like isort and ruff do this automatically.

Prefer `import module` over `from module import name` when readability tips that way. The qualified form (module.name) makes the source obvious at the call site. The from form makes the call site shorter. Pick the form that reads better in context. Most projects mix the two: import for things used once or twice (import math, then math.sqrt in one place), from for things used many times (from typing import List, Optional, Dict).

**Avoid from module import * outside of __init__.py.** PEP 8 discourages it, linters complain about it, and it makes code harder to read and refactor. The one exception is package __init__.py files where the package author has deliberately curated re-exports.

Use `as` aliases sparingly. Two situations call for them: community conventions (import numpy as np, import pandas as pd) and resolving conflicts. Don't alias to make names shorter; the cost is paid by future readers who have to figure out what pd is.

Define `__all__` in modules that will be imported by other code. __all__ documents intent and helps tools distinguish public from internal names.

Prefer absolute imports. Use relative imports only for sibling imports inside the same package, and never go more than one level up. An import like from ...subpackage.module import x usually means the project layout is wrong.

Treat circular imports as a design signal, not a bug to patch. Lazy imports and import module tricks can paper over a cycle, but the cycle itself usually means two modules are entangled in ways they shouldn't be. Refactoring is the real fix; the patches are stopgaps.

Quiz

from...import Quiz

10 quizzes