Functions related to classes¶
- introspection.iter_subclasses(cls, include_abstract=False)¶
Yields subclasses of the given class.
New in version 1.5.
- introspection.get_subclasses(*args, **kwargs)¶
Collects all subclasses of the given class.
- introspection.get_attributes(obj, include_weakref=False)¶
Returns a dictionary of all of
obj
’s attributes. This includes attributes stored in the object’s__dict__
as well as in__slots__
.
- introspection.get_abstract_method_names(cls)¶
Returns a set of names of abstract methods (and other things) in the given class. See also
is_abstract()
.New in version 1.4.
- introspection.safe_is_subclass(subclass, superclass)¶
A clone of
issubclass()
that returnsFalse
instead of throwing aTypeError
.New in version 1.2.
- Parameters
subclass – The subclass
superclass – The superclass
- Return type
- Returns
Whether
subclass
is a subclass ofsuperclass
- introspection.iter_slots(cls)¶
Iterates over all
__slots__
of the given class, yielding(slot_name, slot_descriptor)
tuples.If a slot name is used more than once, all of them will be yielded in the order they appear in the class’s MRO.
Note that this function relies on the class-level
__slots__
attribute - deleting or altering this attribute in any way may yield incorrect results.
- introspection.get_slot_names(cls)¶
Collects all of the given class’s
__slots__
, returning a set of slot names.
- introspection.get_slot_counts(cls)¶
Collects all of the given class’s
__slots__
, returning a dict of the form{slot_name: count}
.- Parameters
cls (
type
) – The class whose slots to collect- Return type
- Returns
A
collections.Counter
counting the number of occurrences of each slot
- introspection.get_slots(cls)¶
Collects all of the given class’s
__slots__
, returning a dict of the form{slot_name: slot_descriptor}
.If a slot name is used more than once, only the descriptor that shadows all other descriptors of the same name is returned.
- introspection.get_implicit_method_type(method_name)¶
Given the name of a method as input, returns what kind of method python automatically converts it to. The return value can be
staticmethod
,classmethod
, orNone
.Examples:
>>> get_implicit_method_type('frobnicate_quadrizzles') >>> get_implicit_method_type('__new__') <class 'staticmethod'> >>> get_implicit_method_type('__init_subclass__') <class 'classmethod'>
New in version 1.3.
- introspection.fit_to_class(thing, cls, name=None)¶
Updates
thing
‘s metadata to matchcls
‘s.thing
can be one of the following:A function
A
property
If
name
is notNone
,thing
will be renamed accordingly.New in version 1.4.
- introspection.add_method_to_class(method, cls, name=None, method_type=auto)¶
Adds
method
tocls
‘s namespace under the givenname
.If
name
isNone
, it defaults tomethod.__name__
.The method’s metadata (
__name__
,__qualname__
, and__module__
) will be updated to match the class.If a
method_type
is passed in, it should have a value ofstaticmethod
,classmethod
, orNone
. If omitted, it is automatically determined by callingget_implicit_method_type()
. The method is then automatically wrapped with the appropriate descriptor.New in version 1.3.
- introspection.wrap_method(method, cls, name=None, method_type=auto)¶
Adds
method
tocls
‘s namespace under the givenname
, wrapping the existing method (if one exists).The replaced method will be passed in as the first positional argument (even before the implicit
self
). If the class previously didn’t implement this method, an appropriate dummy method will be passed in instead, which merely sends the call further up the MRO.method_type
has the same meaning as it does inadd_method_to_class()
.Example:
class Foo: def __init__(self, foo): self.foo = foo def __repr__(self): return f'<Foo object with foo={self.foo}>' def custom_init(original_init, self, *args, **kwargs): original_init(self, *args, **kwargs) print('Initialized instance:', self) wrap_method(custom_init, Foo, '__init__') Foo(5) # prints "Initialized instance: <Foo object with foo=5>"
Note
Adding a
__new__
method to a class can lead to unexpected problems because of the wayobject.__new__
works.If a class doesn’t implement a
__new__
method at all,object.__new__
silently discards any arguments it receives. But if a class does implement a custom__new__
method, passing arguments intoobject.__new__
will throw an exception:class ThisWorks: def __init__(self, some_arg): pass class ThisDoesntWork: def __new__(cls, *args, **kwargs): return super().__new__(cls, *args, **kwargs) def __init__(self, some_arg): pass ThisWorks(5) # works ThisDoesntWork(5) # throws TypeError: object.__new__() takes exactly one argument
This is why, when this function is used to add a
__new__
method to a class that previously didn’t have one, it automatically generates a dummy__new__
that attempts to figure out whether it should forward its arguments to the base class’s__new__
method or not. This is why the following code will work just fine:class ThisWorks: def __init__(self, some_arg): pass def __new__(original_new, cls, *args, **kwargs): return original_new(cls, *args, **kwargs) wrap_method(__new__, ThisWorks) ThisWorks(5) # works!
However, it is impossible to always correctly figure out if the arguments should be passed on or not. If there is another
__new__
method that passes on its arguments, things will go wrong:class Parent: def __init__(self, some_arg): pass class Child(Parent): def __new__(cls, *args, **kwargs): return super().__new__(cls, *args, **kwargs) def __new__(original_new, cls, *args, **kwargs): return original_new(cls, *args, **kwargs) wrap_method(__new__, Parent) Parent(5) # works! Child(5) # throws TypeError
In such a scenario, the method sees that
Child.__new__
exists, and therefore it isChild.__new__
‘s responsibility to handle the arguments correctly. It should consume all the arguments, but doesn’t, so an exception is raised.As a workaround, you can mark
Child.__new__
as a method that forwards its arguments. This is done by setting its_forwards_args
attribute toTrue
:Child.__new__._forwards_args = True Child(5) # works!
New in version 1.3.
- Parameters
method – The method to add to the class
cls – The class to which to add the method
name – The name under which the method is registered in the class namespace
method_type – One of
staticmethod
,classmethod
, orNone
(or omitted)