Unsorted Random Notes

Method calls and interpreters

  • Dunder (‘double under’) __methods__ are only meant to be called by Python interpreters, not by developers directly. __init__ is the usual exception, called explicitly via super().__init__() in subclass constructors.
  • If you need to call a __method__, it’s usually better to call the related built-in function (e.g. len, iter, str, etc.) rather than __len__() directly.
  • Sometimes, the __method__ and method() built-in produces different results. For example, list.sort() sorts a list in place and returns None indicating that no new object was created, while sorted(list) creates a new list and returns it. The shuffles() built-in has the same behaviour as sorted().
  • Invocation of special methods by the interpreter is often implicit, and the dispatch chain can have fallbacks. For example, for k in x first tries iter(x) (which calls x.__iter__); if __iter__ is not defined, the interpreter falls back to the older sequence protocol and calls x.__getitem__(0), x.__getitem__(1), … until IndexError. This is why classes implementing only __getitem__ are still iterable.
  • Built-in types are often optimised for performance - take advantage of them when you can. The optimisation can bypass the special methods entirely: for built-ins like list and str, CPython reads the ob_size field of the PyVarObject struct to get the length instead of calling __len__. This is transparent as long as you go through the built-in (len(obj)) rather than the dunder.
  • __repr__ and __str__ - if you implement one, pick __repr__. It represents the string representation of the object, and you should be able to recreate the object from __repr__’s output. It’s also the fallback for __str__.