python - data - Es self.__ dict__. Update(** kwargs) ¿estilo bueno o pobre?
models python (4)
En Python, digamos que tengo una clase, Circle, que hereda de Shape. La forma necesita coordenadas xey, y, además, el círculo necesita un radio. Quiero ser capaz de inicializar Circle haciendo algo como,
c = Circle(x=1., y=5., r=3.)
El círculo hereda de la forma, así que necesito usar argumentos con nombre para __init__
, porque diferentes clases requieren diferentes constructores. Podría configurar 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 bien, podría tener los atributos de mi Círculo establecido automáticamente usando 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 es necesario mantener una self.foo = kwargs[''foo'']
como self.foo = kwargs[''foo'']
. La desventaja es que no es obvio qué argumentos son necesarios para Circle. ¿Esto se considera un truco o es este buen estilo (siempre que la interfaz con Circle esté bien documentada)?
Gracias a todos por sus respuestas reflexivas. 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 lo reemplace self.__dict__.update(**kwargs)
adecuadamente de los argumentos explícitamente y haciendo un claro chequeo de errores en el código de producción.
Diría que el primer método es definitivamente preferible, porque explícito es mejor que implícito .
Considere lo que sucedería si hiciera un error tipográfico al inicializar un Círculo, algo así como Circle(x=1., y=5., rr=3.)
. Desea ver este error inmediatamente, lo que no sucedería con __dict__.update(kwargs)
.
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 escribirlo explícitamente y piratearlo tú mismo usando self.__dict__
.
Si quisiera que fuera más obvio, podría hacer que Circle.__init__
realice algunos controles de cordura en los argumentos. Es de suponer que usted verificará para asegurarse de que todos los argumentos están ahí, y posiblemente plantee errores para argumentos sin sentido.
Incluso podría hacer que un decorador o una función auxiliar en Shape
hagan esto por usted. Algo como esto:
class Circle(Shape):
def __init__(self, **kwargs):
self.check(kwargs, ''x'', ''y'', ''r'')
super(Circle, self).__init__(**kwargs)
.check
se implementaría en Shape
y básicamente solo verificaría que todos los argumentos están en kwargs
, y posiblemente que no existan otros (lo siento, no hay código para eso; puedes averiguarlo por tu cuenta). Incluso podría tener sobrecargas de subclases para verificar argumentos opcionales, que es posible que desee manejar de forma diferente que otros argumentos (es decir, darles un valor predeterminado que de otro modo no se asignaría en Shape.__init__
.
De lo contrario, si documenta su interfaz y funciona de la manera en que está documentada, siempre estará bien. Cualquier otra cosa que hagas para que funcione de la manera en que "lo esperamos" (lanzando excepciones por argumentos incorrectos) es una ventaja.
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 esto es todo. No use **kwargs
cuando realmente no los necesite.
¿Esto se considera un truco o es este buen estilo (siempre que la interfaz con Circle esté bien documentada)?
Cuando tienes que elegir entre escribir un código simple y comprensible y un código de dolor de cabeza + buenas cadenas de documentos, en realidad no tienes opciones, solo tienes que escribir un código simple y auto-documentado :)