En Python, decir que tengo algunos de la clase, Círculo, que se hereda de Forma. Forma las necesidades de x e y las coordenadas, y, además, el Círculo de las necesidades de un radio. Quiero ser capaz de inicializar Círculo por hacer algo como,

c = Circle(x=1., y=5., r=3.)

Círculo hereda de forma, así que hay que utilizar argumentos con nombre para __init__, debido a que las diferentes clases requieren de diferentes constructores. Yo podría establecer manualmente x, y, y r.

class Shape(object):
    def __init__(self, **kwargs):
        self.x = kwargs['x']
        self.y = kwargs['y']

class Circle(Shape):
    def __init__(self, **kwargs):
        super(Circle, self).__init__(**kwargs)
        self.r = kwargs['r']

o, podría tener los atributos de mi Círculo de forma automática utilizando self.__dict__.update(kwargs)

class Shape(object):
    def __init__(self, **kwargs):
        self.__dict__.update(**kwargs)

class Circle(Shape):
    def __init__(self, **kwargs):
        super(Circle, self).__init__(**kwargs)

La ventaja de esto es que hay menos código y no tengo la necesidad de mantener repetitivo como self.foo = kwargs['foo']. La desventaja es que no es obvio que los argumentos son necesarios para el Círculo. Es esta considerado una estafa o es este un buen estilo (siempre y cuando la interfaz para que el Círculo está bien documentado)?


Gracias a todos por sus respuestas bien pensadas. El self.__dict__.update(**kwargs) hack ha sido útil para mí en la experimentación con la organización de mi código, pero me aseguraré de que me sustituir adecuadamente a pasar argumentos explícitamente y haciendo evidente la comprobación de errores en el código de producción.

4 Comentarios

  1. 25
    class Shape(object):
        def __init__(self, x=None, y=None):
            self.x = x
            self.y = y
    
    class Circle(Shape):
        def __init__(self, r=None, **kwargs):
            super(Circle, self).__init__(**kwargs)
            self.r = r

    Y eso es todo. No utilice **kwargs cuando no es realmente necesario.

    Es esta considerado una estafa o es este un buen estilo (siempre y cuando el
    interfaz Círculo está bien documentado)?

    Cuando usted tiene una opción entre la escritura de una forma sencilla, comprensible y dolor de cabeza código + niza docstrings, que en realidad no tienen ninguna preferencia, usted sólo tiene que ir y escribir simple, auto-documentado código:)

    • hay un montón de perfectamente razonable veces a utilizar **cualquiera que sea especialmente cuando se sobrecarga otras clases
    • Haga clic de nuevo para deshacer.
    • Donde se self?
    • Sí, yo tenía un relleno que algo está perdido:)
    • Para esta solución, ser conscientes de que todas las clases en esta cadena de herencia no tiene acceso a los valores de palabra clave que son despojadas de **kwargs de esta manera (en el niño de las clases). Por ejemplo, la Forma no puede definir un r parámetro y esperar para obtener de ella, sin necesidad de modificar el __init__ método de Círculo.
    • Yo prefiero esta solución, ya que me impide tener que mencionar x explícitamente en cada __init__() todo el camino hacia abajo de la jerarquía de clase, asegurándose de que los argumentos de derecho están presentes en el nivel adecuado.

  2. 17

    Yo diría que el primer método es sin duda preferible, porque explícito es mejor que implícita.

    Considerar qué pasaría si usted cometió un error al inicializar un Círculo, algo así como Circle(x=1., y=5., rr=3.). Quieres ver este error inmediatamente, lo cual no sucedería con __dict__.update(kwargs).

  3. 10

    Si desea asignar automáticamente, sugiero el siguiente enfoque:

    def __init__(self, **kwargs):
        for key, value in kwargs.iteritems():
            setattr(self, key, value)

    que, en términos de estilo, está en algún lugar entre la escritura de manera explícita y hacking tú mismo usando self.__dict__.

    • Me gustaría mucho más ver self.__dict__.update(kwargs) que esto (probablemente menos eficaz y más), de manera de lograr el mismo resultado.
    • Esto tendría la ventaja de trabajar con los descriptores. Trabajando directamente con __dict__ es una mala idea, por esa sola razón.
    • Me podrían ayudar a entender por qué esto funciona mejor con los descriptores?
    • A mi entender, después de leer docs.python.org/3/howto/descriptor.html , es que Chris Morgan (~2) es la promoción de Simeón respuesta, ya que podría funcionar mejor con clases BASADAS en su clase que no superan el valor predeterminado métodos get/set y por lo tanto se convierten en los datos de los descriptores. El uso de setattr sería compatible con sus olas, mientras que el uso de la dict directamente y pasar por alto cualquiera de tales modificaciones.
  4. 3

    Si quería ser más obvia podría tener Circle.__init__ realizar algunas comprobaciones de validez de los argumentos. Es de suponer que usted había asegúrese de que todos los argumentos están ahí, y, posiblemente, aumentar los errores de argumentos sin sentido.

    Probablemente usted podría incluso hacer un decorador o función auxiliar en Shape a hacer esto para usted. Algo como esto:

    class Circle(Shape):
        def __init__(self, **kwargs):
            self.check(kwargs, 'x', 'y', 'r')
            super(Circle, self).__init__(**kwargs)

    .check se llevaría a cabo en Shape y, esencialmente, sólo verifica que todos los argumentos en kwargs, y posiblemente el que supletorias no son (lo sentimos, no hay código para que uno se puede averiguar por su cuenta). Usted podría incluso tener subclases de sobrecarga, se compruebe que los argumentos opcionales, puede que desee para manejar de manera diferente que el resto de los argumentos (es decir, darles un valor predeterminado que no vuelva a ser asignado en Shape.__init__.

    De lo contrario, si el documento en su interfaz, y funciona de la manera en que está documentado, es siempre bien. Cualquier otra cosa que hacer para que funcione de la manera de «esperar» a (lanzando excepciones para los argumentos incorrectos) es un bono.

    • ¿Cómo sabe usted que «.check se implementa en Shape«. Eres el OP del maestro?
    • Yo iba a ser el más joven profesor de informática que nunca si era yo. Lo que quiero decir es que el OP se podría implementar Shape.check y, a continuación, utilizar en todas las subclases. Voy a aclarar eso.

Dejar respuesta

Please enter your comment!
Please enter your name here