2009-02-28 13 views
16

Digamos que tengo una función de biblioteca que no puedo cambiar que produce un objeto de clase A, y he creado una clase B que hereda de A.¿Convertir un objeto en una subclase en Python?

¿Cuál es la forma más directa de usar la función de biblioteca para producir un objeto de clase B?

Editar- me pidieron en un comentario para más detalle, así que aquí va:

PyTables es un paquete que se encarga de conjuntos de datos jerárquicos en Python. El bit que más uso es su capacidad para administrar datos que están parcialmente en el disco. Proporciona un tipo 'Array' que solo viene con slicing extendido, pero necesito seleccionar filas arbitrarias. Numpy ofrece esta capacidad: puede seleccionar proporcionando una matriz booleana de la misma longitud que la matriz que está seleccionando. Por lo tanto, quería subclase Array para agregar esta nueva funcionalidad.

En un sentido más abstracto, este es un problema que he considerado anteriormente. La solución habitual es la que ya se ha sugerido: tener un constructor para B que toma una A y argumentos adicionales, y luego saca los bits relevantes de A para insertar en B. Como parecía un problema bastante básico, pregunté para ver si había soluciones estándar de las que no tenía conocimiento.

+0

Podría añadir más detalles acerca de por qué usted quiere hacer ¿esta? – Kiv

Respuesta

13

Como la función de biblioteca devuelve una A, no puede hacer que devuelva una B sin cambiarla.

Una cosa que puede hacer es escribir una función para llevar a los campos de la A instancia y copiarlas en una nueva instancia B:

class A: # defined by the library 
    def __init__(self, field): 
     self.field = field 

class B(A): # your fancy new class 
    def __init__(self, field, field2): 
     self.field = field 
     self.field2 = field2 # B has some fancy extra stuff 

def b_from_a(a_instance, field2): 
    """Given an instance of A, return a new instance of B.""" 
    return B(a_instance.field, field2) 


a = A("spam") # this could be your A instance from the library 
b = b_from_a(a, "ham") # make a new B which has the data from a 

print b.field, b.field2 # prints "spam ham" 

Editar: dependiendo de su situación, composición en lugar de la herencia podría ser una buena apuesta; esa es su clase B podría contener una instancia de A en lugar de heredar:

class B2: # doesn't have to inherit from A 
    def __init__(self, a, field2): 
     self._a = a # using composition instead 
     self.field2 = field2 

    @property 
    def field(self): # pass accesses to a 
     return self._a.field 
    # could provide setter, deleter, etc 

a = A("spam") 
b = B2(a, "ham") 

print b.field, b.field2 # prints "spam ham" 
+3

Los objetos de Python conocen su clase configurando el atributo '.__ class__'. De hecho, puede establecerlo en otra cosa: http://stackoverflow.com/a/29256784/1423333 –

+0

Estoy votando mediante @propiedad para extraer los datos de self._a. La composición se presta a escribir métodos puros que son mucho más fáciles de probar.La herencia NO es incorrecta y realmente depende de tu caso de uso. Pero mi experiencia dice que la composición tiende a ser más fácil de tratar a largo plazo. – srock

1

Monkeypatch la biblioteca?

Por ejemplo,

import other_library 
other_library.function_or_class_to_replace = new_function 

Poof, devuelve lo que quiera que vuelva.

Monkeypatch A. nuevo para devolver una instancia de B?

Después de llamar obj = A(), cambie el resultado tan obj. clase = B?

15

Esto se puede hacer si el inicializador de la subclase puede manejarlo, o si escribe una mejora explícita. A continuación se muestra un ejemplo:

class A(object): 
    def __init__(self): 
     self.x = 1 

class B(A): 
    def __init__(self): 
     super(B, self).__init__() 
     self._init_B() 
    def _init_B(self): 
     self.x += 1 

a = A() 
b = a 
b.__class__ = B 
b._init_B() 

assert b.x == 2 
3

en realidad se puede cambiar el atributo del objeto .__class__si sabes lo que estás haciendo:

In [1]: class A(object): 
    ...:  def foo(self): 
    ...:   return "foo" 
    ...: 

In [2]: class B(object): 
    ...:  def foo(self): 
    ...:   return "bar" 
    ...: 

In [3]: a = A() 

In [4]: a.foo() 
Out[4]: 'foo' 

In [5]: a.__class__ 
Out[5]: __main__.A 

In [6]: a.__class__ = B 

In [7]: a.foo() 
Out[7]: 'bar' 
Cuestiones relacionadas