Наиболее питоническая форма для отображения серии утверждений? - PullRequest
0 голосов
/ 09 декабря 2008

Это то, что беспокоило меня в течение некоторого времени. Я изучил Haskell до того, как начал изучать Python, поэтому мне всегда нравилось думать о многих вычислениях как о отображении в списке. Это прекрасно выражено в понимании списка (здесь я даю питонскую версию):

result = [ f(x) for x in list ]

Во многих случаях мы хотим выполнить более одного оператора для x, скажем:

result = [ f(g(h(x))) for x in list ]

Это очень быстро становится неуклюжим и трудным для чтения.

Мое обычное решение - развернуть это обратно в цикл for:

result = []
for x in list:
  x0 = h(x)
  x1 = g(x0)
  x2 = f(x1)
  result.append(x2)

Одна вещь, которая беспокоит меня бесконечно, - это инициализация пустого списка «результат». Это мелочь, но меня это расстраивает. Мне было интересно, есть ли альтернативные эквивалентные формы. Одним из способов может быть использование локальной функции (это то, что они называются в Python?)

def operation(x):
  x0 = h(x)
  x1 = g(x0)
  x2 = f(x1)
  return x2
result = [ operation(x) for x in list ]

Есть ли какие-либо конкретные преимущества / недостатки в любой из двух форм выше? Или, может быть, есть более элегантный способ?

Ответы [ 7 ]

5 голосов
/ 09 декабря 2008

Вы можете легко создавать функции в Python.

Вот демонстрация способа создания новой функции, которая представляет собой композицию из существующих функций.

>>> def comp( a, b ):
    def compose( args ):
        return a( b( args ) )
    return compose

>>> def times2(x): return x*2

>>> def plus1(x): return x+1

>>> comp( times2, plus1 )(32)
66

Вот более полный рецепт для композиции функций . Это должно сделать его менее неуклюжим.

3 голосов
/ 09 декабря 2008

Следуйте стилю, который больше всего соответствует вашим вкусам.
Я не буду беспокоиться о производительности; только если вы действительно видите какую-то проблему, вы можете попытаться перейти к другому стилю.

Вот некоторые другие возможные предложения, помимо ваших предложений:

result = [f(
              g(
                h(x)
                )
              )
            for x in list]

Использовать прогрессивные списки:

result = [h(x) for x in list]
result = [g(x) for x in result]
result = [f(x) for x in result]

Опять же, это только вопрос стиля и вкуса. Выберите тот, который вы предпочитаете больше всего, и придерживайтесь его: -)

2 голосов
/ 09 декабря 2008

Если это то, что вы делаете часто и с несколькими различными утверждениями, вы можете написать что-то вроде

def seriesoffncs(fncs,x):
    for f in fncs[::-1]:
        x=f(x)
    return x

где fncs - список функций. поэтому seriesoffncs ((f, g, h), x) вернет F (G (Н (х))). Таким образом, если вам позже в вашем коде понадобится тренировка h (q (g (f (x)))), вы просто сделаете seriesoffncs ((h, q, g, f), x), а не создадите новую функцию операций для каждая комбинация функций.

1 голос
/ 02 января 2009

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

def compose(*f):
    return f[0] if len(f) == 1 else lambda *args: f[0](compose(*f[1:])(*args))

def f(x): 
    return 'o ' + str(x)

def g(x): 
    return 'hai ' + str(x)

def h(x, y): 
    return 'there ' + str(x) + str(y) + '\n'

action = compose(f, g, h)
print [action("Test ", item) for item in [1, 2, 3]]

Конечно, сочинение вне понимания не требуется.

print [compose(f, g, h)("Test ", item) for item in [1, 2, 3]]

Этот способ компоновки будет работать для любого количества функций (ну, до предела рекурсии) с любым количеством параметров для внутренней функции.

1 голос
/ 09 декабря 2008

Вариация dagw.myopenid.com Функция:

def chained_apply(*args):
    val = args[-1]
    for f in fncs[:-1:-1]:
        val=f(val)
    return val

Вместо seriesoffncs ((h, q, g, f), x) теперь вы можете позвонить:

result = chained_apply(foo, bar, baz, x)
1 голос
/ 09 декабря 2008

Если вас интересует только последний результат, ваш последний ответ - лучший. Всем понятно, что ты делаешь.

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

def operation(x):
  x0 = h(x)
  x1 = g(x0)
  x2 = f(x1)
  return x2
result = [ operation(x) for x in list]
0 голосов
/ 09 декабря 2008

В некоторых случаях лучше вернуться к циклу for, да, но чаще я предпочитаю один из этих подходов:

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

result = [blah(blah(blah(x)))
          for x in list]

Или извлеките (достаточно) из логики в другую функцию, как вы упомянули. Но не обязательно местный; Программисты Python предпочитают плоскую, а не вложенную структуру, если вы видите разумный способ выделить функциональность.

Я тоже пришел в Python из мира функционального программирования и разделяю ваши предубеждения.

...