¿Es posible copiar correctamente una clase usando el tipo

De acuerdo con esta respuesta , un objeto de clase cls puede ser replicado con

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

Esto funciona perfectamente para la mayoría de los casos normales. No funciona cuando la metaclase de cls no es de type . Mi primera solución ingenua era hacer

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

Sin embargo, esto es simplemente inútil. No hay forma de saber qué hace una metaclase, como lo señala esta respuesta a una pregunta relacionada, cómo transforma el diccionario de entrada, qué palabras clave adicionales requiere, etc.

El uso original del type es casi lo suficientemente bueno con un par de excepciones menores:

  1. El __dict__ creado por las metaclases que no terminan por llamar al type.__new__ puede ser de un tipo diferente al objeto proxy habitual.
  2. Las clases que extiendan la copia no tendrán la metaclase correcta, lo que puede causar un comportamiento inesperado.
  3. Todas las propiedades u otros descriptores de datos definidos en la metaclase original ya no estarán disponibles en el objeto de clase.

Estoy dispuesto a ignorar el artículo # 1. Es un caso de esquina que estoy dispuesto a documentar si encuentro una solución viable para los otros elementos. Los artículos # 2 y # 3 pueden resolverse si fuera posible cambiar la metaclase de la copia. Lo intenté (de nuevo, ingenuamente)

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

Esto acaba de levantar un TypeError , como podría esperarse:

 TypeError: __init_subclass__() takes no keyword arguments 

Esto tiene sentido a la luz de los documentos :

Al igual que su identidad, el tipo de un objeto también es inmutable. 1

Sin embargo, la nota a pie de página dice que

Es posible en algunos casos cambiar el tipo de un objeto, bajo ciertas condiciones controladas. Sin embargo, generalmente no es una buena idea, ya que puede llevar a un comportamiento muy extraño si se maneja incorrectamente.

¿Cuáles son las condiciones bajo las cuales es posible cambiar el tipo de un objeto, específicamente el de una clase? ¿Es este uno de esos casos, y si es así, cómo?

Nota

Soy consciente de que copy.deepcopy y la herencia son alternativas viables aquí. Para el propósito de esta pregunta, deseo ignorar esas alternativas y seguir usando técnicas relacionadas con el type .

Puede usar type.__new__(type(cls), cls.__name__, cls.__bases__, dict(cls.__dict__)) . Esto utiliza el proceso normal de creación de type , pero crea una instancia de type(cls) lugar de type .

En cuanto al tema __metaclass__ , creo que es porque __metaclass__ suele ser lo que se llama, por lo que el type no puede usarlo.