17

Pythonでは、次のことを行うのがより良いスタイルと見なされますか?

  • より一般的な、場合によっては内部使用の関数の観点から、有用な関数を明示的に定義します。また、
  • 部分機能アプリケーションを使用して、関数カリー化を明示的に記述しますか?

不自然な例として私の質問を説明します。

スコアリング関数とアイテムのリストの2つの引数を取る関数_sort_by_scoringを作成するとします。元のリスト内の各アイテムの位置に基づいてスコアでソートされた元のリストのコピーを返します。2つのスコアリング関数の例も提供されています。

def _sort_by_score(scoring, items_list):
    unsorted_scored_list = [(scoring(len(items_list), item_position), item) for item_position, item in enumerate(items_list)]
    sorted_list = [item for score, item in sorted(unsorted_scored_list)]
    return sorted_list

def _identity_scoring(items_list_size, item_position):
    return item_position

def _reversed_scoring(items_list_size, item_position):
    return items_list_size - item_position

関数_sort_by_scoreが直接呼び出されることはありません。代わりに、スコアリング関数とその唯一の引数(アイテムのリスト)を_sort_by_scoringに渡し、結果を返す他の単一引数関数によって呼び出されます。

# Explicit function definition style
def identity_ordering(items_list):
    return _sort_by_score(_identity_scoring, items_list)

def reversed_ordering(items_list):
    return _sort_by_score(_reversed_scoring, items_list)

明らかに、この意図は機能カリー化の観点からよりよく表現されています。

# Curried function definition style
import functools
identity_ordering = functools.partial(_sort_by_score, _identity_scoring)
reversed_ordering = functools.partial(_sort_by_score, _reversed_scoring)

使用法(いずれの場合も):

>>> foo = [1, 2, 3, 4, 5]
>>> identity_ordering(foo)
[1, 2, 3, 4, 5]
>>> reversed_ordering(foo)
[5, 4, 3, 2, 1]

明示的な関数定義スタイルの明らかな利点:

  1. NameErrorsを発生させることなく、より一般的な関数の前に有用な関数を定義できます。
  2. ヘルパー関数(スコアリング関数など)は、関数定義本体内で定義できます。
  3. おそらくデバッグが簡単です。
  4. 「暗黙的よりも明示的の方が優れている」という理由で、コードは見栄えがします。

カリー化された関数定義スタイルの明らかな利点:

  1. 関数型プログラミングの意図を慣用的に表現します。
  2. 簡潔さのおかげで、コードは見栄えがします。

「便利な」機能を定義するために、2つのスタイルのどちらが好ましいですか?より慣用的な/Pythonicなどの他のスタイルはありますか?

4

2 に答える 2

13

カレー関数をパブリックインターフェイスの一部として使用する場合は、明示的な関数定義を使用します。これには、次の追加の利点があります。

  1. 明示的な関数定義にdocstringを割り当てる方が簡単です。関数の場合partial()、属性に割り当てる必要があり__doc__ますが、これはやや醜いです。

  2. モジュールソースを参照するときに、実際の関数定義を簡単に確認できます。

functools.partial()ラムダ式と同様の方法で、つまりローカルで必要なスローアウェイ関数に使用します。

あなたの特定の例では、おそらくどちらも使用せず、先頭のアンダースコアを削除して呼び出します

sort_by_score(identity_scoring, foo)

これは私にとって最も明白なようです。

于 2011-02-23T13:48:57.203 に答える
2

sortedわずかな接線として、一般的には、ビルトインに可能な限り多くの装飾-並べ替え-非装飾の作業を行わせることが望ましいです。例えば:

def _sort_by_score(scoring, items_list):
    num_items = len(items_list)
    def score(entry):
        return scoring(num_items, entry[0])
    return [item for position, item in sorted(enumerate(items_list), key=score)]

(コードのブロックはコメントとして機能しないため、回答としてのみ投稿されます。実際に尋ねられた質問に対する回答については、Svenの回答を参照してください)

他の誰かによる編集:Pythonの並べ替え関数はリストを反復処理し、最初にキーのリストを生成します。key()関数は、入力リストの順序で、リスト項目ごとに1回だけ呼び出されます。したがって、次の実装を使用することもできます。

def _sort_by_score(scoring, items_list):
    num_items = len(items_list)
    index = itertools.count()
    def score(entry):
        return scoring(num_items, next(index))
    return sorted(items_list, key=score)

(コードのブロックはコメントとして機能しないため、リビジョンとしてのみ投稿されます。)

于 2011-02-23T14:06:22.940 に答える