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

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']


print(dir(Dummy()))
# ['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):
        print(self.color)

    def print_speed(self):
        print(self.speed)


porsche = Car('red', 110)
print(dir(porsche))
print(porsche.__dir__())

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
Syntax: 
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!

To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And 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?

Practice projects is how you sharpen your saw in coding!

Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?

Then become 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.

Join my free webinar “How to Build Your High-Income Skill Python” and watch how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!