Python
special methods
dunder methods
magic methods
object-oriented programming

Why do some functions have underscores __ before and after the function name?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Python, names like __init__, __str__, and __len__ are special methods, often called dunder methods because they have double underscores before and after the name. They are not ordinary naming style choices. They are hooks into Python's object model that let your objects participate in built-in language behavior.

Why The Double Underscores Exist

Python needs a set of reserved method names with well-defined meaning. The double-underscore convention marks those names as interpreter-recognized protocol methods rather than normal application methods.

For example:

  • '__init__ controls instance initialization'
  • '__str__ controls user-facing string conversion'
  • '__repr__ controls developer-oriented representation'
  • '__len__ controls behavior of len(obj)'
  • '__getitem__ controls indexing such as obj[0]'

These names are special because Python itself looks for them when certain syntax or built-in functions are used.

Example: Object Initialization

A simple class with __init__ looks like this:

python
1class User:
2    def __init__(self, name):
3        self.name = name
4
5
6u = User("Ada")
7print(u.name)

When you write User("Ada"), Python creates an instance and then calls __init__ automatically. You do not call it directly in ordinary code.

Example: String Representation

Special methods also control how objects appear when printed.

python
1class User:
2    def __init__(self, name):
3        self.name = name
4
5    def __str__(self):
6        return f"User: {self.name}"
7
8    def __repr__(self):
9        return f"User(name={self.name!r})"
10
11
12u = User("Ada")
13print(str(u))
14print(repr(u))

This is why dunder methods matter. They let your class integrate naturally with the rest of the language.

Example: Operator Overloading

Python also uses special methods for operators.

python
1class Vector:
2    def __init__(self, x, y):
3        self.x = x
4        self.y = y
5
6    def __add__(self, other):
7        return Vector(self.x + other.x, self.y + other.y)
8
9    def __repr__(self):
10        return f"Vector({self.x}, {self.y})"
11
12
13v1 = Vector(1, 2)
14v2 = Vector(3, 4)
15print(v1 + v2)

The expression v1 + v2 works because Python translates it into a call that consults __add__.

These Are Protocol Methods, Not Just "Magic"

Calling them magic methods can make them sound mysterious, but they are better understood as protocol methods.

If your object implements the right methods, it can behave like:

  • a container
  • an iterable
  • a numeric value
  • a context manager
  • a callable object

For example, implementing __iter__ and __next__ lets an object work in a for loop. Implementing __enter__ and __exit__ lets it work in a with statement.

What About Leading Double Underscores Only

Do not confuse dunder methods with names like __hidden.

A name with leading double underscores but not trailing double underscores triggers name mangling inside classes. That is a different feature.

So these are different:

  • '__init__ is a special method name recognized by Python'
  • '__value is a name-mangled attribute, not a protocol method'

That distinction matters a lot for readability and correctness.

Should You Invent Your Own Dunder Names

No. You should not create arbitrary names like __myfeature__. Names of the form __name__ are conventionally reserved for Python's own protocols and special behavior.

If you need a normal helper method, give it a normal method name.

Common Pitfalls

A common mistake is assuming dunder methods are automatically called in all circumstances. For example, defining __str__ does not change repr(obj), and defining __len__ does not make the object iterable.

Another issue is confusing dunder methods with private naming. Double leading underscores without trailing underscores are about name mangling, not interpreter protocols.

Developers also sometimes call special methods directly in ordinary code even when the built-in syntax is clearer. Writing len(obj) is better than obj.__len__() unless you are debugging something specific.

Finally, do not invent your own dunder method names. Stick to the ones Python actually defines.

Summary

  • Names like __init__ and __str__ are special Python protocol methods.
  • They let your objects work naturally with built-in syntax and functions.
  • The double underscores mark reserved interpreter-recognized names.
  • Do not confuse dunder methods with name-mangled attributes such as __value.
  • Use the built-in language features that trigger these methods instead of calling them manually in normal code.

Course illustration
Course illustration

All Rights Reserved.