[Python-es] Pregunta sobre diseño de una biblioteca

Juan Luis Cano juanlu001 en gmail.com
Jue Feb 14 12:34:10 CET 2013


Muchas gracias por tus comentarios Chema, voy a responder por trozos a 
un par de cosas:

On 02/13/2013 11:15 PM, Chema Cortes wrote:
>> 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.
> IMHO, es un error que los lenguajes de programación se centren en POO
> en detrimento de otros paradigmas como la programación funcional. Todo
> lo que veo en tus preguntas son conceptos de la programación funcional
> que no sabes encajar dentro de una jerarquía de objetos. Tú tienes
> "fórmulas" y la mejor representación de una fórmula es como una
> "función".

Bueno, en este momento en vez de funciones son básicamente métodos de 
una clase.

> Los principios SOLID los veo difíciles de cumplir sin contar con un
> potente sistema de tipado de datos (y de anotaciones). Supongo que de
> ahí tu comentario de que andas despistado con el "duck typing" de
> python. Reconozco tener cierto escepticismo con este tipo de
> principios. La teoría de tipos está evolucionado tanto últimamente con
> los tipos genéricos y tipos cotravariantes que dejarían a algunos de
> los principios SOLID, si no desfasados, al menos necesitados de
> revisión.
Yo los veo algo útil, pero como dices tú sin un potente sistema de tipos 
es complicado.
>> 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`?
> Las propiedades que dependen de un
> argumento podrían quedar mejor como "funciones currificadas"
> (funciones 'partial' para el módulo 'functools').
No conocía el concepto, he echado un ojo a la documentación y parece 
interesante.
>> 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.
> Es justo lo que te sugería. Una vez encapsulada la ecuación como una
> función, pásala como argumento donde sea necesario. Si no te gusta
> polucionar el espacio de nombres, agrupa las funciones en módulos y
> paquetes. Cambiando un import basta para probar un nuevo conjunto de
> ecuaciones.
No me convence tanto tener ecuaciones agrupadas en módulos o paquetes. 
Al estar derivadas de unas hipótesis y de unas simplificaciones que he 
introducido en mi modelo, y mi modelo está representado por un objeto, 
la idea de que la ecuación sea un método de la clase me convence más.

Otra vez, gracias por tus consejos, los tendré en cuenta en el futuro.


Más información sobre la lista de distribución Python-es