Python "Magic Methods"                      (C) 2018-2025 T.Birnthaler OSTC GmbH
======================

Python kennt 95 spezielle Methoden ("Dunder" Methods = "Double Underscore" =
"Special Methods" = "Magic Methods"), die Python AUTOMATISCH aufruft, falls die
entsprechende Operation mit einem Objekt (oder einer Klasse) durchgeführt wird
(PY2/PY3 = gibt es nur in Python 2/3, 3.x = gibt es seit Python 3.x).

Doku --> docs.python.org/3/reference/datamodel.html#specialnames

  +-------------------+-----------------------------+--------------------------+
  | Magische Methode  | Aufruf durch ...            | Bedeutung                |
  +-------------------+-----------------------------+--------------------------+
  | __new__           | CLS()                       | Subclass im-mutable type |
  | __init__          | CLS()                       | Konstruktor              |
  | __del__           | del OBJ   garbage collector | Destruktor               |
  | __slots__         | CLS attributes              | Attribute                |
  +-------------------+-----------------------------+--------------------------+
  | __enter__         | with ... as ...             | Kontext-Manager          |
  | __exit__          | with ... as ...             |        "                 |
  +-------------------+-----------------------------+--------------------------+
  | __iter__          | for ... in ..., enumerate() | Iterator-Protokoll       |
  | __next__          | for ... in ..., enumerate() |         "                |
  +-------------------+-----------------------------+--------------------------+
  | __getinitargs__   | pickle.dump()/.restore()    | Pickling-Protokoll       |
  | __getnewargs__    | pickle.dump()/.restore()    |         "                |
  | __getstate__      | pickle.dump()/.restore()    |         "                |
  | __setstate__      | pickle.dump()/.restore()    |         "                |
  | __reduce__        | pickle.dump()/.restore()    |         "                |
  | __reduce_ex__     | pickle.dump()/.restore()    |         "                |
  +-------------------+-----------------------------+--------------------------+
  | __copy__          | copy.copy()                 | Flache Kopie (shallow)   |
  | __deepcopy__      | copy.deepcopy()             | Tiefe Kopie (deep)       |
  | __replace__       | copy.replace()              | Kopie mit Ersetzung      | 3.13
  +-------------------+-----------------------------+--------------------------+
  | __repr__          | repr()  print()             | Maschinen-Repräsentation |
  | __str__           | str()   print()             | Menschliche Darstellung  |
  | __format__        | F"..."   "...".format()     | Formatierung             |
  | __unicode__       | unicode()                   | __str__ + __byte__ in PY3| PY2
  | __hash__          | hash()                      | Fingerprint, Kondensat   |
  | __nonzero__       | bool()                      | __bool__ in PY3          | PY2
  +-------------------+-----------------------------+--------------------------+
  | __bool__          | bool()                      | Datentyp-Konvertierung   |
  | __bytes__         | bytes()                     |         "                |
  | __complex__       | complex()                   |         "                |
  | __int__           | int()                       |         "                |
  | __long__          | long()                      |         "                | PY2
  | __float__         | float()                     |         "                |
  +-------------------+-----------------------------+--------------------------+
  | __oct__           | oct()                       | Zahlen-Konvertierung     |
  | __hex__           | hex()                       |       "                  |
  | __bin__           | bin()                       |       "                  |
  +-------------------+-----------------------------+--------------------------+
  | __index__         | OBJ[N:M:S]                  | Slice-Operator           |
  | __dir__           | dir()                       | Objekt-Attributliste     | 3.7
  | __call__          | OBJ()    called as function | x() --> x.__call__()     |
  | __coerce__        |                             | Mixed mode arithmetic    | PY2
  +-------------------+-----------------------------+--------------------------+
  | __getattr__       | OBJ.ATTR          getattr() | Objekt-Attribute         | 3.7
  | __getattribute__  | OBJ.ATTR          getattr() |       "                  |
  | __setattr__       | OBJ.ATTR = VAL    setattr() |       "                  |
  | __delattr__       | del OBJ.ATTR      delattr() |       "                  |
  +-------------------+-----------------------------+--------------------------+
  | __get__           |                             | Deskriptor-Klasse   TODO |
  | __set__           |                             |           "         TODO |
  | __delete__        |                             |           "         TODO |
  | __set_name__      |                             |           "         TODO |
  +-------------------+-----------------------------+--------------------------+
  | __init_subclass__ |                             | TODO                     |
  | __instancecheck__ | isinstance()                | TODO                     |
  | __subclasscheck__ | issubclass()                | TODO                     |
  | __class_getitem__ |                             | TODO                     |
  +-------------------+-----------------------------+--------------------------+
  | __len__           | len()                       | Element-Anz. (Container) |
  | __length_hint__   |                             | TODO                     |
  | __reversed__      | reversed()                  | Reihenfolge umdrehen     |
  | __contains__      | in    not in                | Enthält-Operator (nicht) |
  +-------------------+-----------------------------+--------------------------+
  | __getitem__       | OBJ[KEY]                    | Indexzugriff auf Element |
  | __missing__       | OBJ[KEY]                    | dict-Subklasse           |
  | __setitem__       | OBJ[KEY] = VALUE            |     "                    |
  | __delitem__       | del OBJ[KEY]                |     "                    |
  +-------------------+-----------------------------+--------------------------+
  | __eq__            | x == y                      | Wert-Vergleich   "equal" |
  | __ne__            | x != y                      |     "        "not equal" |
  | __lt__            | x < y                       |     "        "less than" |
  | __le__            | x <= y                      |     "       "less equal" |
  | __gt__            | x > y                       |     "     "greater than" |
  | __ge__            | x >= y                      |     "    "greater equal" |
  | __cmp__           | x </==/> y --> -1/0/1       |     "          "compare" | PY2
  +-------------------+-----------------------------+--------------------------+
  | __add__           | +                           | Arithmetische Operatoren |
  | __sub__           | -                           |          "               |
  | __mul__           | *                           |          "               |
  | __matmul__        | @                           |          "               |
  | __div__           | /                           |          "               | PY2
  | __truediv__       | /                           |          "               | PY3
  | __floordiv__      | //                          |          "               | PY3
  | __mod__           | %                           |          "               |
  | __divmod__        | divmod()                    |          "               |
  | __pow__           | **   pow()                  |          "               |
  | __lshift__        | <<                          |          "               |
  | __rshift__        | >>                          |          "               |
  | __and__           | &                           |          "               |
  | __or__            | |                           |          "               |
  | __xor__           | ^                           |          "               |
  +-------------------+-----------------------------+--------------------------+
  | __iadd__          | +=                          | "Inplace" arith. Op.     |
  | __isub__          | -=                          |          "               |
  | __imul__          | *=                          |          "               |
  | __imatmul__       | @=                          |          "               |
  | __idiv__          | /=                          |          "               |
  | __itruediv__      | /=                          |          "               | PY2
  | __ifloordiv__     | //=                         |          "               | PY3
  | __imod__          | %=                          |          "               | PY3
  | __ipow__          | **=                         |          "               |
  | __ilshift__       | <<=                         |          "               |
  | __irshift__       | >>=                         |          "               |
  | __iand__          | &=                          |          "               |
  | __ior__           | |=                          |          "               |
  | __ixor__          | ^=                          |          "               |
  +-------------------+-----------------------------+--------------------------+
  | __radd__          | +                           | "Reflected" arith. Op.   |
  | __rsub__          | -                           |          "               |
  | __rmul__          | *                           |          "               |
  | __rmatmul__       | @                           |          "               |
  | __rdiv__          | /                           |          "               | PY2
  | __rtruediv__      | /                           |          "               | PY3
  | __rfloordiv__     | //                          |          "               | PY3
  | __rmod__          | %                           |          "               |
  | __rdivmod__       | divmod()                    |          "               |
  | __rpow__          | **                          |          "               |
  | __rlshift__       | <<                          |          "               |
  | __rrshift__       | >>                          |          "               |
  | __rand__          | &                           |          "               |
  | __ror__           | |                           |          "               |
  | __rxor__          | ^                           |          "               |
  +-------------------+-----------------------------+--------------------------+
  | __neg__           | -              (Vorzeichen) | Unäre arithmetische Op.  |
  | __pos__           | +              (Vorzeichen) |          "               |
  | __abs__           | abs()                       |          "               |
  | __invert__        | ~                           |          "               |
  +-------------------+-----------------------------+--------------------------+
  | __round__         | round()                     | Fließkomma-Konvertierung |
  | __floor__         | floor()                     |          "               |
  | __ceil__          | ceil()                      |          "               |
  | __trunc__         | trunc()                     |          "               |
  +-------------------+-----------------------------+--------------------------+
  | __aenter_         | async with ...              | Asynchroner Kontex-Manag.| TODO
  | __aexit__         | async with ...              |         "                | TODO
  +-------------------+-----------------------------+--------------------------+
  | __aiter__         | async for ...               | Asynchrones Iterator-P.  | TODO
  | __anext__         | async for ...               |         "                | TODO
  | __await__         | await FUNK()                |         "                | TODO
  +-------------------+-----------------------------+--------------------------+
  | __class__         |                             | Klasse des Objekts       | TODO
  | __metaclass__     |                             |       TODO               | TODO
  | __subclasses__    |                             |       TODO               | TODO
  | __mro__           |                             | Method Resolution Order  | TODO
  | __mro_entries__   |                             | Method Resolution Order  | TODO
  +-------------------+-----------------------------+--------------------------+
  | __closure__       |                             |       TODO               | TODO
  | __code__          |                             | Code-Objekt (Fkt, Klasse)| TODO
  | __defaults__      |                             | Defaultwerte von Fkt.    | TODO
  | __kwdefaults__    |                             | Defaultwerte von Fkt.    | TODO
  +-------------------+-----------------------------+--------------------------+
  | __fspath__        |                             |       TODO               | TODO
  | __import__        |                             |       TODO               | TODO
  | __prepare__       |                             |       TODO               | TODO
  | __weakref__       |                             |       TODO               | TODO
  +-------------------+-----------------------------+--------------------------+ TODO
  | __getslice__      |                             | Deprecated               | TODO
  | __delslice__      |                             | Deprecated               | TODO
  | __setslice__      |                             | Deprecated               | TODO
  +-------------------+-----------------------------+--------------------------+

