Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

Clavando un clavo con un zapato I: Do-Sheet.

  1. Te ha­­ce pen­sar di­­fe­­ren­­te.

  2. Es di­­ve­r­­ti­­do.

Lo ma­lo es, por su­pues­to, que el con­te­ni­do de la char­la tie­ne que ser se­cre­to, o no tie­ne nin­gu­na gra­cia. Co­mo el pro­ce­so de re­view pa­ra char­las de Py­Co­nAr es pú­bli­co, no te­nía ma­ne­ra de ex­pli­car de qué se tra­ta­ba.

Co­mo eso sig­ni­fi­ca que pon­go a los re­vi­so­res en el com­pro­mi­so de te­ner que acep­tar mi pa­la­bra de que es­ta char­la es al­go in­te­re­san­te, y eso es injus­to pa­ra ellos y los de­más char­la­ri­nes, can­ce­lé la pro­pues­ta.

La (tal ve­z) bue­na no­ti­cia es que aho­ra to­dos van a po­der ver de qué se tra­ta­ba la char­la. Acá es­tá el cla­vo nú­me­ro 1: Es­cri­bir una ho­ja de cál­cu­lo usan­do doi­t.

Es­ta no es mi pri­me­ra "ho­ja de cál­cu­lo­". To­do em­pe­zó ha­ce mu­cho, mu­cho tiem­po con una fa­mo­sa re­ce­ta de Ra­y­mond He­ttin­ger que he usa­do una y otra y otra vez (ca­paz que fal­ta al­gu­na).

Da­do que ven­go usan­do doit pa­ra Niko­la es­toy im­pre­sio­na­do con lo po­ten­te que es. En bre­ve, doit te per­mi­te crear ta­rea­s, y esas ta­reas de­pen­den de otra­s, ope­ran en da­to­s, dan re­sul­ta­dos que otras ta­reas usan, etc.

¿Se ve adon­de va es­to?

Acá va el có­di­go, con ex­pli­ca­cio­nes:

cells es nuestra hoja. Podés poner cualquier cosa, pero usá siempre el formato "nombre=formula" y la fórmula tiene que ser Python válido ¿ok?

from tokenize import generate_tokens

cells = ["A1=A3+A2", "A2=2", "A3=4"]
values = {}

task_calculate crea una tarea para cada celda, llamada calculate:NOMBRE. La acción que esa tarea realiza es evaluar la fórmula. Pero para hacer eso de manera exitosa, necesitamos saber qué otras celdas hay que evaluar primero.

Eso lo im­ple­men­té usan­do las cal­cu­lated de­pen­den­cies de doi­t, con la ta­rea "ge­t_­de­p:­FOR­MU­LA" pa­ra la fór­mu­la de es­ta cel­da.

def evaluate(name, formula):
    value = eval(formula, values)
    values[name] = value
    print "%s = %s" % (name, value)

def task_calculate():
    for cell in cells:
        name, formula = cell.split('=')
        yield {
            'name':name,
            'calc_dep': ['get_dep:%s' % formula],
            'actions': [(evaluate, (name, formula))],
            }

Por ejemplo, nuestra A1 depende de A3 y A2 que no dependen de nada. Para parsear esto, usé el módulo tokenize, y tomo nota de cuales cosas son "nombres". Existen maneras más soisticadas ;-)

la función task_get_dep es una tarea de doit que crea tareas llamadas "get_dep:NOMBRE" para cada nombre de celda en cells.

A su vez, get_dep devuelve una lista de tareas de doit. Para nuestra celda A1, eso sería ["calculate:A2", "calculate:A3"] o sea que para poder calcular A1 primero tenemos que terminar esas tareas.

def get_dep(formula):
    """Given a formula, return the names of the cells referenced."""
    deps = {}
    try:
        for token in generate_tokens([formula].pop):
            if token[0] == 1:  # A variable
                deps[token[1]] = None
    except IndexError:
        # It's ok
        pass
    return {
        'result_dep': ['calculate:%s' % key for key in deps.keys()]
        }

def task_get_dep():
    for cell in cells:
        name, formula = cell.split('=')
        yield {
            'name': formula,
            'actions': [(get_dep, (formula,))],
            }

Y eso es todo. Veámoslo en acción. Podés obtener tu propia copia acá y probarlo instalando doit, editando cells y usándolo así:

ralsina@perdido:~/dosheet$ doit -v2 calculate:A3
.  get_dep:4
{}
.  calculate:A3
A3 = 4
ralsina@perdido:~/dosheet$ doit -v2 calculate:A2
.  get_dep:2
{}
.  calculate:A2
A2 = 2
ralsina@perdido:~/dosheet$ doit -v2 calculate:A1
.  get_dep:A3+A2
{'A3': None, 'A2': None}
.  get_dep:4
{}
.  calculate:A3
A3 = 4
.  get_dep:2
{}
.  calculate:A2
A2 = 2
.  calculate:A1
A1 = 6

Co­mo po­dés ve­r, siem­pre ha­ce el mí­ni­mo es­fuer­zo po­si­ble pa­ra cal­cu­lar el re­sul­ta­do de­sea­do. Si que­ré­s, hay al­gu­nas co­sas me­jo­ra­ble­s, que de­jo co­mo ejer­ci­cio pa­ra el lec­to­r. Por ejem­plo:

  1. Usar up­­to­­­da­­te pa­­ra no re­­ca­l­­cu­­lar de­­pen­­den­­cias inu­­ti­l­­men­­te.

  2. Eli­mi­nar la va­ria­ble glo­bal va­lues y usar los com­puted va­lues de doit en su lu­ga­r.

Acá es­tá el lis­ta­do com­ple­to, buen pro­ve­cho!

jjconti / 2012-07-26 13:53:

El link al listado completo da 404.

Roberto Alsina / 2012-07-26 13:57:

Arreglado, gracias!


Contents © 2000-2020 Roberto Alsina