dir() versus __dir__() – What’s the Difference?

Rate this post

Problem Formulation

What’s the difference between the built-in dir() function and __dir__ dunder method in Python?

Quick Answer

Python’s built-in function dir(object) returns a list of the object’s attribute names and method names. The dir() function is a wrapper around the __dir__() method because it internally calls the object’s dunder method object.__dir__(). But the two are different in functionality because dir() performs additional tasks on the output of object.__dir__() such as sorting the output list.

In the following minimal example, you overwrite an object’s dunder method __dir__(). When calling dir(), you see that the output is the same, but it is now sorted:

class Dummy:
    def __dir__(self):
        return ['bob', 'alice']

# ['alice', 'bob']

Instead of the list ['bob', 'alice'] you obtain the sorted list ['alice', 'bob'] so some further processing must have been done by the dir(Dummy()) method on the output of the Dummy().__dir__() method call.

In addition to the sorting, the dir() function also performs some housekeeping in case the __dir__() method is not defined by the class. Here‘s the relevant part from the documentation explaining this relationship:

“If the object does not provide __dir__(), the function tries its best to gather information from the object’s __dict__ attribute, if defined, and from its type object.

This means that the dir() function is a higher-level function that does some advanced processing on top of the __dir__() method, mainly for usability reasons. But if you have a large list of attribute names, you may not need to spend costly resources on sorting and should rely on the object.__dir__() method instead in performance-sensitive environments.

Car Example

In the following example, you see the default output of the dir() and __dir__() methods in a more practical context:

class Car:

    def __init__(self, color, speed):
        self.color = color
        self.speed = speed

    def accelerate(self):
        self.speed += 10

    def print_color(self):

    def print_speed(self):

porsche = Car('red', 110)

Here’s the output of this code snippet:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'accelerate', 'color', 'print_color', 'print_speed', 'speed']
['color', 'speed', '__module__', '__init__', 'accelerate', 'print_color', 'print_speed', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']

You can see that the default list of names is far greater—it contains all the names explicitly and implicitly defined for a given object. For example, the color and speed attributes are there (explicitly defined), and the __str__ and __lt__ functions are there too (implicitly defined for any custom object).

Let’s jump into some background on the dir() method—every advanced-level Python coder should get this! 🙂

Background dir()

If used without argument, Python’s built-in dir() function returns the function and variable names defined in the local scope—the namespace of your current module. If used with an object argument, dir(object) returns a list of attribute and method names defined in the object’s scope. Thus, dir() returns all names in a given scope.

Python dir() Visual Explanation
dir() -> names defined in the local scope/namespace.  
dir(object) -> names defined for the object. 
ArgumentsobjectThe object for which the names should be returned.
Return ValuelistReturns all names defined in the namespace of the specified object. If no object argument is given, it returns the names defined in the local namespace of the module in which you run the code.

You can also watch my explainer video to learn even more!

Where to Go From Here?

Enough theory. Let’s get some practice!

Coders get paid six figures and more because they can solve problems more effectively using machine intelligence and automation.

To become more successful in coding, solve more real problems for real people. That’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

You build high-value coding skills by working on practical coding projects!

Do you want to stop learning with toy projects and focus on practical code projects that earn you money and solve real problems for people?

🚀 If your answer is YES!, consider becoming a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

If you just want to learn about the freelancing opportunity, feel free to watch my free webinar “How to Build Your High-Income Skill Python” and learn how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!