Hacker News new | past | comments | ask | show | jobs | submit login

For each special method, you should show what syntax magically invokes it. Something like this:

foo.__iter__() is invoked by for x in foo a.__iadd__(b) is invoked by a += b a.__rmult__(b) is invoked by b * a when b * a fails. foo.__len__() is invoked by if foo when foo.__bool__ or foo.__nonzero__ is not defined. foo.__repr__() is invoked by '%r' % foo, also by pprint.pprint(foo) and deprecated `foo`. It's also invoked by __str__ magic when foo.__str__ is not defined. etc. Putting the above info in a table would also be helpful.




This was my work (not sure why someone randomly posted it here, but such is the internet).

I do exactly what you just described, see http://www.rafekettler.com/magicmethods.html#appendix


The word example is dangerous; two different words of the same length are neither less than each other, greater than each other, or equal to each other. I think sorting may not work as well as you'd like, and you should just be passing a custom cmp function to the sort method. The other comparison methods are for optimization; they should never disagree with __cmp__, and if __cmp__ is already optimal you should usually not define them.


You should not document __coerce__, it shouldn't be used anymore.

Also why put __nonzero__, __str__ and __unicode__ in "Representing your Classes" instead of "Type conversion magic methods"? Why not talk about the collections ABCs for container operators? (using them as mixins greatly implifies implementing containers, and makes it clear what's required and what is not)?

And the __concat__ note is incorrect, that does not exist in the userland datamodel it exists only in the `operator` module and in the C sequence protocol.


I'm quite glad someone posted it here! I'm not sure if I would have found such a useful reference otherwise.

Thanks for writing this up!


Such is the Internet indeed.

I stumbled upon this while researching some Python magic. I felt it was a pretty good write-up so I decided to share it with my fellow HN'ers.

Thank you for posting this.


And thank you for posting. I'll take all of the traffic I can get :)


> a.__rmult__(b) is invoked by b * a when b * a fails.

And for boolean comparisons, mirrored is an other operator: if trying a >= b and a.__ge__(b) fails, then the interpreter will fall back on b.__le__(a) (and if that fails as well, then both CPython and Pypy will compare the value's type's name in Python 2 although that's considered an implementation detail — and the interpreters may behave differently as some types have different casings)

Also, if I remember correctly "failure" is either the method not existing or the method returning NotImplemented.

An other interesting fallback is `in` (`__contains__`) which falls back on iteration when there is no `__contains__` and iteration itself (`__iter__`) falls back on `__getitem__(int)` when `__iter__` is not defined.

So you can have `a in b` ending up calling `a.__getitem__(0)`, which the container does not always expect (when it's not been coded correctly)

It's rather sad that TFA does not explain these, or in which case reflected arithmetic operators get called (his example makes very little sense, especially for non-commutative operators).

> foo.__bool__ or foo.__nonzero__

Important note: the former is the Python 3 version of the latter, defining __bool__ in Python 2 does not work.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: