Get all object attributes in Python?
Categories:
Mastering Python Object Introspection: How to Get All Attributes
Dive deep into Python's introspection capabilities to programmatically discover all attributes of an object, including methods, properties, and hidden members. Learn practical techniques using built-in functions and the inspect
module.
Understanding how to retrieve all attributes of an object in Python is a fundamental skill for debugging, dynamic programming, and framework development. Python's dynamic nature allows objects to have attributes added and removed at runtime, making introspection a powerful tool. This article explores various methods to list an object's attributes, differentiating between callable and non-callable members, and understanding the nuances of special attributes.
Basic Introspection with dir()
The simplest way to get a list of attributes for an object is using the built-in dir()
function. When called without arguments, dir()
returns the names in the current scope. When given an object, it attempts to return a list of valid attributes for that object.
class MyClass:
def __init__(self, name):
self.name = name
self._private_attr = 10
def greet(self):
return f"Hello, {self.name}"
@property
def upper_name(self):
return self.name.upper()
obj = MyClass("Alice")
print(dir(obj))
Output of dir(obj)
will include name
, _private_attr
, greet
, upper_name
, and many special methods.
While dir()
is convenient, its output includes many "special" or "dunder" methods (e.g., __init__
, __str__
) that are often not what you're looking for when trying to inspect user-defined attributes. To filter these out, you typically apply string-based filtering.
Filtering Attributes for User-Defined Members
To get a cleaner list of attributes, excluding the special methods, you can iterate through the dir()
output and filter out names that start and end with double underscores (__
). You might also want to differentiate between methods (callable attributes) and data attributes (non-callable attributes).
class MyClass:
def __init__(self, name):
self.name = name
self._private_attr = 10
def greet(self):
return f"Hello, {self.name}"
@property
def upper_name(self):
return self.name.upper()
obj = MyClass("Alice")
all_attrs = dir(obj)
user_attrs = [attr for attr in all_attrs if not attr.startswith('__')]
print("\nUser-defined attributes:", user_attrs)
print("\nCallable attributes (methods):")
for attr_name in user_attrs:
attr_value = getattr(obj, attr_name)
if callable(attr_value):
print(f" - {attr_name}")
print("\nNon-callable attributes (data/properties):")
for attr_name in user_attrs:
attr_value = getattr(obj, attr_name)
if not callable(attr_value):
print(f" - {attr_name}")
Filtering dir()
output and using callable()
to distinguish methods from data.
getattr(obj, attr_name)
function is crucial for safely retrieving the actual attribute value from its name. It's the programmatic equivalent of obj.attr_name
.Advanced Introspection with the inspect
Module
For more sophisticated introspection, Python's inspect
module is invaluable. It provides functions to examine live objects, including modules, classes, methods, functions, tracebacks, frame objects, and code objects. Specifically, inspect.getmembers()
is highly versatile.
import inspect
class MyClass:
def __init__(self, name):
self.name = name
self._private_attr = 10
def greet(self):
return f"Hello, {self.name}"
@property
def upper_name(self):
return self.name.upper()
obj = MyClass("Alice")
print("\nAll members using inspect.getmembers():")
for name, value in inspect.getmembers(obj):
print(f" - {name}: {type(value)}")
print("\nOnly methods using inspect.ismethod():")
for name, value in inspect.getmembers(obj, inspect.ismethod):
print(f" - {name}")
print("\nOnly data attributes using inspect.isroutine (inverted):")
for name, value in inspect.getmembers(obj, lambda member: not inspect.isroutine(member) and not name.startswith('__')):
print(f" - {name}: {value}")
Using inspect.getmembers()
with various predicates for fine-grained control.
The inspect.getmembers()
function takes an optional second argument, a predicate function, which is used to filter the members. The inspect
module provides many useful predicates like inspect.isfunction
, inspect.ismethod
, inspect.isproperty
, inspect.ismodule
, inspect.isclass
, etc. This allows you to precisely target the types of attributes you're interested in.
Decision flow for choosing the right attribute retrieval method.
_
) or dunder attributes (__attr__
) directly, as they are part of an object's internal implementation and might change in future versions.Choosing the right method depends on your specific needs. For a quick overview, dir()
is sufficient. For filtering out special attributes and distinguishing between callable and non-callable members, a loop with getattr()
and callable()
is effective. For precise control over attribute types, the inspect
module is the most powerful tool.