skip to content

What do __name__, __file__ and __path__ hold on an imported Python package?

level: middleimportance: nice to knowfreq 20%

answer

  1. Three attributes describing where a module came from
  2. One of them only packages have
  3. The dotted name, not the last segment
  4. A package points at its __init__.py
  5. __spec__ carries the same facts

basics

~20 s

name is the module's full dotted import name; file is the file it was loaded from, which for a regular package is its init.py rather than the directory; path is the submodule search list only packages have.

solid answer

~40 s

For a package imported as `pkg.sub`, `__name__` is the full dotted name `'pkg.sub'`, not the last segment. `__file__` is the source the loader executed, so for a regular package it is `.../pkg/__init__.py`; the directory itself is in `__path__`, which is the list the import system searches when resolving submodules and is present only on packages. Two attributes are not guaranteed: `__file__` is absent on built-in modules and on implicit namespace packages, so code must not assume it. The reliable modern source for all of this is `__spec__`, an `importlib.machinery.ModuleSpec` carrying `name`, `origin`, `parent` and `submodule_search_locations` — use it when you need the parent package name or want to test whether something is a package.

code

python · 8 lines
python
import json
import json.decoder

print(json.__name__, json.decoder.__name__)          # json json.decoder
print(json.__file__.endswith("__init__.py"))         # True
print(hasattr(json.decoder, "__path__"))             # False: a plain module
print(json.__spec__.parent, json.decoder.__spec__.parent)   # json json
print(json.decoder.__spec__.submodule_search_locations)     # None

go deeper

for a junior

Recall the three: name is the module's import name, file is the file it was loaded from, and path appears only on packages. Knowing name from the main-guard idiom is a fine starting point.

for a middle

Explain why a package's file names its init.py rather than the directory, that path is the submodule search list, and that both spec and path let you test whether something is a package.

for a senior

Demonstrate the caution: these attributes are not universally present, so resource lookup built on file breaks for namespace packages, frozen builds and archives. Prefer spec and a proper resource reader.

for a principal

Own the convention for locating package data and configuration across services, so that nothing in the codebase assumes an unpacked filesystem layout that a frozen or archived deployment will not provide.

## What each attribute means Every module object created by the import system carries a small set of attributes describing where it came from. **`__name__`** is the module's fully qualified dotted name, as it appears as a key in `sys.modules`. For `json.decoder` it is `'json.decoder'`, not `'decoder'`. The one famous exception is the module the interpreter runs as the entry point, whose `__name__` is `'__main__'` regardless of the file it lives in — which is what the main-guard idiom keys off. **`__file__`** is the path of the file the loader executed. For a plain module it is the `.py` (or the compiled extension) itself. For a regular package it is that package's `__init__.py`, because that file *is* the package body. This is the single most common surprise here: `pkg.__file__` never names the directory, so code that wants the package directory must take the parent of that path. `__file__` is also not guaranteed to exist — modules compiled into the interpreter have none, and neither do implicit namespace packages, since there is no file to point at. Treat it as optional. **`__path__`** exists only on packages, and its presence is the definition of one. It is a list (technically, a sequence the import system iterates) of directories searched when resolving a submodule of that package. For a regular package it contains exactly the package directory. It is also mutable at runtime, which is what plugin systems exploit — append a directory and submodules found there become importable under the package's name. ## The spec is the authoritative record Since the import machinery was reworked around module specs, each module also carries `__spec__`, an `importlib.machinery.ModuleSpec`. It is the same information in one place and is the form to prefer when writing code that introspects modules: - `__spec__.name` — the full dotted name, matching `__name__`. - `__spec__.origin` — where the module came from; a path for file-based modules, the string `'built-in'` for modules compiled into the interpreter, `'frozen'` for frozen ones. - `__spec__.parent` — the enclosing package's name (a package's own name for a package, the parent's name for a submodule, and an empty string for a top-level module). - `__spec__.submodule_search_locations` — `None` for a plain module, otherwise the search path, which is what `__path__` is set from. So the robust runtime test for "is this a package?" is `mod.__spec__.submodule_search_locations is not None`, with `hasattr(mod, "__path__")` as the older equivalent. The unrobust test is looking for `__init__.py` on disk, which is wrong for namespace packages, and looking at the name, which tells you nothing. ## Where this shows up in real code Two places, mostly. The first is code that wants to locate something next to itself and reaches for `__file__` — correct only if you take the directory of that path and only if the module is file-based at all, which fails the moment the code is loaded from an archive or a frozen build. The second is logging and diagnostics: `__name__` is the conventional argument when getting a logger, precisely because it is the full dotted name, so the logger hierarchy mirrors the package hierarchy for free and configuration can be applied per subtree. ## The trap to name out loud If you are asked this, the point to volunteer is that these attributes are *not* uniformly present. `__file__` is missing on built-ins and namespace packages; `__path__` is missing on every plain module by design. Any code that reads them without a guard has a failure mode on some legitimate import. Reading `__spec__` instead is both more complete and more honest about what it does not know.

  • How would you get the directory a package lives in, given only the package object?
    Take the parent of `__file__` — `pathlib.Path(pkg.__file__).parent` — since `__file__` names the `__init__.py`, not the directory. Guard it: `__file__` is absent on namespace packages and built-ins, and for anything loaded from an archive there is no real directory at all, so a reader for package data is the more robust tool.
  • Why is `__name__` the conventional argument when creating a logger?
    Because it is the module's full dotted name, so the logger names mirror the package hierarchy exactly. Configuration can then be applied to a whole subtree by naming the package, and every log record identifies the module it came from without anyone writing a string by hand.
  • What is the most robust runtime check that an imported object is a package?
    `mod.__spec__.submodule_search_locations is not None`, or the older `hasattr(mod, "__path__")`. Both hold for namespace packages as well as regular ones. Checking for an `__init__.py` on disk is wrong for namespace packages, and inspecting the dotted name tells you nothing at all.

saying these in an interview costs you the question

  • Says a package's __file__ is the package directory
  • Assumes every module object has a __file__
  • Thinks __name__ is only the last dotted segment
  • Believes plain modules have a __path__ too
  • Detects a package by looking for __init__.py on disk

context