HINWEISE:

* Die ZUWEISUNG "=" ist KEIN Operator und kann daher nicht überladen werden
  (weist der linken Seite immer die ID des Objekts auf der rechten Seite zu).

    var = ...

* Der WALRUS OPERATOR ":=" ist eine ZUWEISUNG im Rahmen eines Rechenausdrucks
  und kann daher nicht überladen werden (weist der linken Seite immer die ID
  des Objekts auf der rechten Seite zu).

    if erg := (2 + 3) * 4:
        ...

* "is" und "is not" vergleichen die IDENTITÄT zweier OBJEKTE anhand ihrer
  beiden IDs und können nicht überladen werden. Sind eine Abkürzung für:

    a is b        # --> id(a) == id(b)
    a is not b    # --> id(a) != id(b)

* __iOP__ ("Inplace") wird aufgerufen bei der abgekürzten Zuweisung a OP= b
  (entspricht a = a OP b)

    a += b        # --> type(a).__iadd__(a, b) aufgerufen

* __rOP__ ("Reflected") wird aufgerufen, falls die von a OP b aufgerufene
  Funktion type(a).__OP__(a, b) den Wert "NotImplemented" zurückgibt oder
  falls diese Funktion fehlt. Dann wird type(b).__rOP__(a, b) aufgerufen.

    a + b --> type(a).__add__(a, b) aufgerufen
          --> Nicht vorhanden oder Ergebnis "Not Implemented"
          --> type(b).__radd__(a, b) aufgerufen

* Die logischen Operatoren "and", "or" und "not" können nicht überladen werden.
  Sie konvertieren Objekt(e) nach bool() per Methode __bool__() und verwenden
  dieses Ergebnis für die Ermittlung des Endergebnisses. "and" und "or" machen
  eine Short-Cut/Short-Circuit-Evaluation, d.h. sie brechen die Auswertung ab,
  falls das Ergebnis bereits aufgrund der linken Seite feststeht.

    not a    # --> not bool(a) --> not type(a).__bool__(a)
    a and b  # --> bool(a) == True?  --> b
             #     bool(a) == False? --> a
    a or b   # --> bool(a) == True?  --> a
             #     bool(a) == False? --> b