Python has a number of protocols that classes can opt into by implementing one or more “dunder methods”, aka double-underscore methods. Examples include
__call__ (make an object behave like a function) or
__iter__ (make an object iterable).
The choice of wrapping these functions with double-underscores on either side was really just a way of keeping the language simple. The Python creators didn’t want to steal perfectly good method names from you (such as “call” or “iter”), but they also did not want to introduce some new syntax just to declare certain methods “special”. The dunders achieve the dual goal of calling attention to these methods while also making them just the same as other plain methods in every aspect except naming convention.
Some people call these “magic methods”. Indeed one of the best guides online, A Guide to Python’s Magic Methods, uses this term. The reason I don’t like this term is that it makes it seem like dunders are only reserved for “real experts”, when quite the opposite is true. Indeed, nearly any new Python programmer uses
__init__ to implement object initializers (aka constructors). The double-underscores don’t mean “reserved for wizards”; they simply mean, “reserved by the core Python team”.
One somewhat perplexing trend is that a few library authors have chosen to use the dunder conventions for their own code. For example, in SQLAlchemy, you use
__tablename__ to map a SQLAlchemy ORM class to a SQL table. It then exposes new properties,
__mapper__. Ugh. For an otherwise beautifully designed library, this is so very wrong and completely misses the point. The dunder convention is a namespace reserved for the core Python team to implement their own protocols. Never use the namespace for your own, library-specific things! This defeats the whole purpose. If you need to hide a property, use
A recent video called “
__dunder__ functions” walks through and demystifies many of the dunder protocols. It’s worth a watch, especially for Python beginners.
Moving forward, here are the rules you should follow for dunders:
- Call them “dunders” — Terminology like “magic” makes them seem much more complicated than they actually are. For example, it’s the “dunder call method”, not the “double-underscore call double-underscore method” and not the “magic call method”.
- Implement dunders on your classes at will — There is nothing magic about them, you shouldn’t feel like you’re using an esoteric language feature when you implement the
__call__method. Because, you’re not! It’s a standard language feature just like
- Never, ever, invent your own dunders — Python leaves you with a number of clean namespaces (classes, modules, etc.) for your own code. Use them! The core Python team reserved a somewhat ugly namespace for themselves — don’t trample all over their compromise by stealing their names.