2010-02-07 11 views
18

tengo una clase:evitar especificar todos los argumentos en una subclase

class A(object): 
    def __init__(self,a,b,c,d,e,f,g,...........,x,y,z) 
     #do some init stuff 

Y tengo una subclase que necesita un extra arg (el último W)

class B(A): 
    def __init__(self.a,b,c,d,e,f,g,...........,x,y,z,W) 
     A.__init__(self,a,b,c,d,e,f,g,...........,x,y,z) 
     self.__W=W 

Parece tonto para escribir todo el código de la caldera de la placa, por ejemplo, pasando todos los argumentos de B 's ctor a la llamada interior a A' s ctor, desde entonces, cada cambio en A 's ctor debe ser aplicado a otros dos lugares en B' código de s.

estoy adivinando Python tiene algún modismo para manejar estos casos los que soy consciente de. ¿Me puede apuntar en la dirección correcta?

Mi mejor presentimiento, es tener una especie de copia-Ctor para A y luego cambiar el código de B en

class B(A): 
    def __init__(self,instanceOfA,W): 
     A.__copy_ctor__(self,instanceOfA) 
     self.__W=W 

Esto se adapte a mis necesidades ya que siempre se crea la subclase cuando se les da una instancia del padre clase, aunque no estoy seguro de si es posible ...

+0

Si usted tiene que muchos argumentos, no usarían argumentos posicionales, pero tener a todos ellos/la mayoría de ellos como kwargs y use la sintaxis py3 '*' 'def __initi __ (arg1, arg2, * kwarg1 = ..., ..., kwargx = ..., w = ...) 'para forzar kwargs (= no confíe en el orden). Usar 'def __init __ (self, arg1, arg2, *, ** kwargs)' es más corto, pero no me gusta porque es un error completar el código en IDEs como pycharm. Aparte de perder un poco de pantalla, ¿cuál es el daño al escribir todos los kwargs? De todos modos, tendría que documentarlos todos en la docstring ... –

Respuesta

17

Teniendo en cuenta que los argumentos se podrían pasar por su nombre o por su posición, me gustaría código:

class B(A): 
    def __init__(self, *a, **k): 
     if 'W' in k: 
     w = k.pop('W') 
     else: 
     w = a.pop() 
     A.__init__(self, *a, **k) 
     self._W = w 
+0

Me gusta esta idea, pero no creo que el ejemplo funcione. Como '* a' causa' a' a [recibir ** tupla **] (http://docs.python.org/tutorial/controlflow.html?highlight=kwargs#keyword-arguments), 'a' doesn ' t tiene el método 'pop()'. 'a' necesita convertirse primero en una lista. Además, si todos los argumentos se pasan por nombre, 'a' está vacío (por lo tanto, no puede' pop() '). –

+0

Er, no importa la última frase de mi comentario anterior. –

+1

'AttributeError: el objeto 'tuple' no tiene ningún atributo 'pop'' –

0

¿usted está queriendo algo como esto?

class A(object): 
    def __init__(self, a, b, c, d, e, f, g): 
     # do stuff 
     print a, d, g 

class B(A): 
    def __init__(self, *args): 
     args = list(args) 
     self.__W = args.pop() 
     A.__init__(self, *args) 
+0

, esto funciona para la versión muy simplificada. Pero ahora B toma cualquier cantidad de args (menos confinamiento) ... ¿No hay algo más idiomático? – olamundo

+1

B solo toma un número de argumentos; llama a A y si A obtiene el número equivocado, levantará 'TypeError'. Usted podría verificar explícitamente la cantidad de argumentos si lo desea. Probablemente lo haría en el código de producción. –

+0

Si encuentra una cantidad incorrecta de argumentos, usted levantaría un TypeError usted mismo de todos modos. – Dinoboff

7

Editar: basado en la sugerencia de Matt, y para abordar la inquietud de gnibbler, se trata de un enfoque posicional; usted puede comprobar para asegurarse de que el argumento adicional específico de subclase se está especificando-similar a Alex's answer:

class B(A): 
    def __init__(self, *args, **kwargs): 
    try: 
     self._w = kwargs.pop('w') 
    except KeyError: 
     pass 
    super(B,self).__init__(*args, **kwargs) 

>>> b = B(1,2,w=3) 
>>> b.a 
1 
>>> b.b 
2 
>>> b._w 
3 

Respuesta original:
La misma idea que Matt's answer, utilizando super() lugar.

Uso super() llamar al método de superclase __init__(), y luego continuar la inicialización de la subclase:

class A(object): 
    def __init__(self, a, b): 
    self.a = a 
    self.b = b 

class B(A): 
    def __init__(self, w, *args): 
    super(B,self).__init__(*args) 
    self.w = w 
+0

Esta solución requiere que w se pase como primer arg o por nombre. La pregunta es como el último argumento –

+0

@gnu: gracias por tu comentario. He editado mi respuesta para abordar esta preocupación; similar a lo que Alex publicó hace muchas horas :-) – bernie

2

En situaciones donde algunos o todos los argumentos pasados ​​a __init__ tienen valores predeterminados, puede ser útil evitar repetir la firma del método __init__ en subclases.

En estos casos, __init__ puede pasar argumentos adicionales a otro método, que las subclases pueden anular:

class A(object): 
    def __init__(self, a=1, b=2, c=3, d=4, *args, **kwargs): 
     self.a = a 
     self.b = b 
     # … 
     self._init_extra(*args, **kwargs) 

    def _init_extra(self): 
     """ 
     Subclasses can override this method to support extra 
     __init__ arguments. 
     """ 

     pass 


class B(A): 
    def _init_extra(self, w): 
     self.w = w 
Cuestiones relacionadas