Hola Habr! Hablaré sobre el marco arquitectónico que estoy desarrollando.
La arquitectura determina la estructura más general del programa y la interacción de sus componentes. Lena como marco implementa una arquitectura específica para el análisis de datos (más sobre esto a continuación) y proporciona al usuario clases y funciones que pueden ser útiles (teniendo en cuenta esta arquitectura).
Lena está escrito en el popular lenguaje Python y funciona con versiones de Python 2, 3 y PyPy. Se publica bajo la licencia gratuita de Apache (versión 2) aquí . Por el momento, todavía se está desarrollando, pero las características descritas en este manual ya están en uso, probadas (la cobertura total de todo el marco es aproximadamente del 90%) y es poco probable que se modifique. Lena surgió en el análisis de datos experimentales en física de neutrinos y lleva el nombre del gran río siberiano.

Los problemas de arquitectura surgen, por regla general, en proyectos grandes y medianos. Si está pensando en usar este marco, aquí hay una breve descripción de sus tareas y ventajas.
Desde el punto de vista de la programación:
- modularidad, compromiso débil. Los algoritmos se pueden agregar, reemplazar o reutilizar fácilmente.
 - ( ). . PyPy " ".
 - . . .
 - . , . . .
 - , .
 
, Python, , .
:
(tutorial) – Lena. , , , , . . .
Lena
. , , . .
, . Lena , , . , , .
Lena
Lena — . .
Lena . , :
>>> from __future__ import print_function
>>> from lena.core import Sequence
>>> s = Sequence(
...     lambda i: pow(-1, i) * (2 * i + 1),
... )
>>> results = s.run([0, 1, 2, 3])
>>> for res in results:
...     print(res)
1 -3 5 -7
Lena Python 2 3, print. .
Sequence . run. ( ).
, for.
. - , - . Source:
from lena.core import Sequence, Source
from lena.flow import CountFrom, ISlice
s = Sequence(
    lambda i: pow(-1, i) * (2 * i + 1),
)
spi = Source(
    CountFrom(0),
    s,
    ISlice(10**6),
    lambda x: 4./x,
    Sum(),
)
results = list(spi())
Source __call__, . : , .
CountFrom — , . , ¹. CountFrom ( ). CountFrom — start ( ) step ( 1).
Source ( ) (callable) run. Sequence.
. s Source. , s s.
Sequence , Sequence. Sequence Source, (flow).
: Sequence Source , LenaTypeError ( TypeError Python).
Lena — LenaException. ( , ).
, - . ISlice. ISlice CountFrom islice count itertools Python. ISlice start, stop[, step], ( ) step ( step , ).
, .
.
. run, flow:
class Sum():
    def run(self, flow):
        s = 0
        for val in flow:
            s += val
        yield s
, return, yield. Yield — Python, .
— Python.
>>> results = s.run([0, 1, 2, 3])
Sequence run . , , , . , . ( ) :
>>> for res in results:
...     print(res)
:
- . . , , , . , .
 - . -. , , .
 
Python yield. Lena. run, . , , , , - .
(yield) . (flow) . , (value).
Lena . — , .
Lena , . Jinja . Lena , . LaTeX:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\begin{document}
\begin{tikzpicture}
\begin{axis}[]
\addplot [
    const plot,
]
table [col sep=comma, header=false] {\VAR{ output.filepath }};
\end{axis}
\end{tikzpicture}
\end{document}
TikZ , : \VAR{ output.filepath }. \VAR{ var } var . , . output.filepath .
:
\BLOCK{ set var = variable if variable else '' }
\begin{tikzpicture}
\begin{axis}[
    \BLOCK{ if var.latex_name }
        xlabel = { $\VAR{ var.latex_name }$
        \BLOCK{ if var.unit }
            [$\mathrm{\VAR{ var.unit }}$]
        \BLOCK{ endif }
        },
    \BLOCK{ endif }
]
...
variable, var . latex_name unit (), x. , x [m] E [keV] . , , .
Jinja . , . Jinja² .
Jinja LaTeX, Lena ³: \BLOCK \VAR .
— Python . Flow Lena (data, context). dataflow, . , Lena. . , :
class ReadData():
    """Read data from CSV files."""
    def run(self, flow):
        """Read filenames from flow and yield vectors.
        If vector component could not be cast to float,
        *ValueError* is raised.
        """
        for filename in flow:
            with open(filename, "r") as fil:
                for line in fil:
                    vec = [float(coord)
                           for coord in line.split(',')]
                    
                    yield (vec, {"data": {"filename": filename}})
