Python exe c () обновляет параметры глобально, но не может найти их внутри другой функции - PullRequest
2 голосов
/ 04 мая 2020

Так что я работаю в python 2.7.

Я использую эту строку для выполнения ряда операторов в словаре:

for key in pipeline: 
    exec(dictionary[key], globals(), globals())

Вот что содержит конвейер:

pipeline = {
    'initializer' : 'initializer()',
    'preprocesser' : 'preprocesser()'
}

Вот два Функции initializer () и preprocesser ():

def initializer():
    global params 

    data = pd.read_csv(params['dataset'])
    data.fillna(0, inplace=True)
    params['data'] = data
    return params 

def preprocesser():
    global params
    print(params.keys())

Обе эти функции модифицируют глобальный словарь, называемый params, вот как это выглядит:

params = {
                'instruction' : "Predict median house value", 
                'dataset' : './data/housing.csv', 
}

По какой-то причине, если я напечатаю из словарных ключей params он напечатает обновленные ключи: функция initializer () должна добавить ключ «data» в глобальный словарь params. Но если я распечатываю список ключей внутри функции препроцессора (), я просто получаю ['инструкция', 'набор данных']. Если я распечатываю ключи сразу после вызова функции exe c (в глобальной области видимости), она правильно печатает ['инструкция', 'набор данных', 'данные]. Почему он обновляется глобально, но тогда я не могу получить доступ к этому обновленному параметру внутри функции preprocesser (). Как бы это исправить?

Ответы [ 2 ]

1 голос
/ 04 мая 2020

В Python 2.7 объекты словаря не поддерживают порядок вставки. Наблюдайте за порядком, который выдается:

In [3]: pipeline = {
   ...:     'initializer' : 'initializer()',
   ...:     'preprocesser' : 'preprocesser()'
   ...: }

In [4]: list(pipeline)
Out[4]: ['preprocesser', 'initializer']

Итак, предварительный процессор запустил first . Вам вообще не нужно dict здесь, вы могли бы просто использовать список кортежей или, если по какой-то другой причине ваш код требует указания, тогда вы можете хранить список ключей в том порядке, в каком вы хотите запустить вещи.

Но в целом весь этот подход не рекомендуется. Не используйте exec здесь, это не дает вам никаких преимуществ, а динамическое c выполнение кода имеет много недостатков, и в этом случае оно совершенно не нужно. Почти во всех случаях, включая этот, это явный антипаттерн.

Кроме того, не использует изменяемое глобальное состояние . Это еще один другой известный антипаттерн. Вместо этого явно передает аргументы функциям . Вот как я бы это сделал:

In [9]: def initializer(params):
   ...:     params['data'] = 42
   ...:     return params
   ...:
   ...: def preprocesser(params):
   ...:     print(params.keys())
   ...:

In [10]: pipeline = [(initializer, (params,)), (preprocesser, (params,))]

In [11]: for func, args in pipeline:
    ...:     func(*args)
    ...:
['instruction', 'data', 'dataset']

In [12]: params
Out[12]:
{'data': 42,
 'dataset': './data/housing.csv',
 'instruction': 'Predict median house value'}

Теперь, как правило, также считается анти-паттерном для функций, изменяющих свои входы, но это должно привести вас к более вменяемый подход ..

Наконец, вам следует избегать использования Python 2, он истек официальный срок службы, больше не будет даже обновлений безопасности и большинство основных сторонних библиотек также перестали поддерживать , включая pandas, который вы используете.

0 голосов
/ 04 мая 2020

Просто для любого в будущем, если ваши параметры глобальны, вы также можете сделать:

reg_pipeline = [initializer,
                preprocesser]


for func in reg_pipeline:
    func(init_params)
...