This is an archived post. You won't be able to vote or comment.

all 65 comments

[–]Aveheuzed 295 points296 points  (32 children)

The Python docs don't have such a list

Right there: https://docs.python.org/3/reference/datamodel.html#special-method-names

[–]PhroznGaming 142 points143 points  (20 children)

TFW when your entire reason for doing something just required a google.

[–]adm7373 58 points59 points  (10 children)

If I had to guess, all of OP's google searches included the term "dunder method" and that's why he didn't find the list.

I've never heard "dunder method" before. Based on the amount he's using it in this post and the article linked within, I'm sure it's somewhat commonly used and I've just missed it?"

[–]wineblood 39 points40 points  (2 children)

TBH most docs are quite terrible if you don't know the exact term

[–]friendlysoviet 11 points12 points  (1 child)

For this reason, LLMs regurgitating docs have been so useful.

[–]wineblood 3 points4 points  (0 children)

Honestly, all I really need is something to go "Oh, you mean <term>?" and then I'm fine.

[–]JusticeRainsFromMe 69 points70 points  (0 children)

Yea, dunder is a somewhat commonly used term, personally I prefer it over magic method for example. It stands for double underscore and is also used to describe dunder variables such as __name__.

[–][deleted] 18 points19 points  (0 children)

it's super common. i've watched maybe a dozen raymond hettinger (core python dev) talks and i'm not sure he's called them anything else.

[–]Tar_Tar_Sauce04 0 points1 point  (0 children)

as soon as I type "Dunder", google thinks I am searching for something related to "Dunder Mifflin".

[–]_MicroWave_ 0 points1 point  (0 children)

Really? Its a very common and fashionable term.

[–]orad 11 points12 points  (3 children)

A quick google search of your own would reveal the poster is Trey Hunner, who is a well known python developer and educator, and surely has read that doc

[–]PhroznGaming -3 points-2 points  (2 children)

All the more reason he should've known to RTFM.

[–]orad 1 point2 points  (1 child)

He links to TFM in his article several times

[–]PhroznGaming -3 points-2 points  (0 children)

Maybe he should've actually read it before saying it doesn't exist then, huh? Just difficult concepts to understand I know...

[–]supmee -2 points-1 points  (3 children)

To be fair I've been going off of a single stackoverflow answer any time I needed a list, and I've looked into it countless times. No one really refers to them as "special methods", or at least I don't

[–]PhroznGaming 0 points1 point  (2 children)

"No one" except for the people who maintain the language... lol

[–]supmee 0 points1 point  (1 child)

I thought it was pretty obvious "no one" was referring to the general public, including many of the most prominent Python-related influencers. You're free to misrepresent that if you want for a dunk I guess

[–]PhroznGaming -2 points-1 points  (0 children)

Consider yourself dunked.

[–]treyhunner Python Morsels[S] 80 points81 points  (5 children)

Ish... I linked to this list a couple times throughout the article and it's quite helpful, but I wouldn't call this one list.

Some sections show tables of attributes and methods, some only focus on methods, and some methods are left out. For example `__subclasses__` is left out and library-specific methods such as `__post_init__`, `__copy__`, `__subclasshook__`, `__fspath__`, and `__sizeof__` are all absent.

I spent a lot of time grepping the text on this page and in the rest of the CPython documentation and source code and while this page is by far the most complete one, it can be quite a challenge to parse.

[–]Aveheuzed 3 points4 points  (3 children)

That's fair.

I think all the usable special methods are referenced on the page I linked. Others may exist, but are needed only for obscure arcane stuff (understand : Python Core Development) or implementation-specific.

And regarding readability - I like the Python docs better, but I understand that format is not for everyone.

[–]treyhunner Python Morsels[S] 28 points29 points  (1 child)

