How to Inspect Python Objects and Get Attributes and Methods
Python's introspection capabilities allow you to examine objects at runtime, discovering their attributes (data) and methods (functions).
This guide explains how to get a list of an object's or class's attributes and methods using dir()
, vars()
, __dict__
, and the inspect
module. We'll also cover filtering the results to get exactly what you need.
Getting Attributes with __dict__
and vars()
(Instance Attributes)
Both __dict__
and vars()
provide access to an object's instance attributes (not class attributes or methods) as a dictionary:
class Person():
cls_id = 'employee' # Class attribute
def __init__(self, first, last, age):
self.first = first # Instance attributes
self.last = last
self.age = age
tom = Person('tom', 'nolan', 25)
# Using __dict__
print(tom.__dict__)
# Output: {'first': 'tom', 'last': 'nolan', 'age': 25}
# Using vars() - equivalent to __dict__ for instances
print(vars(tom))
# Output: {'first': 'tom', 'last': 'nolan', 'age': 25}
# Get a list of attribute names only:
attributes = list(tom.__dict__.keys()) # or list(vars(tom))
print(attributes) # Output: ['first', 'last', 'age']
__dict__
: Every object with dynamically assignable attributes has a__dict__
attribute. This is a dictionary where keys are attribute names (strings) and values are the corresponding attribute values.vars(object)
: For class instances,vars(object)
is equivalent toobject.__dict__
. It's slightly more general, as it can also be used with modules and classes (returning their__dict__
). Usevars()
for readability.- The difference between class attributes and instance attributes is that instance attributes are unique to the instance and can be modified on the object directly.
Getting All Attributes and Methods with dir()
The dir()
function is a more comprehensive tool. It returns a list of all valid attributes (including methods) for a given object, including inherited attributes:
class Person():
def __init__(self, first, last, age):
self.first = first
self.last = last
self.age = age
tom = Person('tom', 'nolan', 25)
print(dir(tom))
# Output (long list, including):
# ['__class__', '__delattr__', ..., 'age', 'first', 'last', ...]
dir(tom)
: Returns a list of strings, representing all attributes (instance variables, methods, class variables, inherited members) accessible on thetom
object. This includes the "magic" attributes/methods (starting and ending with double underscores) that are part of Python's object model.
Filtering dir()
Results
The raw output of dir()
is often too verbose. You usually want to filter it.
Excluding "Magic" Attributes (Double Underscore)
To exclude attributes that start and end with double underscores (dunder methods), use a list comprehension:
attributes = [attr for attr in dir(tom) if not attr.startswith('__')]
print(attributes) # Output: ['age', 'first', 'last']
Getting Only Methods
To get only the methods of an object, use callable()
in your filter:
class Employee():
cls_id = 'employee'
def __init__(self, name, salary):
self.name = name
self.salary = salary
def get_name(self):
return self.name
def get_salary(self):
return self.salary
emp1 = Employee('tom', 'nolan')
methods = [method for method in dir(emp1)
if not method.startswith('__')
and callable(getattr(emp1, method))
]
print(methods) # Output: ['get_name', 'get_salary']
callable(getattr(emp1, attribute))
: This is the key.getattr(emp1, attribute)
retrieves the attribute (which might be a method, a variable, etc.).callable()
then checks if that attribute is something you can call (like a function or method).- The
@classmethod
and@staticmethod
are also considered callable, so they are included in the output as well.
Getting Class Methods with inspect.getmembers()
import inspect
class Employee():
def __init__(self, name, salary):
self.salary = salary
self.name = name
def get_name(self):
return self.name
def get_salary(self):
return self.salary
# Get class methods
list_of_methods = inspect.getmembers(Employee, predicate=inspect.isfunction)
print(list_of_methods)
#Output: [('__init__', <function Employee.__init__ at 0x...>), ('get_name', <function Employee.get_name at 0x...>), ('get_salary', <function Employee.get_salary at 0x...>)]
# Get object methods
tom = Employee('tomolan', 100)
list_of_methods = inspect.getmembers(tom, predicate=inspect.ismethod)
print(list_of_methods)
#[('__init__', <bound method Employee.__init__ of <__main__.Employee object at 0x...>>),
# ('get_name', <bound method Employee.get_name of <__main__.Employee object at 0x...>>),
# ('get_salary', <bound method Employee.get_salary of <__main__.Employee object at 0x...>)]
inspect.getmembers(Employee, predicate=inspect.isfunction)
: This returns a list of(name, value)
tuples, wherename
is the name of the method andvalue
is the method itself. Thepredicate=inspect.isfunction
part filters the results, including only those members that are functions. If the argument is an instance of a class, useinspect.ismethod
instead ofinspect.isfunction
.- This approach is generally better than filtering the result of the dir, because it returns more information, like method value and name.