1. ホーム
  2. python

[解決済み] 変数ret_valの使用はいつがよいのでしょうか?

2022-02-07 10:15:10

質問

次のコードが良いかどうか、相反するアドバイスを見たことがあります。

def function():
    ret_val = 0
    if some_condition():
        ret_val = 2
    else:
        ret_val = 3
    return ret_val

とか、こっちの方がいいんじゃない?

def function():
    if some_condition():
        return 2
    else:
        return 3

これは簡単な例で、pythonスタイルで書きましたが、私が探しているのは、戻り値を追跡するためにいくつかの"accumulator"変数をいつ使うか、または複数の出口点を使うかについての一般原則なのです。 言語によって、1つのスタイルを使用する理由が異なることは承知していますので、特定の言語が特定のスタイルに固執する理由についての異なる視点を評価したいと思います。(特に過去には、C言語の構造化プログラミングでは、関数の出口を複数にすることを避けると聞いたことがあります)。

どのように解決するのか?

そもそも、なぜ「複数の終了点」が有害とされたのか、忘れてしまったのでしょうか。 その昔(優れた例外処理と最終的な構成に広くアクセスする前、あるいは auto_ptr これは、多くのマルチエグジット関数につきまとう問題でした。

int function blah(arg1, arg2)
    allocate resource

    if early failure detection
        return failure_status

    ... much later...

    release resource // oh rats! resource didn't release
    return success_status

リソースがメモリである場合、メモリリークが発生します。 もしそれがデータベーストランザクションであれば、悪いデータベースの競合やデッドロックに向かうことになる。 それに関しては、より多くの例外サポートの出現により、我々は暗黙のうちに 多く 処理されない例外によって)メソッドを終了する可能性があります。 C++時代、私はこのような習慣を身につけました。 決して は削除を呼び出すのではなく auto_ptr を実行したときに、割り当てられたメモリがクリーンアップされるようにしました。 auto_ptr がスコープを抜けると、たとえ予期せぬ例外が頭をもたげてきたとしても、です。

ガベージコレクションのPythonの世界では、ファイルやロックなどの多くのオブジェクトがセルフクリーニングの動作を改善しているにもかかわらず、この問題が発生する可能性があります。 しかし、CPython以外の実装(jythonやIronPythonなど)では、デストラクタがいつ呼ばれるか保証はありません。 そのための最初の仕組みが try/finally です。

int function blah(arg1, arg2)
    allocate resource
    try:

        if early failure detection
            return failure_status

        ... much later...
        return success_status

    finally:
        release resource // always releases no matter what

しかし、Pythonには新しい'with'構文と連動したコンテキストマネージャがあります。

int function blah(arg1, arg2)
    allocate resource
    with context_manager(resource): // releases on exit from 'with'

        if early failure detection
            return failure_status

        ... much later...
        return success_status

つまり、この古い慣習を捨てられるのは、新しいコーディング手法によって不要になったからだということを、きちんと伝えましょう。