A Guide to Python's Magic Methods
rafekettler.com
rafekettler.com
Whenever working on any reasonably complex class, I find that open in a tab to verify that I'm using the magic methods properly, and that they'll be called as I expect.
I wanted my post to be more akin to a tutorial than a reference. I don't think the data model reference is useful to people who don't know the basics -- the idea was to bridge that gap so that it could be useful.
> ... This can be useful for catching and redirecting common misspellings ...
I can think of only one good reason to redirect spelling errors, and that's if you are a widely-used library and you want to support both "color" and "colour" (and similar Britishisms). Other than that, you're just asking for a headache.
Stuff like __getattr__ is particularly tricky. I also try to end __getattr__ code with an AttributeException, which I find really helps debugging. I like using this to dispatch calls to objects better built to fill them, but I try to do so explicitly within the __getattr__ code to give reviewers a clue as to what's going on. For example, I'll check the attribute name against a list before passing it on to the target object. Even if I intent to pass _everything_ to a target, I'll first check the target for the passed attribute with getattr(target, attribute name, False), so that failed passthroughs stay with the object calling them. (You can generate messages indicating the problem -- "Can't find 'RIAA' in object 'Nice'" and pass those to an AttributeException.) Ideally any string validly usable as an instance attribute should be findable somewhere in the code by grep.
What? When did that get discredited?
http://programmers.stackexchange.com/questions/12401/be-libe...
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.
I do exactly what you just described, see http://www.rafekettler.com/magicmethods.html#appendix
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.
Thanks for writing this up!
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.
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.
They probably started this trend around 1995, now that I think about it, ya know. since the language is that old and all.
It is still really annoying, I just cringe when I use __init__ constructors because they look so ugly in otherwise very English-document-like source.
</rant>
How about a "special" keyboard?
def special init()
How about @?
def @init()
or ::
def special::init()
or, all caps, like Go does initial-cap for exported members:
def INIT()
And I think you're right about __init__ - constructors are not magic.
But in fact, I like "word" __init__ even more outside of python.
I use it to name directories for all new, incoming, uncategorized stuff.
For example: I have "music" with subdirectories named by artist, and I have __init__ where I put all artists I found recently. Same for "books", "docs", "work", etc.
I like it because "__init__" is always on top. Compare it with "new", "incoming", "now", "unclassified".
Its been a while since I've been through getattr vs getattribute pages, but I distinctly remember there's a big big difference in how you use them. I was kinda hoping the page had it, but unfortunately it didnt.
Original Author, if you're reading this - kindly do that.
__getattr__ allows "normal" lookup (is it a method, does it exist in __dict__, etc) to be done by the VM and isn't called until you would otherwise get an AttributeError.