El día 9 de febrero de 2010 18:38, Olemis Lang (Simelix)
<olemis...@gmail.com> escribió:
> 2010/2/9 lasizoillo <lasizoi...@gmail.com>:
>> El día 9 de febrero de 2010 15:52, Olemis Lang (Simelix)
>> <olemis...@gmail.com> escribió:
>>>
>>>>>    - Otro ejemplo, la solución al `case` o `switch` de Python basada en 
>>>>> dict(s)
>>>>>      implica q a cada llave se le asigne algo q, al ejecutarlo, se 
>>>>> realiza lo
>>>>>      q sea específico de esa alternativa. Pasa algo más o menos semejante,
>>>>>      en Python resulta engorroso escribir una función para cada 
>>>>> alternativa,
>>>>>      sin el propósito de reutilizarla (sino solo para suplir una carencia 
>>>>> del
>>>>>      lenguaje) y la legibilidad es pésima, porq todo está separado y
>>>>>      disperso y con un vistazo no se puede tener idea de lo
>>>>>      q pasa. Con bloques inline como los de Ruby se podría mejorar esto.
>>>>>
>>>>
>>>> Si el if/elif/else no te vale, igual si que deberias considerar usar
>>>> funciones separadas :-O
>>>>
>>>
>>> Ok, lo cual sería mucho más legible que algo como (en un Python
>>> Rubizadoribilistizado ;o)
>>>
>
> Realmente debería lucir mejor así
>
> {
>  'k' : do
>          x = 1; y = 2
>        end,
>  'w' : do
>          x = 3; y = 4
>        end,
>  'g' : do
>          x = 5; y = 6
>        end,
>  'xxx' : do
>          x = 7; y = 8
>        end,
> }[variable].execute()

Eso debería pintar así

if variable=='k':
    x=1
    y=2
elif variable=='w':
    x=3
    y=4
elif variable=='g':
    x=5
    y=6
elif variable=='xxx':
    x=7
    y=8

Normalmente, usar un diccionario como dispatcher se suele usar cuando
la llamada y la definición del diccionario no estan juntas. Dos
ejemplos practicos te los puse en el anterior correo:

  * Versión pythonica: http://github.com/breily/juno
  * Versión ruby: http://github.com/bmizerany/sinatra

En ambos crean una descripción de enrutado que enlazan a un bloque de
código (con función encapsulando el bloque de codigo en el caso de
python). Como te dije, para ese caso concreto, ruby si que me parece
más legible y el uso de un diccionario para hacer un switch apropiado.
Como construcción normal del lenguaje me parece incorrecto.

Aunque si somos precisos ambos se registran en una lista en vez de un
diccionario, porque varios paths de urls pueden disparar un mismo
bloque de código. Pero esto son detalles de implementación que no
vienen al caso.

>
> ;o)
>
>> Si viera un código que utilizara eso me cortaria las venas. De pronto
>> me encontraria sorprendido de que me aparezan mágicamente las
>> variables x e y.
>
> Es la misma magia q ocurre si se ejecuta
>
> exec(
>  {
>    'k' : compile('x = 1; y = 2'),
>    'w' : compile('x = 3; y = 4'),
>    'g' : compile('x = 5; y = 6'),
>    'xxx' : compile('x = 7; y = 8')
>  }[variable])
>
> lo q con la ventaja adicional del chequeo de sintaxis, y ser más
> legible (IMO ;o)

De todas formas, recuerda que es una posibilidad disponible, no algo
recomendable ;-)

El if/elif/else es lo más recomendable para hacer algo parecido a un
switch. Para hacer un dispatcher se puede permitir cierta magia
siempre que todo quede documentado :-)

