Published on

The Python `dir()` Function

Table of Contents

the dir() Function

In Python, the dir() function is a built-in function that returns a list of names in the current local scope or the names of an object's attributes. Here's the general syntax:

dir([object])

If object is not provided, dir() returns the names in the current local scope. If an object is passed as an argument, dir() returns the names of the object's attributes and methods.

Here's an example of using the dir() function:

# Example 1: Names in current local scope
print(dir())

# Example 2: Names of an object's attributes
my_list = [1, 2, 3]
print(dir(my_list))

In the first example, dir() is called without any arguments, so it returns the names in the current local scope. It will include the names of variables, functions, classes, and other objects defined in the current scope.

In the second example, dir(my_list) returns the names of attributes and methods of the my_list object. These may include methods like append(), remove(), or attributes like count, index, and so on, that are available for list objects.

Note that dir() returns a list of strings, and it may include some built-in names or names defined by imported modules, depending on the context in which it is called.

Practical Use Cases

1. Exploring New Libraries

When working with unfamiliar libraries or modules, dir() is invaluable for discovery:

import pandas as pd

# Discover available methods and attributes
print(dir(pd))

# Explore DataFrame methods
df = pd.DataFrame({'A': [1, 2, 3]})
methods = [method for method in dir(df) if not method.startswith('_')]
print(methods)

2. Debugging and Introspection

Use dir() during debugging to understand what's available on an object:

class DataProcessor:
    def __init__(self):
        self.data = []
        self.processed = False

    def process(self):
        self.processed = True

processor = DataProcessor()
print(dir(processor))
# Output includes: 'data', 'process', 'processed', and inherited methods

3. Interactive Development

In interactive Python sessions (REPL or Jupyter), dir() helps you quickly recall method names:

# Quick check of string methods
text = "hello"
string_methods = [m for m in dir(text) if not m.startswith('_')]
print(string_methods)
# ['capitalize', 'casefold', 'center', 'count', 'encode', ...]

Advanced Usage

Filtering Results

Filter dir() output to show only public attributes:

def get_public_attributes(obj):
    """Get all public attributes and methods of an object."""
    return [attr for attr in dir(obj) if not attr.startswith('_')]

my_list = [1, 2, 3]
public_attrs = get_public_attributes(my_list)
print(public_attrs)
# ['append', 'clear', 'copy', 'count', 'extend', 'index', ...]

Combining with type() and help()

import numpy as np

# Discover what numpy offers
print(f"NumPy version: {np.__version__}")
print(f"NumPy type: {type(np)}")

# Get specific function info
functions = [name for name in dir(np) if callable(getattr(np, name))]
print(f"NumPy has {len(functions)} callable functions")

# Use help() for detailed info on specific items
help(np.array)

Inspecting Custom Classes

class Vehicle:
    wheels = 4

    def __init__(self, brand):
        self.brand = brand
        self._private = "private data"

    def drive(self):
        return f"{self.brand} is driving"

car = Vehicle("Toyota")
print(dir(car))

# Separate class attributes from instance attributes
class_attrs = dir(Vehicle)
instance_attrs = dir(car)
unique_to_instance = set(instance_attrs) - set(class_attrs)
print(f"Instance-specific attributes: {unique_to_instance}")

dir() vs vars()

class Example:
    class_var = "I'm a class variable"

    def __init__(self):
        self.instance_var = "I'm an instance variable"

obj = Example()

# dir() shows all attributes including inherited and magic methods
print("dir():", len(dir(obj)))  # ~35+ items

# vars() shows only instance dictionary
print("vars():", vars(obj))     # {'instance_var': "I'm an instance variable"}

dir() vs help()

# dir() - Quick list of what's available
print(dir(dict))

# help() - Detailed documentation
help(dict.keys)  # Shows full docstring and usage

dir() vs type()

value = 42

# type() tells you what it is
print(type(value))  # <class 'int'>

