I know this is probably bad design, but I've run into a case where I need to create a subclass Derived
of a class Base
on-the-fly, and make instances of Derived
fail the issubclass(Derived, Base)
or isinstance(derived_obj, Base)
checks (i.e. return False
).
I've tried a number of approaches, but none succeeded:
- Creating a property named
__class__
inDerived
(https://stackoverflow.com/a/42958013/4909228). This can only be used to make the checks returnTrue
. - Overriding the
__instancecheck__
and__subclasscheck__
methods ofBase
. This doesn't work because CPython only calls these methods when conventional checks returnFalse
. - Assigning the
__class__
attribute during__init__
. This is no longer allowed in Python 3.6+. - Making
Derived
subclassobject
and assigning all its attributes and methods (including special methods) to that ofBase
. This doesn't work because certain methods (e.g.__init__
) cannot be called on an instance that is not a subclass ofBase
.
Can this possibly be done in Python? The approach could be interpreter specific (code is only run in CPython), and only needs to target Python versions 3.6+.
To illustrate a potential usage of this requirement, consider the following function:
def map_structure(fn, obj):
if isinstance(obj, list):
return [map_structure(fn, x) for x in obj]
if isinstance(obj, dict):
return {k: map_structure(fn, v) for k, v in obj.items()}
# check whether `obj` is some other collection type
...
# `obj` must be a singleton object, apply `fn` on it
return fn(obj)
This method generalizes map
to work on arbitrarily nested structures. However, in some cases we don't want to traverse a certain nested structure, for instance:
# `struct` is user-provided structure, we create a list for each element
struct_list = map_structure(lambda x: [x], struct)
# somehow add stuff into the lists
...
# now we want to know how many elements are in each list, so we want to
# prevent `map_structure` from traversing the inner-most lists
struct_len = map_structure(len, struct_list)
If the said functionality can be implemented, then the above could be changed to:
pseudo_list = create_fake_subclass(list)
struct_list = map_structure(lambda x: pseudo_list([x]), struct)
# ... and the rest of code should work