inspect.getmembers_static: Inspect Attributes Safely

Published on: August 30, 2026
Reading time: 2 minutes
Close-up view of a computer screen displaying code in a software development environment.

inspect.getmembers_static() lists attributes without using normal dynamic resolution. Unlike inspect.getmembers(), it avoids invoking many descriptors, properties, and custom __getattr__ or __getattribute__ paths. This makes it useful for documentation tools, debuggers, class analyzers, and API auditing.

The trade-off is that results may contain raw descriptor objects instead of computed values, and attributes created only at runtime may be absent.

Basic example

import inspect

class Example:
    @property
    def value(self):
        print("property executed")
        return 42

obj = Example()
print(inspect.getmembers_static(obj))

The property appears as a descriptor without executing its getter.

Difference from getmembers

inspect.getmembers(obj) performs normal attribute access and may execute arbitrary code. A property can open files, access a network, raise exceptions, or change state.

Filtering with predicate

members = inspect.getmembers_static(
    Example,
    predicate=inspect.isfunction,
)

The predicate receives each static value. Because descriptors are not bound, values can differ from normal attribute access.

Raw descriptors

Static inspection can return property, staticmethod, classmethod, and custom descriptor objects. This is useful when a tool needs the definition rather than the computed result.

for name, value in inspect.getmembers_static(Example):
    if isinstance(value, property):
        print(name, value.fget)

Inheritance and origin

To identify where an attribute was defined, walk the class MRO and inspect each class dictionary.

for cls in Example.__mro__:
    if "value" in vars(cls):
        print("defined on", cls)

Dynamic attributes may be missing

class Dynamic:
    def __getattr__(self, name):
        if name.startswith("field_"):
            return name.upper()
        raise AttributeError(name)

Those names are synthesized rather than stored, so static inspection does not discover them. That is expected.

Not a security sandbox

The function reduces accidental descriptor execution, but introspection is not isolation. Do not import untrusted modules or deserialize unsafe objects merely to analyze them.

Documentation generation

Documentation tools can collect descriptors, docstrings, and definitions statically, then explicitly resolve only trusted members.

Auditing properties

def list_properties(cls):
    return {
        name: value
        for name, value in inspect.getmembers_static(cls)
        if isinstance(value, property)
    }

staticmethod and classmethod

Normal access binds methods. Static inspection may return the wrapper object. Use __func__ when the original function must be analyzed.

Metaclasses

Metaclasses can synthesize attributes. Static inspection separates stored definitions from runtime behavior. This complements the internal guide to DynamicClassAttribute.

Comparing results

normal = {name for name, _ in inspect.getmembers(obj)}
static = {name for name, _ in inspect.getmembers_static(obj)}
print(normal - static)

The difference may reveal dynamic members. Run normal lookup only when its side effects are acceptable.

Common mistakes

  • Expecting computed property values.
  • Treating a raw staticmethod as a bound function.
  • Concluding that a dynamic attribute does not exist.
  • Calling normal inspection on unknown objects first.
  • Treating introspection as a security boundary.

Start with static inspection, recognize descriptor types explicitly, walk the MRO when origin matters, and resolve dynamic values only for trusted members. See the internal guides to inspect and inspect.signature.

Conclusion

inspect.getmembers_static exposes object structure while avoiding much dynamic execution. It is especially valuable for documentation, auditing, and descriptor analysis.

External sources

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Detailed close-up of yellow and white albino python scales, capturing texture and pattern.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    DynamicClassAttribute: Descriptors and Dynamic Access

    Understand Python DynamicClassAttribute, descriptors, class versus instance access, metaclasses, Enum behavior, and safe introspection.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Close-up of vibrant JavaScript code featuring functions and syntax highlighting.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python UserList: Custom Sequences

    Learn Python UserList for custom mutable sequences with validation, normalization, mutation rules, copying, and predictable APIs.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python UserDict: Custom Mappings

    Learn Python UserDict for custom mappings with validation, normalization, composition, copying, and predictable mutation behavior.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Detailed close-up of yellow and white albino python scales, capturing texture and pattern.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    itertools.accumulate: Running Sums and State

    Learn Python itertools.accumulate for running sums, balances, records, custom state transitions, and lazy data pipelines.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    itertools.groupby: Group Sorted Data Correctly

    Learn Python itertools.groupby for ordered data, streaming aggregation, shared iterators, object keys, and correct grouping behavior.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Close-up of hands typing on a laptop keyboard, Python book in sight, coding in progress.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    contextlib.chdir: Risks of Changing Directories

    Learn Python contextlib.chdir, its global-state and concurrency risks, and when pathlib or subprocess cwd is the safer design.

    Ler mais

    Tempo de leitura: 3 minutos
    30/08/2026