Agregar una clase base a un objeto existente en Python

Tengo varios objetos de diferentes tipos (diferentes nombres de funciones, diferentes firmas) y los parcheo para tener una forma común de acceder a ellos desde diferentes funciones. Brevemente, hay un distribuidor que toma los objetos que quiero parchear y, según el tipo de objeto, llama a un parcheador diferente. Un parche agregará métodos al objeto:

def patcher_of_some_type(object): def target(self, value): # do something and call self methods object.target = types.MethodType(target, object) # many more of these 

A medida que el progtwig se vuelve más complicado, hacer una envoltura alrededor del objeto (o la clase de objeto) parece ser una mejor idea. Algunos parches comparten código común o están interrelacionados. Pero no controlo la creación de objetos, ni la creación de clases. Solo consigo los objetos. E incluso si pudiera hacer eso, solo quiero envolver (o parchar) ciertos objetos, no todos.

Una solución podría ser agregar una clase base a un objeto existente, pero no estoy seguro de qué tan fácil y seguro sea. ¿Hay otra solución?

La modificación dinámica del tipo de un objeto es razonablemente segura, siempre que la clase base adicional sea compatible (y obtendrá una excepción si no lo es). La forma más sencilla de agregar una clase base es con el constructor de type 3 argumentos:

 cls = object.__class__ object.__class__ = cls.__class__(cls.__name__ + "WithExtraBase", (cls, ExtraBase), {}) 

Basado en un comentario en otra respuesta, esta es otra manera de parchear la clase base:

 class Patched(instance.__class__, ExtraBase): pass instance.__class__ = Patched 

Para agregar una clase a otra base de clases, podrías hacer algo como esto:

 def pacher_of_some_type(object): #this class holds all the stuff you want to add to the object class Patch(): def target(self, value): #do something #add it to the class' base classes object.__class__.__bases__ += (Patch, ) 

Pero esto afectará a TODOS los objetos de esta clase, ya que realmente cambia la clase en sí misma, que no parece ser lo que desea … si solo desea parchear una Instancia, puede crear una subclase de la clase original y cambiar la clase de instancias. dinamicamente:

 class PatchedClass(object.__class__): def target(self, value): #do whatever object.__class__ = PatchedClass 

En términos de seguridad y capacidad de administración, diría que agregar dinámicamente una clase base es tan fácil de mantener como agregar dinámicamente algunas funciones, y más seguro porque es menos probable que sobrescriba accidentalmente algunas funciones internas de la clase original porque se agrega la nueva clase base hasta el final de la tupla, lo que significa que se usa por última vez para la resolución de nombres. Si realmente desea sobrescribir los métodos, agréguelos al principio de la tupla de clases base (por supuesto, esto no se aplica al enfoque de subclase). No me preguntes si es seguro cambiar dinámicamente la clase de una instancia, pero en un ejemplo trivial no parece haber problema:

 class A(): def p(self): print 1 class B(): def p(self): print 2 a = A() ap() #prints 1 a.__class__ = B ap() #prints 2