Как правило это выглядит так. После написания уравнения, численной схеме и пр., ваяется прототип кода. Ядро пишется на плюсах в виде отдельного модуля, в котором есть класс модели со всякими численными/физическими параметрами и методами (типа задать начальные условия, посчитать че нить, скинуть результат в файл), модуль цепляется к питону через SWIG и дальше из питоньего скрипта им рулится - создается экземпляр класса модели, устанавливаются параметры, запускаются методы.
Дальше это все отлаживается до какого то вида, и вот наступает тот самый момент когда оно вроде работает и надо его активно тестить гоняя серии расчетов.
Что бы не складывать результаты в файлы с именами типа a=1-b=2.34-c=-13.5.dat (а файлов с одного расчета м.б. несколько) давно отработана некая идеология - есть библиотека на питоне, которой для каждого расчета делается уникальная директория куда сваливаются все результаты расчета, туда же автоматом тарятся исходники и пиклятся параметры расчета.
Первый вопрос с-но в том, что бы прицепить эту библиотеку к новому коду. Сейчас библиотека цепляется так - создается экземпляр специального класса, у котрого прописываются какие то параметры (их дефолтные значения).
calc = CALC(a=1, b=2.5, c=True, N=100)
Эти параметры можно менять при запуске из командной строки. Дальше эти параметры либо пачкой накатываются на модель (весь словарь), либо явно юзаются в скрипте
m = CPPModel()
...
m.init(calc.N)
...
Дальше можно искать расчеты в репозитории, перезаупскать и тд и тп. Но с-но хочется как то упростить подключение этой самой библиотеки, потому что приходится для этого здорово корежить головной скрипт.
Мой воспаленный мосг родил такую идею. Вот у нас есть скрипт
from model import *
m = CPPModel()
m.a = 1
m.b = 1.5
m.dt = 0.1
m.init(100)
while m.t<10.:
m.calc(25) # че то считаем
m.dump('result.dat')
from model import *
from racs import calc # тут создается уникальная директория
# и всяко разно происходит, включая разбор аргументов
# командной строки
m = calc.control(CPPModel())
m.a = 1
m.b = 1.5
m.dt = 0.1
m.init(100)
while m.t<10.:
m.calc(25) # че то считаем
m.dump('result.dat')
calc.control возвращает CPPModel() завернутую в оболочку, перехватывающую get/setattr. Все атрибуты которые для оболчки задаются считаются параметрами (их деволтными значениями). Если я в аргументах командной строки напишу a=2 то будет задано m.a=2 Это клево, но вызвыает некоторое... недоумение.
Дальше хуже. При вызове методов, если я хочу управлять параметрами вызова мне придется писать че то типа
calc.N = 100 # дефолтное значение
m.init(calc.N)
С точки зрения лени мне это решение очень нравится. С точки зрения здравого смысла неменого пугает - во первых оно заточено под совершенно конкретный дизайн приложения, во вторых такое ощущение что машина оказывается умнее человека - делается много умолчаний что обеспечивает вроде бы интуитивно понятное и удобное поведение, но любой шаг в тосроны и ты отстрелил себе все что ниже шеи.
В общем хотелось бы обсудить;-)