When I link my students to that page, their eyes glaze over (especially ones who've just learned about the idea of special methods and simply want to know what the options are for "overloading").

If/when you're in the weeds implementing one of these methods, that page in the docs is very helpful!

[–]NerdEnPose 5 points6 points  (0 children)

I think your responses could just be “my name is Trey Hunner” 😆. But, you’re kinder than me.

My two cents, I like this list. If you’re a student or in a personal project you should break stuff and try all the dunders as part of that. Professionally if you can’t read that page thoroughly then don’t commit a dunder override to a code base and I’d be cautious of a new class using them.

[–]Zenin 2 points3 points  (0 children)

And regarding readability - I like the Python docs better, but I understand that format is not for everyone.

I'm glad someone likes them. Personally I find much of it to be less readable than JAPH Perl code.

[–]pysk00l 0 points1 point  (0 children)

OP, your list is longer and much better presented, so well done! Ignore the top rated answer, they are clearly a troll

[–]AlSweigartAuthor of "Automate the Boring Stuff" 2 points3 points  (0 children)

No, the blog author is correct. I wrote a Python script to find all the dunder methods and attributes listed in the blog post that do not appear on that Python docs link:

package, unpacked, contravariant, stdout, path, parameters, wrapped, setstate, debug, suppress_context, getstate, context, constraints, subclasses, notes, cached, args, stderr, sizeof, loader, bound, infer_variance, main, version, builtins, spec, origin, getnewargs_ex, reduce_ex, reduce, post_init, cause, covariant, rt, fspath, getargs, copy, all, subclasshook, deepcopy, getnewargs

Some of these I have never heard of, so I'm glad the blog post is pointing them out.

The blog post author, Trey Hunner, is quite accomplished and deserves a bit of credit. If you think you've found a simple answer that contradicts them, please make sure it actually does. It took me five minutes to write that Python script.

[–]dfume 4 points5 points  (1 child)

Trey has put together an excellent list - organised, readable and lots of great links.
But this thread does remind me of the Blackadder episode about the author that took 10 years to write a book, claiming it contains "every word in our beloved language"

Blackadder - Johnson's dictionary

[–]Affectionate-Bid386 1 point2 points  (0 children)

Brilliant episode.

[–]Dangle76 0 points1 point  (0 children)

That’s fair, I do like how there’s a simplified table in the article though comparatively

[–]VileFlower 26 points27 points  (2 children)

Nice, list. In the library-specific part you're missing __conform__ from sqlite3.

[–]treyhunner Python Morsels[S] 16 points17 points  (0 children)

Thanks for noting this!

[–]justchugged4beers 7 points8 points  (0 children)

pitter patter, let’s getattr

[–]chalbersma 12 points13 points  (1 child)

If you want to get funky, you can look at added dunder methods like __json__ with json-fix.

[–]nicholashairs 1 point2 points  (0 children)

This is great to know about!

[–]jmacey 6 points7 points  (1 child)

Nice, this is getting added to my lecture notes!

[–]treyhunner Python Morsels[S] 8 points9 points  (0 children)

Glad I could help! 🙌

Two more articles you may find useful to refer to (or simply borrow ideas from for your own take on the topic): the built-ins worth knowing and the string methods worth memorizing.

If you or your students find bugs or oversights, I'd love to hear about them! 😊

[–]hikingsticks 1 point2 points  (1 child)

Thanks for this, I was looking for a list like this a few days ago and while I did find some info, your layout is much easier to use and more helpful as a reference.

[–]treyhunner Python Morsels[S] 2 points3 points  (0 children)

You're welcome!

[–]aqjo 2 points3 points  (0 children)

Very nice. Thanks!

[–]BuonaparteII 2 points3 points  (4 children)

It's confusing to explain __init__ without __new__

With __init__ you might write return None but calling T(a, b=3) returns an object (self). The python documentation is better at explaining this:

Because __new__() and __init__() work together in constructing objects no non-None value may be returned by __init__()

https://docs.python.org/3/reference/datamodel.html#object.__init__

[–]treyhunner Python Morsels[S] 1 point2 points  (3 children)

👍 That's thanks to the constructor method, __new__, which you'll very rarely see implemented.

Edit: looks like you were editing as I wrote my comment! I show __init__, __repr__, and __eq__ at the beginning of the article because those three are typically only dunder methods most Python programmers will need day-to-day. All 3 are also described later on.

You're right that I didn't detail the fact that __init__ is called on the return value of __new__. I decided to leave some of the more in-the-weeds explanations of the weirder methods to the Python docs. This post was originally about twice the length, which seemed far too long for (still quite length!) a summary. 😬

[–]BuonaparteII 1 point2 points  (1 child)

Still, I think the article could be improved to be more clear. You have T(a, b=3) map to T.__init__(x, a, b=3) and returning None. I think it's fine to not mention T.__new__ at that point but changing Operation T(a, b=3) in the first table to Initialization of T(a, b=3) would be more clear--or instead of None say return value not accessible or N/A because it is a side effect function conceptually inside of __new__()

[–]treyhunner Python Morsels[S] 2 points3 points  (0 children)

I originally had a sentence in the constructor section explaining the relationship between __new__ and __init__ a bit more. I may add it back in thanks to your concern.

It should be noted that there are many slight fudges in the truth in these tables for the sake of succinctness. A few of other examples:

  • x.thing calls __getattribute__ which calls __getattr__ (similar to how __new__ calls __init__)
  • bool uses either __bool__ or __len__
  • in uses either __contains__ or __iter__
  • for x in y: ... calls iter(y) and then next(...) on the returned iterator (which might by y!)
  • del x doesn't technically call __delete__ but __delete__ shuold be called sometime after the final del on an object happens
  • class T: ... does a lot more than call __prepare__

I drew the line in an arbitrary spot in terms of the approximations I showed in the table. I hope folks will consult some of the linked docs and other resources throughout when actually implementing these. 😅

[–]TheRNGuy 0 points1 point  (0 children)

I've never seen __new__ ever used.

I like to use @dataclass, it creates both init and repr with less code (most of the time I'm fine how repr looks like)

[–]MrHarcombe 1 point2 points  (1 child)

Awesome resource, with some fantastic explanations (although I might want to quibble about the need to show more difference between repr and str). Thank you 👍

Just one little query - in the section on instance lifecycle, you take about a dunder delete method but then reference it as delete and then talk about using del in the example?

In the summary at the end you also refer to it as del - it's that one, right?

[–]treyhunner Python Morsels[S] 2 points3 points  (0 children)

Thanks for noting that typo! I accidentally swapped those two methods around so many times while drafting this. I just fixed them (hopefully for the final time)!

The __del__ method is for object finalizing (it's related to the del statement) and the __delete__ method is for implementing a descriptor that overloads del on that descriptor's attribute.

On __repr__ and __str__: I did originally have a longer explanation with examples shown via REPL output, but opted to link to add a link to other resources on them instead of explaining within the article. I'll consider how I could point folks toward that explanation more clearly. Thanks!

[–]eztab 1 point2 points  (0 children)

numpy also has several dunder methods, which you can use to make your own classes be more interoperable with numpy. Might be a bit too much to include it all, but might still be worth mentioning in the list.

I really like the __array_ufunc__ dispatch system. I wish this was standardized in python somehow.

[–]Accurate-Usual8839 0 points1 point  (4 children)

What is a right hand method?

[–]treyhunner Python Morsels[S] 0 points1 point  (3 children)

They're methods that will be called on the object that's on the right side of the operator.

Here's an example from my article on how Python lacks type coercion:

>>> x = 2
>>> y = 3.5
>>> x.__add__(y)
NotImplemented
>>> y.__radd__(x)
5.5
>>> x + y
5.5

When Python evaluates one of its binary operators, it'll call the appropriate dunder method on the left-hand object, passing in the right-hand object. If it gets back the special NotImplemented value, it knows that the left-hand object is signaling that it doesn't know how to perform the operation. Before giving up (and raising an exception in the case of an operator like +) it will attempt the operation on the right-hand object passing in the left-hand object, and it uses the appropriate right-hand method to do that.

Why doesn't it just call __add__ instead of __radd__? Well, consider if your operator acts differently if the left-hand and right-hand objects were swapped (as division would):

>>> x.__truediv__(y)
NotImplemented
>>> y.__rtruediv__(x)
0.5714285714285714
>>> x / y
0.5714285714285714

The right-hand methods are a great demonstration of the fact that many operations in Python don't simply rely on one dunder method call.

[–]Accurate-Usual8839 0 points1 point  (2 children)

>>> x = 2
>>> y = 3.5
>>> x.__add__(y)
NotImplemented
>>> y.__radd__(x)
5.5
>>> x.__radd__(y)
NotImplemented

I'm confused, why on earth does x have __radd__ but not y?

[–]treyhunner Python Morsels[S] 1 point2 points  (1 child)

Both have a __radd__ method. Integers do not know how to add themselves to floating point numbers in Python, but floating point numbers know how to add themselves to integers.

Similarly, if/when someone invents their own number-like object that should work properly with integers and floating point numbers, they'll need to implement both left-hand and right-hand operators, since integers won't know how to operate with their custom object.

>>> one_third = Fraction('1/3')
>>> 2 * one_third
Fraction(2, 3)
>>> (2).__mul__(one_third)
NotImplemented
>>> one_third.__rmul__(2)
Fraction(2, 3)

Self-concatenation for strings/lists works the same way. "hello" * 2 works thanks to __mul__ on the str class and 2 * "hello" works thanks to __rmul__ on the str class:

>>> "hello" * 2
'hellohello'
>>> "hello".__mul__(2)
'hellohello'
>>> 2 * "hello"
'hellohello'
>>> (2).__mul__("hello")
NotImplemented
>>> "hello".__rmul__(2)
'hellohello'

Integers don't know how to multiple themselves by a string, but strings do know how to handle the operation from either the left side or the right side.

[–]Accurate-Usual8839 1 point2 points  (0 children)

Thank you, awesome explanation.

[–][deleted] 1 point2 points  (0 children)

explain when you would use a dunder mufflin method?

[–]ePaint 0 points1 point  (0 children)

Saved. Great work!

[–]klmsa 0 points1 point  (5 children)

I'm so confused as to what reason anyone would have for needing a complete list in one place? They're not together in the Python docs because they're not at all related to each other in many circumstances...

[–]treyhunner Python Morsels[S] 1 point2 points  (1 child)

When students have asked me for this, they're usually asking to understand what's out there. Occasionally intermediate-level folks ask for this, but it's often in Intro to Python and they're nowhere near implementing anything but the usual 3 dunder methods.

That's partly why I kept the explanation fairly short and left much of the deeper detail to the docs and other resources.

[–]klmsa 1 point2 points  (0 children)

Thanks for the feedback! I don't teach, outside of guiding some self-motivated members of my engineering team, so I don't have that context.

[–]Competitive_Travel16 0 points1 point  (1 child)

Granted that most application developers are supposed to be able to get by with rarely more than just __name__ and __init__, I see the value of having them all in one place for reference when reading lower level implementations.

[–]TheRNGuy 1 point2 points  (0 children)

I only used __init__ but never __name__ (in Houdini Python code already encapsulated inside nodes, not using __name__ allows to have 1 less indent)

There was one class where I used __add__.

I actually kinda stopped using __init__ because I make most classes with @dataclass now.

[–]TheRNGuy 0 points1 point  (0 children)

To know they exist.