Module Attributes
Every module carries built-in attributes — __name__, __file__, __doc__, and more — that describe the module itself and let code introspect where it came from and what it exposes.
A module isn't just a bag of the names you defined — Python automatically attaches several dunder (double-underscore) attributes to every module object, describing its identity, location, documentation, and public interface. These attributes are how tools, and your own code, can introspect a module rather than just use it.
__name__: The Module's Identity
Holds the module's name as a string — the dotted path used to import it, or "__main__" if the file is currently running as the top-level script. This is the attribute behind the main guard, covered in its own topic.
import json
print(json.__name__) # 'json'__file__: Where the Module Lives
Holds the filesystem path of the file the module was loaded from. Useful for locating resources (data files, templates) stored alongside a module's source.
Not every module has __file__ — built-in modules implemented in C (like sys itself) and some dynamically created modules don't have a corresponding source file, so this attribute may be absent. Check with hasattr or getattr(module, '__file__', None) before relying on it.
import json
print(json.__file__) # e.g. '/usr/lib/python3.12/json/__init__.py'__package__: Which Package It Belongs To
Holds the name of the package the module belongs to (empty string for a top-level module not inside any package, and the package's own name for an __init__.py). It's used internally to resolve relative imports.
import json
print(json.__package__) # 'json'
import json.decoder
print(json.decoder.__package__) # 'json'__spec__: The Full Import Specification
Holds a ModuleSpec object describing exactly how the module was found and should be loaded: its name, loader, origin (file path), submodule search locations, and whether it's a package. This is the structured data the import system itself builds and consults; most everyday code doesn't need to touch it, but tools and import hooks do.
import json
print(json.__spec__)
# ModuleSpec(name='json', loader=<...>, origin='/usr/lib/python3.12/json/__init__.py', submodule_search_locations=[...])__doc__: The Module's Docstring
Holds the module's docstring — a string literal placed as the very first statement in the file — or None if the file has none. This is the same mechanism used for function and class docstrings, applied at the module level.
"""Utilities for working with temperatures."""
def to_celsius(f: float) -> float:
return (f - 32) * 5 / 9import temperature
print(temperature.__doc__) # 'Utilities for working with temperatures.'
help(temperature) # also displays the docstring__all__: Declaring the Public API
An optional list of strings a module defines to control exactly which names from module import * exposes, and to signal (to humans and tools) which names are the intended public interface. Names not listed in __all__ are still accessible by explicit dotted access or explicit from-import — __all__ only affects the star-import form.
from textutil import * imports only shout and whisper. _internal_helper remains reachable as textutil._internal_helper, just not via the star import, and its leading underscore is a separate convention signaling it's not meant for external use.
# textutil.py
__all__ = ['shout', 'whisper']
def shout(s: str) -> str:
return s.upper() + '!'
def whisper(s: str) -> str:
return s.lower()
def _internal_helper(): # not in __all__, and leading underscore signals 'private'
passInspecting All Attributes at Once
dir(module) lists every name in a module's namespace, including its dunder attributes and everything you defined. vars(module) (equivalent to module.__dict__) returns the actual namespace as a dictionary.
import json
print([n for n in dir(json) if n.startswith('__')][:6])Key Takeaways
__name__ holds the module's import name, or "__main__" when run directly.
__file__ holds the source file path, but may be absent for built-in or dynamically created modules.
__package__ names the containing package, used internally for resolving relative imports.
__spec__ carries the full ModuleSpec built by the import system — name, loader, origin, and more.
__doc__ holds the module's docstring, the first string literal in the file.
__all__ controls what from module import * exposes and documents the intended public API.
path = json.__file__ # assumes __file__ always exists path = getattr(json, '__file__', None) if path is not None:...
Some modules (built-in C modules, some dynamically generated ones) have no __file__ attribute at all, so direct access can raise AttributeError.
__all__ = ['shout', 'Whisper'] # typo: actual function is 'whisper' __all__ = ['shout', 'whisper']
A name in __all__ that doesn't actually exist in the module causes from module import * to raise AttributeError at import time.
What does a module's __name__ attribute hold when the module is imported normally (not run directly)?
The module's own dotted import name, e.g. 'json' or 'mypackage.mymodule'.
Why might accessing module.__file__ raise an AttributeError for some modules?
Built-in modules implemented in C and some dynamically created modules have no corresponding source file, so they lack a __file__ attribute.
What does __package__ hold for a top-level module that isn't part of any package?
An empty string.
What is __spec__, and who mainly uses it?
A ModuleSpec object describing how the module was found and loaded (name, loader, origin, search locations); mainly used by the import system itself and by tools/import hooks, not everyday code.
What controls what from module import * actually imports?
The module's __all__ list, if defined; without __all__, star-import falls back to all names not starting with an underscore.
Does leaving a name out of __all__ prevent other code from importing it explicitly?
No — the name remains accessible via dotted access (module.name) or an explicit from module import name; __all__ only affects the star-import form.
Write a module shapes.py with functions circle_area and square_area, plus an internal helper _validate, using __all__ to expose only the two area functions to star imports.
With __all__ = ['circle_area', 'square_area'], from shapes import * brings in only those two names; _validate remains reachable as shapes._validate but is excluded from the star import.
What does this print?
It prints 'Small utility helpers.' (the module's docstring) and then 'util' (the module's name, since it was imported rather than run directly).
Explain why getattr(module, '__file__', None) is a safer way to find a module's source path than module.__file__ directly.
Because not every module object has a __file__ attribute (built-in and some dynamically created modules lack one); getattr with a default returns None gracefully instead of raising AttributeError when the attribute is missing.
# util.py
"""Small utility helpers."""
def double(x):
return x * 2
# main.py
import util
print(util.__doc__)
print(util.__name__)