El día 9 de febrero de 2010 15:52, Olemis Lang (Simelix) <olemis...@gmail.com> escribió: > Antes q todo, por lo menos mi intención no es comenzar un flamewar, > sino analizar las potencialidades, facilidades o como quiera q le > llamemos de ambos lenguajes . Aclaro q prefiero Python, pero q también > me gusta Ruby ;o) >
Claro, estamos hablando de gustos personales. Todo lo que se pueda aprender bienvenido sea. > 2010/2/9 lasizoillo <lasizoi...@gmail.com>: >> El día 9 de febrero de 2010 14:09, Olemis Lang (Simelix) >> <olemis...@gmail.com> escribió: >>> Solo una precisión ;o) >>> >> - Pero los bloques no se limitan necesariamente a eso. >>> - Por ejemplo, >>> en el caso de IO asíncrona muy frecuentemente se utilizan >>> callbacks. En Python la única solución es escribir una >>> función o «clase invocable» (i.e. callable) y pasarla como parámetro >>> a alguna función o mecanismo de registro q tenga la API. >>> Esto puede ser engorroso. En Ruby los casos sencillos pueden >>> ser descritos con un bloque de código inline y queda más legible >>> y menos «verbose» (más conciso). >> >> #Asi a ojo y sin probar >> >> def block(code): >> def inner(): >> exec code >> return inner >> >> cosa_asincrona.register(block("print 'no es para tanto'")) >> otra_cosa.register(block(""" >> for i in range(10): >> print 'no volvere a copiar en clase' >> """)) >> >> No lo he probado porque soy feliz definiendo funciones para las >> llamadas asincronas. > > Sería curioso saber si cuando Ud lo ejecuta le funciona. Pongamos el > ejemplo de cuando se hace el exec en un módulo con una cadena definida > en otro, digamos porq Ud ofrece `block` en un módulo y especifica lo q > hay q hacer en otro. En este caso el namespace global no coincide con > el q Ud espera y entonces solo obtendrá un `NameError` tras otro y > tendrá que apelar al `stack` para saber de dónde lo llamaron y, y ... > y ya no sería tan simple (o podríamos forzar al cliente de la librería > a estar declarando `block` en cada módulo q él haga, y si cambia algo > en el framework, como hay gran dispersión del código «scattering», y > como eso es casi el anti patrón más malo en la ingeniería de software, > el mantenimiento del código no será nada divertido). E.g. me viene a > la mente esto porq me sucedió con CASPy cuando declaraba «inline > assertions». > Bastaria con pasarle los globals() y locals() al codigo a ser probado: http://docs.python.org/reference/simple_stmts.html#the-exec-statement > De todas formas no estoy en contra de un estilo ni de otro, solo q > IMO, los bloques inline podrían aportar legibilidad en algunos casos > ;o). Estoy de acuerdo en que es una cuestión de estilo. Pero para mi un estilo explicito es más conveniente para un lenguaje, aunque puede resultar feo para las cosas creadas con un framework. > ¿Qué es más legible? (ambos ejemplos escritos a la carrera y sin > probar ;o) : > > {{{ > #!python > > # Antes de 2.7 > class TestCase > def _helper_method(self, x, b=33, c=12) > x = 0 > x = b + c / x > > def test_xxx(self): > self.assertRaises(ZeroDivisionError, self._helper_method, 1, c=4) > }}} > > {{{ > #!python > > # Para 2.7 > class TestCase > def test_xxx(self): > with self.assertRaises(ZeroDivisionError): > x = 0 > x = 33 + 4 / x > }}} > Está claro que el with es más cómodo que hacer una función inline (para un único caso se suelen usar funciones inline) para un único caso. Pero tan poco es tan raro de ver que un test usa una función que reutiliza algo de código: http://bitbucket.org/neithere/pyrant/src/tip/nose_tests/test_query.py#cl-329 > > Mi opinión es q las funciones surgieron, fundamentalmente, como un > mecanismo de reutilización. Que puedan ser utilizadas para sustituir > carencias del lenguaje, es válido, pero todavía las carencias están > ahí > Yo no veo carencia en el tema de bloques en python. Quizá es que no conozca los bloques de ruby. Pero por lo que he podido ver solo tienen dos ventajas: * Azucar sintáctico: Te ahorras una o dos lineas de código a la hora de no tener que escribir una función inline. Parecido al tema de querer cargarse las funciones lambda porque no son necesarias. * Algunas cosas pueden resultar más legibles: * Versión pythonica: http://github.com/breily/juno * Versión ruby: http://github.com/bmizerany/sinatra/ La versión de ruby es algo más concisa que la pythonica. Pero no veo nada más allá de azucar sintactico. > >>> - 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) > > { > '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, > } > 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. Recuerda que estarías invocando a una función devuelta por un diccionario que puede estar definido muy lejos de donde se está usando. Donde algunos ven carencias, yo veo una feature del lenguaje. Esa feature es como la de impedir asignaciones en un if. > ... 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. > >>> Claro, q en todos estos casos se pudiera utilizar un objeto de typo >>> `code`, la función `compile`, o `exec`, pero el efecto no es el mismo >>> ... IMO >> >> ¿Por el coloreado de sintaxis en el editor? >> > > No, de hecho no uso nada eso, todo lo programo con VIm sin colorcitos :P :sy on Es lo que yo uso en vim para que me sea incluso más fácil de leer el código python. Ese código que aunque escribí hace tiempo tengo que leer una y otra vez ;-) > > 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. 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 ;-) > >> Creo que esto se empieza a perecer a una lucha dialectica entre si la >> tortilla de patata está más buena con cebolla o sin ella :-P > > Puede ser q ese sea el camino q otros quieran darle a la conversación, > yo solo quiero explorar y análizar las capacidades del lenguaje > tratando de estar lo menos prejuiciado posible por el hecho de q me > gusta, para así poder ser medianamente objetivo y 30% acertado, y > tener bien claro cómo es posible mejorarlo ;o) > Es objetivo que esa funcionalidad no está en el lenguaje. Es subjetivo el hecho de que sea deseable. Yo personalmente no la deseo si el precio a pagar puede ser la perdida de legibilidad. Un saludo: Javi _______________________________________________ Python-es mailing list Python-es@python.org http://mail.python.org/mailman/listinfo/python-es FAQ: http://python-es-faq.wikidot.com/