[Python-es] Pregunta sobre diseño de una biblioteca
Juan Luis Cano
juanlu001 en gmail.com
Mie Feb 13 17:12:03 CET 2013
No suelo preguntar nada en esta lista, pero hoy me gustaría plantearos
una cuestión un poco abierta a la que llevo dando vueltas algunos meses.
No tengo una formación reglada en programación así que me gustaría
recabar algunas ideas sobre cómo llevar a cabo este diseño
DeLaManeraCorrecta™. Os cuento (aviso de que es un email largo, un poco
denso, posiblemente incomprensible y con algún tecnicismo):
Estoy escribiendo una biblioteca llamada scikit-aero para cálculos
comunes en ingeniería aeronáutica con Python.
https://github.com/Pybonacci/scikit-aero
Uno de los módulos es de dinámica de gases. Y uno de los «objetos» que
he definido es `IsentropicFlow`, que representa un flujo con unas
determinadas características. Tiene varias propiedades, que se pueden
obtener con expresiones matemáticas definidas en los métodos:
https://github.com/Pybonacci/scikit-aero/blob/master/skaero/gasdynamics/isentropic.py#L65
Al definir un `IsentropicFlow` especifico todas las variables que lo
determinan *unívocamente*, y de ahí obtengo las propiedades.
Me surgen dos preguntas:
1. (Menos importante) Cada vez que quiero una propiedad de uno de estos
objetos la calculo con la fórmula matemática y la devuelvo. Por ejemplo,
defino un `IsentropicFlow` y puedo obtener de él ciertas propiedades en
función de otro argumento `M`, el número de Mach incidente.
Pero aquí tengo otro ejemplo, los objetos `NormalShock`, que representan
ondas de choque:
https://github.com/Pybonacci/scikit-aero/blob/master/skaero/gasdynamics/shocks.py#L22
donde las propiedades vienen determinadas por las variables que definen
el `NormalShock`, nada más.
*Pregunta*: Si no dependen de argumentos extra, ¿tal vez sería mejor
calcularlas en `__init__`, almacenarlas y simplemente devolver los
valores cuando se pidan? Si es así, ¿hasta qué punto tiene sentido
definir una clase, cuando prácticamente podría conseguir lo mismo
utilizando un diccionario, o un `namedtuple`?
2. (Más importante) Digamos que otro tipo de objetos, `ObliqueShock`
(ondas de choque oblicuas) vienen caracterizados por dos variables: `M`
(número de Mach incidente) y `beta` (ángulo de la onda de choque).
Definido un `ObliqueShock`, puedo obtener su ángulo de deflexión
correspondiente, `theta`, a través de una relación matemática. Sin
embargo si conozco `M` y `theta`, esa relación se tiene que resolver
iterativamente para hallar `beta`, y además hay dos valores posibles
entre los que tengo que discriminar.
Como me interesa, por motivos prácticos, disponer de una manera de
instanciar `ObliqueShock` dados `M` y `theta`, mi aproximación al
problema ha sido crear una función que:
* Recibe como argumentos `M`, `theta` y un argumento booleano que
discrimina entre las dos soluciones posibles.
* Comienza un proceso iterativo: construye un `ObliqueShock` con `M`
dado y `beta` cualquiera; si el `theta` resultante es el dado, devuelvo
ese `ObliqueShock`, en caso contrario sigo iterando.
Una idea parecida está recogida en la función `mach_from_area_ratio`:
https://github.com/Pybonacci/scikit-aero/blob/master/skaero/gasdynamics/isentropic.py#L25
que itera sobre un `IsentropicFlow`.
*Pregunta*: ¿esto va bien? Supongo que sería una idea tipo «factoría» de
clases. La razón del embrollo es no escribir la misma ecuación «fuera» y
«dentro» de la clase, teniendo así que repetir código.
Estoy muy interesado en los principios SOLID y en intentar escribir
código POO de buena calidad pero no parece haber mucho material
disponible en la red y por otro lado sin una orientación a objetos
«purista» no me resulta tan sencillo. Cuando programaba en ActionScript
3 hacía y deshacía con interfaces, encapsulación, herencia... ahora
Python y su «duck typing» me despistan un poco en este sentido.
Espero no haber aburrido a nadie más de la cuenta, si hacen falta más
aclaraciones sobre lo anterior las daré gustoso y si alguien tiene
comentarios sobre esto o sobre otros aspectos del código de scikit-aero
estaría enormemente agradecido de recibirlos.
Un saludo,
Juan Luis Cano
Más información sobre la lista de distribución Python-es