>>> ... verdad ? Si se da cuenta, utilizando funciones tendríamos q hacer
>>> 4 que retornaran una tupla y se le asignaran a x y y. La otra cuestion
>>> es la de los parámetros de esas funciones. Generalmente se necesitan
>>> cosas en el namespace local para utilizarlas dentro del `switch` y
>>> estas hay q pasarlas como parámetros. Claro, se pueden usar las
>>> clausuras, pero reflexionemos todos los conceptos q se han mencionado
>>> y cuan similares son a lo q nosotros pensamos cuando vamos a tomar uno
>>> de varios caminos para tomar una decisión.
>>>
>>
>> El código que se escribe se ha de leer muchas veces. En las
>> revisiones, mejoras, correcciones de bugs, ... Prefiero un código que
>> se tarda unos segundos más en escribirlo y se tarda varios minutos
>> menos en leerlo. Prefiero que uno no se vea tentado a sacrificar esa
>> legibilidad ni en los momentos de peor estrés.
>>
>
> Correcto, q es más legible, el código inline dentro del diccionario o
> el exec (q debe funcionar y es real) con los `compile`s ?
>
> Yo me voy por el primero ;o)

Yo me voy por el if/elif/else. Es mucho más legible, directo y bastante conciso.

Creia que el usar el diccionario era una forma simplicada de hablar de
dispatching más complejo y menos común. Del tipo capistrano vs fabric,
sinatra vs juno, ...

En esos casos excepcionales y solo en esos, si que veo que puede ser
util llevar a python algún oscuro truco de magía negra para hacer una
dsl. Pero lo normal es que no resulte ni necesario, ni ventajoso.

>>> Lo digo porq errores en el código se detectan al compilar hacia .PYC,
>>> mientras que errores dentro de una cadena ejecutada con exec se
>>> detectan al ejecutar la línea de código del exec (i.e. el hecho de q
>>> compile no quiere decir q no está roto ;o). Además, si las
>>> continuaciones son «perjudiciales como el goto», no creo q un exec sea
>>> más beneficioso, considerando que rompe la secuencia precondición,
>>> invariante, postcondición y las buenas prácticas de escritura del
>>> código q plantearon Dijkstra, CAR Hoare et al. basados en modelos como
>>> CSP, o luego DbC, ... Pero bueno, esa meta-tranca no la sigo para no
>>> ponerme demasiado OT
>>>
>>
>> La generación de bytecodes (ficheros .pyc) sólo detecta errores sintácticos.
>>
>
> es de lo q hablo
>
>> 4c4-local:~ lasi$ python kk.py
>> hola
>> m4c4-local:~ lasi$ cat kk.py
>> def kk():
>>    print variable_que_no_existe
>>
>> print "hola"
>> m4c4-local:~ lasi$ pyflakes kk.py
>> kk.py:2: undefined name 'variable_que_no_existe'
>>
>>
>> Usar pyflakes o pylint es mejor ;-)
>>
>
> ... pero eso no analiza las cadenas de los exec, eval & co. ¿o sí?
>

Ni falta que hace. Porque lo normal es que los exec sean totalmente
innecesarios para el 99.99% de los casos. A lo que quería apuntar es
que la generación del bytecode es una prueba muy mala de que algo esté
bien. La cantidad de errores que se le escapan al "compilador" de
python (o cualquier otro dinámico) es brutal. En el otro extremo están
pyflakes o pylint a los que se les pueden escapar cosas o darte falsos
positivos.

>
>> Yo personalmente no la deseo si el
>> precio a pagar puede ser la perdida de legibilidad.
>>
>
> ¿En q sentido se pierde la legibilidad?
>

Muchas veces, los blocks de ruby se usan para hacer cosas que se
pueden hacer con un with de python. En ambos casos es igual de conciso
y legible. Es más, diría que incluso recomendable.

No veo qué se puede hacer con un bloque de ruby que no se pueda hacer
con una función (inline si es necesario). Y no se me ocurren casos
donde la perdida de legibilidad por no usarlos sea notable (como por
ejemplo en juno y sinatra).

Un claro ejemplo de perdida de legibilidad por el uso de bloques sería
tu propuesta de usarlos para hacer un simple switch, en vez de usar la
estructura if/elif/else :-P
_______________________________________________
Python-es mailing list
Python-es@python.org
http://mail.python.org/mailman/listinfo/python-es
FAQ: http://python-es-faq.wikidot.com/

Responder a