6 de febrero de 2013

String Calculator en Python

Para complementar la entrada del joven +Alcides Flores Pineda, aquí anexo mi versión de la Kata en Python:

Pruebas:

#!/usr/bin/env python
import unittest
from strcalc import calc

def expected(exception):
    def argcatcher(f):
        def wrapper(self, *args):
            self.assertRaises(exception, lambda: f(self, *args))
        return wrapper
    return argcatcher


class StringCalcTest(unittest.TestCase):
    def testEmptyString(self):
        self.assertEquals(0, add(""))

    def testOneNumberString(self):
        self.assertEquals(2, add("2"))

    def testTwoNumberString(self):
        self.assertEquals(7, add("2,5"))

    def testThreeNumberString(self):
        self.assertEquals(15, add("2,5,8"))

    def testThreeNumberStringNewLine(self):
        self.assertEquals(15, add("2,5\n8"))

    def testEmptyStringWithUserSeparator(self):
        self.assertEquals(0, add("//;\n"))

    def testOneNumberStringWithUserSeparator(self):
        self.assertEquals(2, add("//;\n2"))

    def testTwoNumberStringWithUserSeparator(self):
        self.assertEquals(7, add("///\n2/5"))

    def testThreeNumberStringWithUserSeparator(self):
        self.assertEquals(15, add("//#\n2#5#8"))

    def testThreeNumberStringNewLineAndUserSeparator(self):
        self.assertEquals(15, add("//!\n2!5\n8"))

    @expected(ValueError)
    def testNegativesNotAllowed(self):
        add("2,-1")

    @expected(ValueError)
    def testNegativesNotAllowedWithUserSeparator(self):
        add("//&\n2&-1")

    def testIgnoreGreaterThan1000(self):
        self.assertEquals(1, add("1\n1001"))

    def testIgnoreGreaterThan1000WithUserSeparator(self):
        self.assertEquals(8, add("//$\n1\n1002$3$4$1005"))


if __name__ == '__main__':
    unittest.main()

Código:

#!/usr/bin/env python

def parse(s):
    return int(s) if s else 0

def tonums(lines, sep=','):
    return [parse(part) for line in lines for part in line.split(sep)]

def config(s):
    lines = s.split()
    if lines and lines[0].startswith('//'):
        return lines[1:], lines[0][2:]
    return lines, ','

def add(s):
    lines, sep = config(s)
    nums = tonums(lines, sep)
    negatives = [n for n in nums if n < 0]
    if negatives:
        raise ValueError('No se permiten negativos: %r' % negatives)
    return sum(n for n in nums if n <= 1000)

Al igual que en el caso de +Alcides Flores Pineda y +rodrigo salado anaya , el presente código no implementa el requerimiento de separadores de longitud arbitraria.

El código resultante es más largo que la versión en scheme/kawa, en algunos casos por la verbosidad propia de las comprensiones y generadores de Python, y en otras por las diferencias propias de la implementación, más que por cuestiones sintácticas.

A mi en lo particular me resulta muy ilustrativo ver las diferentes respuestas que se han generado para la misma kata en diversos lenguajes o incluso de personas distintas usando el mismo lenguaje.

La siguiente parte del ejercicio es: ejecutarlo en 15 o menos minutos todos los días por una semana y al cabo de ese tiempo, reflexionar:

  • ¿Mi solución a la kata está evolucionando cada vez que la ejecuto o por el contrario, repito los mismos pasos "como periquito"?
  • ¿Puedo encontrar alguna forma más elegante/clara/eficiente de resolver el problema o alguna parte de el mismo?
  • ¿Si la primera vez resolví el problema de forma, digamos, procedural, puedo intentar una solución orientada a objetos?, ¿funcional?
  • ¿Qué ventajas/desventajas tendrían dichas soluciones?

Saludos

No hay comentarios:

Publicar un comentario