Is it possible to correctly copy a class using type

According to this answer, an object of class cls can be replicated using

 cls_copy = type('cls_copy', cls.__bases__, dict(cls.__dict__)) 

This works great for most common cases. It does not work if the metaclass cls not type . My initial naive decision was to make

 cls_copy = type(cls)('cls_copy', cls.__bases__, dict(cls.__dict__)) 

However, this is simply pointless. It is impossible to find out what the metaclass does, how this answer , the related question indicates how it converts the input dictionary, what additional keywords it requires, etc.

The original use of type pretty good enough with a few minor exceptions:

  • __dict__ created by metaclasses that do not end with a call to type.__new__ may be of a different type than a regular proxy object.
  • Classes that extend the copy will not have the correct metaclass, which may cause unexpected behavior.
  • Any properties or other data descriptors defined in the source metaclass will no longer be available for the class object.

I am ready to ignore element number 1. This is a corner case when I am ready to document whether I should find a viable solution for other subjects. Elements No. 2 and No. 3 can be resolved if possible to change the metaclass of the copy. I tried (again, naive)

 cls_copy = type('cls_copy', cls.__bases__, dict(cls.__dict__), metaclass=type(cls)) 

This just raised a TypeError , as you would expect:

 TypeError: __init_subclass__() takes no keyword arguments 

This makes sense in the light of the docs :

Like its identifier, the type of objects is also immutable. 1

However, footnote states that

In some cases, it is possible to change the type of objects in certain controlled conditions. This is not a good idea at all, though, since it can lead to some very strange behavior if it is handled incorrectly.

What are the conditions under which you can change the type of an object, in particular a class? This is one of these cases, and if so, how?

Note

I know that copy.deepcopy and inheritance are viable alternatives here. For the purposes of this question, I want to ignore these alternatives and stick to type methods.

+5
source share
1 answer

You can use type.__new__(type(cls), cls.__name__, cls.__bases__, dict(cls.__dict__)) . This uses the normal process of creating type , but instantiates type(cls) instead of type .

Regarding the __metaclass__ problem, I think this is because __metaclass__ usually called the so-called, so type cannot use it.

+4
source

Source: https://habr.com/ru/post/1275764/


All Articles