flow . data ( ). filename data["filename"] data.filename.
-, HTML LaTeX , , . , . — , - ( ).
Lena. , .
, , . , , .
. x.
docs/examples/tutorial .
main.py
from __future__ import print_function
import os
from lena.core import Sequence, Source
from lena.math import mesh
from lena.output import HistToCSV, Writer, LaTeXToPDF, PDFToPNG
from lena.output import MakeFilename, RenderLaTeX
from lena.structures import Histogram
from read_data import ReadData
def main():
    data_file = os.path.join("..", "data", "normal_3d.csv")
    s = Sequence(
        ReadData(),
        lambda dt: (dt[0][0], dt[1]),
        Histogram(mesh((-10, 10), 10)),
        HistToCSV(),
        MakeFilename("x"),
        Writer("output"),
        RenderLaTeX("histogram_1d.tex"),
        Writer("output"),
        LaTeXToPDF(),
        PDFToPNG(),
    )
    results = s.run([data_file])
    print(list(results))
if __name__ == "__main__":
    main()
, output/, :
$ python main.py
pdflatex -halt-on-error -interaction batchmode -output-directory output output/x.tex
pdftoppm output/x.pdf output/x -png -singlefile
[(‘output/x.png’, {‘output’: {‘filetype’: ‘png’}, ‘data’: {‘filename’: ‘../data/normal_3d.csv’}, ‘histogram’: {‘ranges’: [(-10, 10)], ‘dim’: 1, ‘nbins’: [10]}})]
LaTeXToPDF pdflatex, PDFToPNG pdftoppm. , LaTeX , output/x.tex ( ).
— , (run) . , , ( , ). , ( ) output/x.png.
. s ( ). ReadData (data, context), lambda , ( (data, context)).
lambda , . , .
x Histogram, (edges), (mesh) -10 10 .
, , CSV (, ). ( pdflatex) , .
MakeFilename context["output"]. Context.output.filename — ( : csv, pdf ..). , x.
Writer . . , "output".
csv, LaTeX histogram_1d.tex , pdf png. , RenderLaTeX , .
: , . Lena, .
:
from lena.context import Context
from lena.flow import Cache, End, Print
s = Sequence(
    Print(),
    ReadData(),
    
    ISlice(1000),
    lambda val: val[0][0], 
    Histogram(mesh((-10, 10), 10)),
    Context(),
    Cache("x_hist.pkl"),
    
    HistToCSV(),
    
)
Print , . , , Print . print .
ISlice, , , . , , , .
Context — , , , . Context , , ( , ). .
Cache . — , . , Cache , , . , . Cache pickle, Python ( ). (, , ), Cache. Cache, , .
End . , Cache ( End), HistToCSV . End , .
Lena , . , , . , .
(callable) . , , . , .
. — . , .
. Sequence , . Source Sequence, .
, , , . .
End. :
class End(object):
    """Stop sequence here."""
    def run(self, flow):
        """Exhaust all preceding flow and stop iteration."""
        for val in flow:
            pass
        raise StopIteration()
main.py . ,
Traceback (most recent call last):
File “main.py”, line 46, in <module>
main()
File “main.py”, line 42, in main
results = s.run([data_file])
File “lena/core/sequence.py”, line 70, in run
flow = elem.run(flow)
File “main.py”, line 24, in run
raise StopIteration()
StopIteration
, , , . , StopIteration . ?
, . , .
Count , . , . ? , .
, .
" - ",- . " CSV, , , ,… , , code bloat ( )."
? ?
** Sum . , , .
Sum , ? ? .
Las respuestas a los ejercicios se dan al final del manual .
Notas al pie
1. Esta característica se puede agregar en el futuro.
2. Documentación de Jinja
3. El uso de Jinja para el diseño de LaTeX se propuso aquí y aquí , la sintaxis de las plantillas se tomó del artículo original.
Alternativas
Ruffus es una tubería computacional para Python utilizada en ciencia y bioinformática. Conecta los componentes del programa a través de la escritura y lectura de archivos.