Functions related to dundermethods — Introspection documentation

# Functions related to dundermethods

Working with dundermethods can be tricky, because when python searches for a dundermethod, it doesn’t use the same mechanism as it does for normal attribute access. Normal attribute access like `obj.attr` will look for `attr` in the instance’s namespace (i.e. `obj.__dict__`) and the class’s namespace (i.e. `type(obj).__dict__` plus the `__dict__` of every parent class). Dundermethods, on the other hand, are only searched for in the class namespace - not the instance namespace. Defining a dundermethod in the instance namespace won’t work:

    class Demo:
        pass

    obj = Demo()
    obj.__len__ = lambda self: 0

    print(len(obj))  # throws TypeError: object of type 'Demo' has no len()

And neither will defining a dundermethod in a metaclass:

    class DemoMeta(type):
        def __len__(cls):
            return 0

    class Demo(metaclass=DemoMeta):
        pass

    obj = Demo()

    print(len(obj))  # throws TypeError: object of type 'Demo' has no len()

So if you wanted to implement your own `len` function, you wouldn’t have an easy way of accessing the relevant `__len__` method - `obj.__len__` would be incorrect because it would search the instance namespace, and `type(obj).__len__` would be incorrect because it would search the metaclass namespace. That’s where these functions come in - `get_bound_dundermethod(obj)` or `get_class_dundermethod(type(obj))` would do the work for you.

`introspection.` `DUNDERMETHOD_NAMES` = {'__abs__', '__add__', '__aenter__', '__aexit__', '__aiter__', '__and__', '__anext__', '__await__', '__bool__', '__bytes__', '__call__', '__ceil__', '__class_getitem__', '__complex__', '__contains__', '__del__', '__delattr__', '__delete__', '__delitem__', '__delslice__', '__dir__', '__div__', '__divmod__', '__enter__', '__eq__', '__exit__', '__float__', '__floor__', '__floordiv__', '__format__', '__fspath__', '__ge__', '__get__', '__getattr__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__iand__', '__ifloordiv__', '__ilshift__', '__imatmul__', '__imod__', '__imul__', '__index__', '__init__', '__init_subclass__', '__instancecheck__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', '__length_hint__', '__lshift__', '__lt__', '__matmul__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__next__', '__or__', '__pos__', '__pow__', '__prepare__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rfloordiv__', '__rlshift__', '__rmatmul__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__set__', '__set_name__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__sub__', '__subclasscheck__', '__subclasses__', '__truediv__', '__trunc__', '__xor__'}

  A set containing the names of all dundermethods.

`introspection.` `AUGMENTED_ASSIGNMENT_DUNDERMETHOD_NAMES` = {'__iadd__', '__iand__', '__ifloordiv__', '__ilshift__', '__imatmul__', '__imod__', '__imul__', '__ior__', '__ipow__', '__irshift__', '__isub__', '__itruediv__', '__ixor__'}

  A set containing the names of all augmented assignment dundermethods.

  New in version 1.1.

`introspection.` `iter_class_dundermethods`(cls, bound=None)

  Yields all dundermethods implemented by the given class as `(method_name, method)` tuples.

  (For the purpose of this function, “implemented” simply means “exists”. Even if the method’s value is `None` or anything else, it will still be yielded.)

  If multiple classes in the MRO implement the same dundermethod, both methods will be yielded. Methods implemented by subclasses will always be yielded before methods implemented by parent classes.

  You can cause the iteration to stop early by passing in a class as the upper `bound`. The MRO will only be iterated up to the `bound`, excluding the `bound` class itself. This is useful for excluding dundermethods implemented in `object`.

  Parameters

    - cls – The class whose dundermethods to yield

    - bound – Where to stop iterating through the class’s MRO

  Returns

    An iterator yielding `(method_name, method)` tuples

  Raises

    TypeError – If `cls` is not a class

`introspection.` `class_implements_dundermethod`(cls, method_name, bound=None)

  Checks whether the given class implements a certain dundermethod.

  The method is considered implemented if any of the classes in the MRO have an entry for `method_name` in their `__dict__`. The only exception is that `__hash__` methods are considered not implemented if their value is `None`.

  Note that `object` implements various dundermethods, including some unexpected ones like `__lt__`. Remember to pass in `bound=object` if you wish to exclude these.

  Parameters

    - cls – A class

    - method_name – The name of a dundermethod

    - bound – Where to stop searching through the class’s MRO

  Returns

    A boolean indicating whether the class implements that dundermethod

  Raises

    TypeError – If `cls` is not a class

`introspection.` `class_implements_any_dundermethod`(cls, methods, bound=None)

  Checks whether the given class implements at least one of the given dundermethods.

  Parameters

    - cls – A class

    - methods – The names of a bunch of dundermethods

    - bound – Where to stop searching through the class’s MRO

  Returns

    A boolean indicating whether the class implements any of those dundermethods

  Raises

    TypeError – If `cls` is not a class

`introspection.` `class_implements_dundermethods`(cls, methods, bound=None)

  Checks whether the given class implements all given dundermethods.

  Parameters

    - cls – A class

    - methods – The names of a bunch of dundermethods

    - bound – Where to stop searching through the class’s MRO

  Returns

    A boolean indicating whether the class implements all those dundermethods

  Raises

    TypeError – If `cls` is not a class

`introspection.` `collect_class_dundermethods`(cls, bound=None)

  Generates a dict of the form `{method_name: method}` containing all dundermethods implemented by the given class.

  If multiple classes in the MRO implement the same dundermethod, only the first implementation is included in the result.

  Parameters

    - cls – The class whose dundermethods to collect

    - bound – Where to stop iterating through the class’s MRO

  Returns

    A `{method_name: method}` dict

  Raises

    TypeError – If `cls` is not a class

`introspection.` `get_class_dundermethod`(cls, method_name, bound=None)

  Retrieves a class’s implementation of the given dundermethod.

  Parameters

    - cls – A class

    - method_name – The name of a dundermethod

    - bound – Where to stop searching through the class’s MRO

  Returns

    The function object for the given `method_name`

  Raises

    - TypeError – If `cls` is not a class

    - AttributeError – If `cls` does not implement that dundermethod

`introspection.` `get_bound_dundermethod`(instance, method_name, bound=None)

  Retrieves a class’s implementation of the given dundermethod.

  New in version 1.1.

  Parameters

    - instance – Any object

    - method_name – The name of a dundermethod

    - bound – Where to stop searching through the class’s MRO

  Returns

    A bound method for the given `method_name`

  Raises

    - TypeError – If `cls` is not a class

    - AttributeError – If `cls` does not implement that dundermethod