0

これは、しばらくの間私を悩ませてきたものです。Python を学ぶ前に Haskell を学んだので、多くの計算をリストへのマッピングとして考えるのが好きでした。これは、リスト内包表記によって美しく表現されています (ここでは Pythonic バージョンを示しています)。

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)

これについて私を悩ませていることの1つは、空のリスト「結果」を初期化する必要があることです。それは些細なことですが、私を不幸にします。代替の同等の形式があるかどうか疑問に思っていました。1 つの方法は、ローカル関数を使用することです (それは Python で呼び出されているものですか?)

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

上記の 2 つの形式のいずれかに特定の利点/欠点はありますか? それとももっとエレガントな方法がありますか?

4

7 に答える 7

5

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

関数合成のより完全なレシピを次に示します。これにより、見栄えが悪くなります。

于 2008-12-09T15:11:15.917 に答える
3

あなたの好みに最も合ったスタイルに従ってください。
パフォーマンスについては心配しません。実際に問題が発生した場合にのみ、別のスタイルに移行してみてください。

あなたの提案に加えて、いくつかの他の可能な提案をここに示します:

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]

繰り返しますが、それはスタイルと好みの問題です。一番好きなものを選んで、それに固執してください:-)

于 2008-12-09T09:25:04.947 に答える
2

これが頻繁に行うもので、いくつかの異なるステートメントがある場合は、次のように書くことができます

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

fncs は関数のリストです。したがって、seriesoffncs((f,g,h),x) は f(g(h(x))) を返します。このようにして、コードの後半で h(q(g(f(x)))) をワークアウトする必要がある場合、新しい操作関数​​を作成するのではなく、単純に seriesoffncs((h,q,g,f),x) を実行します。各機能の組み合わせ。

于 2008-12-09T15:35:13.887 に答える
1

最後の結果だけに関心がある場合は、最後の答えが最適です。あなたが何をしているのかを見ている人には明らかです。

複雑になり始めたコードを関数に移動することがよくあります。これは基本的に、そのコードブロックのコメントとして機能します。(複雑なコードは、とにかく書き直しが必要になる可能性があります。関数に入れると、後で戻って作業できます)

def operation(x):
  x0 = h(x)
  x1 = g(x0)
  x2 = f(x1)
  return x2
result = [ operation(x) for x in list]
于 2008-12-09T08:34:29.090 に答える
1

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)
于 2008-12-09T18:20:06.177 に答える
1

私が知る限り、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]]

この構成方法は、内部関数の任意の数のパラメーターを使用して、任意の数の関数 (再帰の制限まで) に対して機能します。

于 2009-01-02T14:41:29.913 に答える
0

はい、forループに戻るのが最善の場合もありますが、多くの場合、これらのアプローチの1つを好みます。

適切な改行とインデントを使用して、読みやすくします。

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

または、あなたが言及したように、ロジックを別の関数に(十分に)抽出します。しかし、必ずしもローカルではありません。Pythonプログラマーは、機能を除外する合理的な方法がわかる場合は、ネストされた構造よりもフラットな構造を好みます。

私も関数型プログラミングの世界からPythonに来て、あなたの偏見を共有します。

于 2008-12-09T08:26:04.160 に答える