Import Python File: A Practical Guide to Local Modules

Diagram showing one Python file importing a local module

Python loads a local file as a module when its directory is available on Python’s module search path. To load a local module, use its filename without the .py extension. A Python import of another Python file works the same way whether the file contains functions, classes, or constants.

The simplest setup keeps both files in one directory, then expands to packages when the project grows.

Import Python file from the same directory

Suppose a directory contains main.py and helpers.py. The module name is helpers, not helpers.py.

  • helpers.py: GREETING = “Hello” and def greet(name): return f”{GREETING}, {name}”.
  • main.py: import helpers, from helpers import greet, print(helpers.GREETING), and greet(“Mina”).

The statement import helpers imports the module and keeps its names under the helpers namespace. Use helpers.GREETING or helpers.greet() to access them. The statement from helpers import greet binds only greet in main.py, so you can call greet() directly.

Do not include the .py extension, and avoid filenames containing spaces, hyphens, or names that conflict with standard-library modules.

How to import another Python file selectively

Use from module import name when you need specific functions, classes, or constants:

  • from helpers import greet, GREETING imports two names.
  • from helpers import greet as say_hello assigns an alias.
  • import helpers as h shortens the module reference while retaining its namespace.

Selective imports make calls shorter, but they can make the source of a name less obvious. Use the module form when a file exposes many similarly named objects or when clarity matters. Python executes a module’s top-level code during its first import, then normally reuses the loaded module.

Import another Python file from a package

A package is a directory containing related modules. A predictable structure might look like this:

  • app/__init__.py
  • app/main.py
  • app/tools/__init__.py
  • app/tools/formatters.py

Inside app/main.py, an absolute import can be from app.tools.formatters import clean. A package-relative import can be from .tools.formatters import clean. The leading dot means “from this package”; two dots refer to the parent package, as in from ..shared import settings.

The parent directory of app must be on the search path for the absolute form to work. An __init__.py file makes package boundaries explicit and supports consistent behavior across tools, even though modern Python also supports namespace packages without one.

Fix module search paths, entry points, and circular imports

Python searches sys.path, which commonly includes the directory containing the launched script, the current directory for interactive or module execution, configured PYTHONPATH entries, the standard library, and installed packages. A ModuleNotFoundError usually means the module’s directory or the package’s parent is missing from that list.

  1. Run a package module from the project’s parent directory: python -m app.main. This gives relative imports the package context they require.
  2. Use if __name__ == “__main__”: to separate reusable definitions from script-only behavior. Put startup code in a main() function, then call it beneath the guard. Importing the file will define its functions without launching the script.
  3. Check spelling, capitalization, package names, and the directory from which the command runs. Also check that a local file is not shadowing a standard-library or installed module.

Running python app/main.py directly can break a relative import because Python treats the file as a standalone script rather than as part of app. Prefer python -m app.main or configure the project as an installed package. Arbitrary sys.path mutation may hide the underlying structure problem and should not be the default fix.

Circular imports occur when a.py imports b.py while b.py imports a.py. Typical symptoms include “cannot import name,” a “partially initialized module” message, or missing attributes during startup. Move shared functions or constants into a third module, make imports flow in one direction, or defer a genuinely optional import inside a function.