# dir() tells you what it can do
print(dir(value))   # ['__abs__', '__add__', 'bit_length', ...]

Common Patterns and Best Practices

1. Autocomplete Helper

def show_methods(obj, pattern=""):
    """Show methods matching a pattern."""
    methods = [m for m in dir(obj) if pattern.lower() in m.lower()]
    return methods

# Find all methods containing 'append'
my_list = []
print(show_methods(my_list, "append"))  # ['append']

# Find all string formatting methods
print(show_methods("", "format"))  # ['format', 'format_map']

2. Documenting Your Classes

class APIClient:
    """Example API client with various methods."""

    def get(self): pass
    def post(self): pass
    def delete(self): pass

    @staticmethod
    def available_methods():
        """Return list of available API methods."""
        return [m for m in dir(APIClient)
                if not m.startswith('_') and callable(getattr(APIClient, m))]

print(APIClient.available_methods())

3. Dynamic Attribute Access

class Config:
    debug = True
    timeout = 30
    retries = 3

config = Config()

# List all configuration options
config_options = [attr for attr in dir(config)
                 if not attr.startswith('_') and not callable(getattr(config, attr))]

print("Configuration options:")
for option in config_options:
    value = getattr(config, option)
    print(f"  {option}: {value}")

Performance Considerations

The dir() function is relatively lightweight, but keep in mind:

import timeit

# Calling dir() repeatedly
setup = "obj = list(range(100))"

# Measure performance
time = timeit.timeit('dir(obj)', setup=setup, number=10000)
print(f"Time for 10,000 calls: {time:.4f} seconds")

# Tip: Cache results if calling repeatedly in loops
cached_methods = dir([])
# Use cached_methods instead of calling dir() again

Troubleshooting Common Issues

Issue 1: Too Much Output

# Problem: dir() returns too many items including magic methods
obj = "hello"
print(len(dir(obj)))  # 78 items!

# Solution: Filter out magic methods
public_only = [attr for attr in dir(obj) if not attr.startswith('_')]
print(len(public_only))  # 44 items

Issue 2: Understanding Inherited Attributes

class Parent:
    parent_method = "from parent"

class Child(Parent):
    child_method = "from child"

child = Child()

# All attributes including inherited
all_attrs = dir(child)

# Only child-specific
child_specific = set(dir(child)) - set(dir(Parent))
print(f"Child-specific: {child_specific}")

Issue 3: Dynamic Attributes

class DynamicClass:
    def __getattr__(self, name):
        return f"Dynamic: {name}"

obj = DynamicClass()

# dir() won't show dynamically created attributes
print(dir(obj))  # Doesn't show dynamic attributes

# They're still accessible
print(obj.anything)  # "Dynamic: anything"

When NOT to Use dir()

While dir() is useful, it's not always the right tool:

  1. For Documentation: Use help() instead for detailed information
  2. For Type Checking: Use isinstance() or type()
  3. For Attribute Checking: Use hasattr() for specific attribute existence
  4. For Production Code: Don't rely on dir() for critical logic; use explicit attribute access
# Bad: Using dir() to check for attribute
if 'append' in dir(my_list):
    my_list.append(value)

# Good: Use hasattr() instead
if hasattr(my_list, 'append'):
    my_list.append(value)

# Better: Just use try/except or duck typing
try:
    my_list.append(value)
except AttributeError:
    print("Object doesn't support append")

Conclusion

The dir() function is an essential tool for Python developers, especially when:

  • Learning new libraries and APIs
  • Debugging unfamiliar code
  • Working interactively in REPL or Jupyter notebooks
  • Exploring object capabilities dynamically

Combined with help(), type(), and vars(), dir() forms part of Python's powerful introspection toolkit that makes the language approachable and explorable.

Related Articles

Python Cheat Sheet

Awesome Python frameworks. A curated list of awesome Python frameworks, libraries, software and resources.

PyTorch for Python

PyTorch is a popular open-source library primarily used for deep learning applications but also offers versatility in general machine learning areas.