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
Derivedsubclassobjectand 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