How Python's help() Reads Object Documentation
Python's built-in help() function is an interactive
wrapper around the standard library's pydoc module,
designed to dynamically inspect objects and render human-readable
documentation directly in the console at runtime. By introspecting an
object's attributes, signature, class hierarchy, and docstrings,
help() constructs a comprehensive reference manual on the
fly. This article examines the exact runtime mechanics
help() uses to extract, format, and present metadata from
arbitrary Python objects.
The Underlying Engine:
pydoc
When invoked, help() delegates execution to an instance
of pydoc.Helper. Instead of parsing raw .py
source files from disk, pydoc primarily interacts with live
objects already loaded into memory. It dynamically queries the object
using standard Python introspection protocols, resolving its type,
module origin, and structural layout.
Extraction of __doc__
The most direct interaction occurs with the __doc__
attribute. When a function, class, or module defines a docstring, the
Python compiler binds that string literal to the object's
__doc__ attribute. At runtime, pydoc reads
this attribute:
- Modules: Reads the module-level
__doc__string and enumerates public members listed in__all__(or all non-underscored attributes if__all__is absent). - Functions: Reads the function's
__doc__and combines it with runtime signature details. - Classes: Reads the class-level
__doc__, followed by the docstrings of its methods and properties.
If an object lacks a __doc__ attribute or it is set to
None, help() indicates that no documentation
is found, though it will still display structural information such as
method signatures.
Signature Resolution via Introspection
help() does not rely solely on docstrings to describe
callables. It leverages the inspect module to parse runtime
metadata from code objects:
- Parameters and Defaults: It reads
__code__.co_varnames,__defaults__, and__kwdefaults__to reconstruct argument lists. - Type Annotations: It inspects
__annotations__to display type hints alongside parameters and return values. - Built-in Functions and C Extensions: For C-based
built-ins (such as those in the
mathorsysmodules), Python inspects the internal__text_signature__attribute, often populated by Python's Argument Clinic, to reconstruct function headers even when bytecode is unavailable.
Traversing the Method Resolution Order (MRO)
When analyzing classes, help() inspects the class's
__mro__ (Method Resolution Order) attribute. This allows
the utility to:
- Differentiate between methods defined directly on the target class and those inherited from base classes.
- Group class members into logical sections: methods, static methods, class methods, properties, and inherited attributes.
- Fall back to base class docstrings if an overriding method does not
define its own
__doc__.
Descriptors and Dynamic Attributes
Because help() operates on live objects, it must access
class members carefully without executing unintended code. It accesses
attributes via inspect.getattr_static() rather than
standard getattr(). This prevents the evaluation of
properties, custom descriptors, or __getattr__ hooks during
documentation generation, ensuring that running help() does
not trigger unintended side effects.
Output Formatting and Paging
Once the metadata, docstrings, and signatures are assembled into
plain text, pydoc passes the string to a pager. In an
interactive terminal session on Unix-like platforms, it pipes output
through system pagers such as less or more. In
non-interactive environments or standard IDE consoles, it writes the
formatted documentation directly to sys.stdout.