According to this answer, a class object cls
can be replicated with
cls_copy = type('cls_copy', cls.__bases__, dict(cls.__dict__))
This works perfectly for most normal cases. It does not work when the metaclass of cls
is not type
. My initial naive fix was to do
cls_copy = type(cls)('cls_copy', cls.__bases__, dict(cls.__dict__))
However, this is simply pointless. There is no way to know what a metaclass does, as this answer to a related question points out, how it transforms the input dictionary, what additional keywords it requires, etc.
The original use of type
is almost good enough with a couple of minor exceptions:
__dict__
created by metaclasses that do not end up calling type.__new__
may be of a different type than the usual proxy object.I am willing to ignore item #1. It is a corner case that I am willing to document away should I find a viable solution to the other items. Items #2 and #3 can be solved if it were possible to change the metaclass of the copy. I tried (again, naively)
cls_copy = type('cls_copy', cls.__bases__, dict(cls.__dict__),
metaclass=type(cls))
This just raised a TypeError
, as could be expected:
TypeError: __init_subclass__() takes no keyword arguments
This makes sense in light of the docs:
Like its identity, an object’s type is also unchangeable. 1
However, the footnote states that
It is possible in some cases to change an object’s type, under certain controlled conditions. It generally isn’t a good idea though, since it can lead to some very strange behaviour if it is handled incorrectly.
What are the conditions under which it is possible to change an object's type, specifically that of a class? Is this one of those cases, and if so, how?
Note
I am aware that copy.deepcopy
and inheritance are viable alternatives here. For the purpose of this question, I wish to ignore those alternatives and stick with using type
-related techniques.
You could use type.__new__(type(cls), cls.__name__, cls.__bases__, dict(cls.__dict__))
. This uses the normal type
creation process, but creates an instance of type(cls)
instead of type
.
As for the __metaclass__
issue, I think that is because __metaclass__
is usually what is called, so type
can't use it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With