LINUX.ORG.RU

Питон, модуль в качестве аргумента функции/метода.

 


0

1

Я в программировании не силён. Так вообще делают?

#utils.py
def func(conf):
 x=conf.opt1
 y=conf.opt2
 return x+y

class C(object):
 def __init__(self,conf):
  self.x=conf.opt1
  self.y=conf.opt2
#main.py
import config, utils
utils.func(config)
x=utils.C(config)

config.py содержит различные опции, которые нужны для utils.py и специфичны для каждой задачи (у каждой задачи свой config.py). Или есть более правильный подход?

★★☆

Только так и делаю. Это лучше, чем тащить в зависимости ненужные парсеры конфигов.

anonymous
()
Ответ на: комментарий от thunar

Что-то я не догоняю, как мне пикл поможет передать методу параметры из конфига?

yvv ★★☆
() автор топика
Последнее исправление: yvv (всего исправлений: 1)

А если тебе понадобится инициализировать несколько «задач», то ты устроишь пляски с sys.path? Если ты всего лишь хочешь обращаться к записям в словаре как к аттрибутам, то:

class Namespace:
    def __init__(self, **kwargs):
        for name in kwargs:
            setattr(self, name, kwargs[name])

    def __contains__(self, key):
        return key in self.__dict__
with open('config.json') as f:
    config = Namespace(**json.load(f))
Zeta_Gundam
()

Или есть более правильный подход?

Путь к файлу конфига удобно делать передаваемым через args параметром. Я использую JSON + парсер simplejson. Распаковка параметров сводится к чтению файла + simplejson.load(...).

Norgat ★★★★★
()
Ответ на: комментарий от Zeta_Gundam

Мне по барабану атрибуты это или key/value, но за подсказку всё равно спасибо. Да, я добавляю в sys.path одну запись. config.py привлекателен тем, что туда можно и кое-какой код вставить если надо. Если быть точнее, мой конфиг это __init__.py. Что-то типа этого:

#__init_-.py
experiment_id='имя'
data_path='путь_к_данным'
plot_path='путь_к_графикам'
dates=dateutils.rrule(start,end,frequency)
и т.д.
#make_plots.py
import utils
import sys
sys.path.append('experiment_path')
import exp1,exp2,exp3

dset1=utils.Reader(exp1)
dset2=utils.Reader(exp2)
dset3=utils.Reader(exp3)

vars=['temperature','pressure','humidity']

for var in vars:
 v1=dset1(var)
 v2=dset2(var)
 v3=dset3(var)
 plot=utils.Plotter(var)
 plot(v1)
 plot(v2)
 plot(v3)
 plot(v1-v2)
 plot(v1-v3)
 plot(v2-v3)

ну и так далее.

yvv ★★☆
() автор топика
Ответ на: комментарий от yvv

я добавляю в sys.path одну запись.

А когда надо прочитать второй конфиг — вторую?

туда можно и кое-какой код вставить

Да, это бывает удобно. Но потом, когда наколенная поделка разрастется, можно поиметь проблемы с извлечением данных.

Zeta_Gundam
()
Ответ на: комментарий от Zeta_Gundam

А когда надо прочитать второй конфиг — вторую?

Нет, только один раз. Оно так работает:

experiment_dir/
 exp1/__init__.py
 exp2/__init__.py
 ...
 exp100500/_init__.py
sys.path.append('experiment_dir')
import exp1, exp2, ..., exp100500

Но я ещё не решил окончательно, а не лучше ли всё-таки генерировать текстовый кофиг (json или yaml) с помощью скрипта? Это нужно делать один раз для каждого эксперимента. Какие у такого подхода ещё плюсы, кроме отсутствия необходимости изменять sys.path?

yvv ★★☆
() автор топика
Ответ на: комментарий от yvv

import exp1, exp2, ..., exp100500

Я не понимаю, честно, зачем тебе питон, если ты все равно предпочитаешь делать все руками.

Тебя правда не смущает, что ты захардкодил всю структуру каталогов?

Какие у такого подхода ещё плюсы

Да все те же: данные это всего лишь данные, они не диктуют тебе как себя обрабатывать. Если данные внутри кода — тебе остается только выполнять этот код одним и тем же образом, в том же самом окружении.

Zeta_Gundam
()
Ответ на: комментарий от Zeta_Gundam

Структура каталогов у меня такая, какая она есть, захардкодил её не я, и меняться она никогда не будет.

Мой код чётко разделён на часть, которая ничего не знает про конкретные данные, и на часть, которая содержит в себе мета-данные. Это не зависит от того, использую ли я config.py, или config.json. Последняя часть как раз таки и предназначена для того, чтоб «выполнять этот код одним и тем же образом, в том же самом окружении» (мне для каждого эксперимента нужно строить один и тот же стандартный набор графиков). Импорт конфига в виде модуля может быть не очень удобным, если мою библиотеку захочет использовать кто-то другой со своими данными, с этим я согласен.

yvv ★★☆
() автор топика
Ответ на: комментарий от Zeta_Gundam

Лучше так

class Namespace(dict):                                                          
    __getattr__= dict.__getitem__                                               
    __setattr__= dict.__setitem__                                               
    __delattr__= dict.__delitem__                                               
                                                                                
foo = Namespace({'a': 1, 'b': 3})

Смысл тот же

Crocodoom ★★★★★
()
Ответ на: комментарий от yvv

В целом всё в порядке

  • В изменении sys.path нет ничего предосудительного. Это нормальный способ импортирования, если у тебя файлы не связаны принадлежностью к одному пакету. Насколько я понял - они и не должны быть по логике. Если всё же будут связаны - используй relative import.
  • Импорт 100500 файлов-конфигов можно сделать в пару строчек, если вспомнить о существовании функции __import__ Например, это может выглядеть как
    map(__import__, [exp1, exp2, exp100500])
    Откуда брать список конфигов для импорта - решай сам.
  • Я бы динамически формировал список всех конфигов в директории 'experiment_dir', и передавал бы его импорту выше. Если теперь ещё и имя 'experiment_dir' перенести в аргументы твоего make_plots.py, то весь хардкод исчезнет, и никто не уйдёт обиженный (с)
  • и да, json и пр. здесь явно лишние

Удачи!

Crocodoom ★★★★★
()

Ну, в целом, я понял все «за» и «против». Всем отписавшимся огромное спасибо.

yvv ★★☆
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.