Pythonic способ определения замыканий функций - PullRequest
0 голосов
/ 17 мая 2018

У меня есть некоторая функция, определенная в модуле mymodule:

def f1(a, b):
    # do something with a and b

По ряду причин проектирования в основном скрипте мне нужно вызвать f1 из функции высшего порядка mycaller, которая будет передавать только a в качестве аргумента. Другой параметр b доступен только в основном скрипте.

Внутренне mycaller выглядит следующим образом:

  def mycaller(list_of_functions, a):
        for f in list_of_functions:
             f(a)

Пока что я сделал

from mymodule import f1

bb = myB()
aa = myA()

def closure_f1(a):
    return f1(a, bb)

mycaller([closure_f1], aa)

Это правильный способ конструировать такое закрытие? Прямо сейчас я получаю много замыканий в основном скрипте, которые выглядят ужасно, и я считаю, что это может также вызвать проблемы с сериализацией. Как я могу улучшить это?

Вот некоторые попытки, которые я сделал без отдельной функции closure_f1:

mycaller([f1],a)

Однако тогда функция пропускает аргумент b. Тогда я попробовал

mycaller([f1(b)],a)

но, конечно, это приводит к вызову функции (которая завершается ошибкой), а не к передаче функции с аргументом b set.

1 Ответ

0 голосов
/ 17 мая 2018

Несколько возможностей:

1. Используйте functools.partial

Если вы хотите исправить первый аргумент (или первые несколько аргументов), просто используйте functools.partial:

from functools import partial
mycaller([partial(f1, bb)], aa)

Чтобы это работало с вашим примером, вы должны поменять местами порядок аргументов a и b в определении f1.


2. Определите свой собственный partial, который исправляет второй аргумент

Если вы хотите исправить второй аргумент, functools.partial не поможет, потому что он работает слева направо. Но если у вас много функций, где вам нужно исправить второй аргумент, вы можете сделать что-то вроде этого:

def partial2(f, y):
  def res(x):
    return f(x, y)
  return res

, а затем используйте его следующим образом:

mycaller([partial2(f1, bb)], aa)

3. Просто используйте lambda s:

Это несколько многословно, но в то же время наиболее гибкая возможность:

mycaller([lambda x: f1(x, bb)], aa)

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

4. Просто определите вспомогательную функцию

Я не вижу ничего катастрофического в определении вспомогательной функции, особенно если она часто используется. Итак, просто оставьте closure_f1 как есть и используйте:

mycaller([closure_f1], aa)
...