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 available in python 3.9.
- 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 available in python 3.9.
New in version 1.1.
- introspection.iter_class_dundermethods(cls, *, start=None, start_after=None, 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 skip some classes in the MRO by specifying
start
orstart_after
. Ifstart
is notNone
, iteration will begin at that class. Ifstart_after
is notNone
, iteration will begin after that class. Passing both at the same time is not allowed.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 thebound
, excluding thebound
class itself. This is useful for excluding dundermethods implemented inobject
.- Parameters
cls (
type
) – The class whose dundermethods to yieldstart (
Optional
[type
], default:None
) – Where to start iterating through the class’s MROstart_after (
Optional
[type
], default:None
) – Where to start iterating through the class’s MRObound (
Optional
[type
], default:None
) – Where to stop iterating through the class’s MRO
- Return type
- Returns
An iterator yielding
(method_name, method)
tuples- Raises
TypeError – If
cls
is not a class
- introspection.class_implements_dundermethod(cls, method_name, *, start=None, start_after=None, 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 exceptions are methods fromNONEABLE_DUNDERMETHOD_NAMES
, which are considered not implemented if their value isNone
.Note that
object
implements various dundermethods, including some unexpected ones like__lt__
. Remember to pass inbound=object
if you wish to exclude these.For details about
start
,start_after
andbound
, seeiter_class_dundermethods()
.New in version 1.4: The
start
andstart_after
parameters.- Parameters
cls (
type
) – A classmethod_name (
str
) – The name of a dundermethodstart (
Optional
[type
], default:None
) – Where to start searching through the class’s MROstart_after (
Optional
[type
], default:None
) – Where to start searching through the class’s MRObound (
Optional
[type
], default:None
) – Where to stop searching through the class’s MRO
- Return type
- 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, *, start=None, start_after=None, bound=None)¶
Checks whether the given class implements at least one of the given dundermethods.
For details about
start
,start_after
andbound
, seeiter_class_dundermethods()
.New in version 1.4: The
start
andstart_after
parameters.- Parameters
cls (
type
) – A classmethods (
Iterable
[str
]) – The names of a bunch of dundermethodsstart (
Optional
[type
], default:None
) – Where to start searching through the class’s MROstart_after (
Optional
[type
], default:None
) – Where to start searching through the class’s MRObound (
Optional
[type
], default:None
) – Where to stop searching through the class’s MRO
- Return type
- 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, *, start=None, start_after=None, bound=None)¶
Checks whether the given class implements all given dundermethods.
For details about
start
,start_after
andbound
, seeiter_class_dundermethods()
.New in version 1.4: The
start
andstart_after
parameters.- Parameters
cls (
type
) – A classmethods (
Iterable
[str
]) – The names of a bunch of dundermethodsstart (
Optional
[type
], default:None
) – Where to start searching through the class’s MROstart_after (
Optional
[type
], default:None
) – Where to start searching through the class’s MRObound (
Optional
[type
], default:None
) – Where to stop searching through the class’s MRO
- Return type
- Returns
A boolean indicating whether the class implements all those dundermethods
- Raises
TypeError – If
cls
is not a class
- introspection.collect_class_dundermethods(cls, *, start=None, start_after=None, 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.
For details about
start
,start_after
andbound
, seeiter_class_dundermethods()
.New in version 1.4: The
start
andstart_after
parameters.- Parameters
cls (
type
) – The class whose dundermethods to collectstart (
Optional
[type
], default:None
) – Where to start iterating through the class’s MROstart_after (
Optional
[type
], default:None
) – Where to start iterating through the class’s MRObound (
Optional
[type
], default:None
) – Where to stop iterating through the class’s MRO
- Return type
- Returns
A
{method_name: method}
dict- Raises
TypeError – If
cls
is not a class
- introspection.get_class_dundermethod(cls, method_name, *, start=None, start_after=None, bound=None)¶
Retrieves a class’s implementation of the given dundermethod.
For details about
start
,start_after
andbound
, seeiter_class_dundermethods()
.New in version 1.4: The
start
andstart_after
parameters.- Parameters
cls (
type
) – A classmethod_name (
str
) – The name of a dundermethodstart (
Optional
[type
], default:None
) – Where to start searching through the class’s MROstart_after (
Optional
[type
], default:None
) – Where to start searching through the class’s MRObound (
Optional
[type
], default:None
) – Where to stop searching through the class’s MRO
- Return type
- Returns
The function object for the given
method_name
- Raises
TypeError – If
cls
is not a classAttributeError – If
cls
does not implement that dundermethod
- introspection.get_bound_dundermethod(instance, method_name, *, start=None, start_after=None, bound=None)¶
Retrieves an instance’s implementation of the given dundermethod.
Some dundermethods (for example
__hash__
) can be explicitly disabled by setting them toNone
. In such a case, this function will throw anAttributeError
.For details about
start
,start_after
andbound
, seeiter_class_dundermethods()
.New in version 1.1.
New in version 1.4: The
start
andstart_after
parameters.- Parameters
instance (
Any
) – Any objectmethod_name (
str
) – The name of a dundermethodstart (
Optional
[type
], default:None
) – Where to start searching through the class’s MROstart_after (
Optional
[type
], default:None
) – Where to start searching through the class’s MRObound (
Optional
[type
], default:None
) – Where to stop searching through the class’s MRO
- Return type
- Returns
A bound method for the given
method_name
- Raises
AttributeError – If
instance
does not implement that dundermethod
- introspection.call_dundermethod(instance, method_name, *args, **kwargs)¶
Given an instance and the name of a dundermethod, calls the object’s corresponding dundermethod. Excess arguments are passed to the dundermethod.
Examples:
>>> call_dundermethod('foo', '__len__') 3 >>> call_dundermethod([1], '__add__', [2]) [1, 2]
Alternatively, you can use the functions in the
introspection.dunder
module:>>> introspection.dunder.__len__('foo') 3 >>> introspection.dunder.add([1], [2]) [1, 2]
New in version 1.4.