return、return None、no return no?


386

次の3つの関数について考えてみます。

def my_func1():
  print "Hello World"
  return None

def my_func2():
  print "Hello World"
  return

def my_func3():
  print "Hello World"

それらはすべてNoneを返すようです。これらの関数の戻り値の動作に違いはありますか?どちらか一方を好む理由はありますか?


40
文体の違いがあることに注意してください。return None関数には非None戻り値が含まれる場合があるが、の場所return Noneにはそのような戻り値がないことを意味します。「no」returnと書くことは、「関数」ではなく「プロシージャ」のような興味深い戻り値がないことを意味します。return前のポイントの「手順」から早期に存在することを意味します。

回答:


500

実際の動作には違いはありません。彼らはすべて戻ってきてNone、それだけです。しかし、これらすべての時間と場所があります。以下の説明は基本的にさまざまな方法の使用方法(または少なくとも私が教えられた方法を使用する方法)ですが、絶対的なルールではないため、必要に応じてそれらを混同することができます。

使用する return None

これは、この関数が実際に後で使用するために値を返すことを意図しており、この場合はを返すことを示していますNone。この値Noneは他の場所で使用できます。return None関数からの戻り値が他にない場合は使用されません。

次の例では、指定されたものが人間personmother場合にを返しpersonます。人間でない場合Noneは、personがないmotherます(動物ではないものとしましょう)。

def get_mother(person):
    if is_human(person):
        return person.mother
    else:
        return None

使用する return

これは同じ理由で使用されます break、ループれます。戻り値は問題ではなく、関数全体を終了したいだけです。頻繁には必要ない場合でも、一部の場所では非常に役立ちます。

私たちは15 prisoners人で、そのうちの1人がナイフを持っていることを知っています。それぞれをprisoner1つずつループして、ナイフがあるかどうかを確認します。ナイフで人に当たった場合、ナイフは1つしかなく、残りのをチェックする理由がないため、関数を終了できprisonersます。prisonerナイフでが見つからない場合は、警告を発します。これはさまざまな方法で行うことができ、使用することreturnはおそらく最善の方法でさえありませんが、これreturnは関数を終了するための使用方法を示すための単なる例です。

def find_prisoner_with_knife(prisoners):
    for prisoner in prisoners:
        if "knife" in prisoner.items:
            prisoner.move_to_inquisition()
            return # no need to check rest of the prisoners nor raise an alert
    raise_alert()

注:var = find_prisoner_with_knife()戻り値はキャッチされることを意図していないため、絶対に実行しないでください。

全く使用していないreturnすべてで

これもを返しNoneますが、その値は使用またはキャッチされることを意図していません。それは単に関数が正常に終了したことを意味します。基本的には同じですreturnvoid、このようなC ++やJavaなどの言語で機能します。

次の例では、人の母親の名前を設定し、関数は正常に完了した後に終了します。

def set_mother(person, mother):
    if is_human(person):
        person.mother = mother

注:var = set_mother(my_person, my_mother)戻り値はキャッチされることを意図していないため、絶対に実行しないでください。


5
var = get_mother()var受け入れる他の関数にパスしている場合は問題ありませんNone-「決して」は少し極端です
joelb

var = get_mother()使用できない場合、戻り値をどのように受け入れる必要がありますか?私見それを行うのは全く問題ありません。None値をif var使用する前に、値がないかどうかを確認する必要があります。
winklerrr 2018

これは単なる良い慣例ではなく、PEP8で必要とされていることを言及することが重要だと思いました。私はあなたの賛辞に答えを投稿し、これについてPEP8を引用します。
Fabiano

29

はい、すべて同じです。

解釈されたマシンコードを確認して、それらがすべてまったく同じことを行っていることを確認できます。

import dis

def f1():
  print "Hello World"
  return None

def f2():
  print "Hello World"
  return

def f3():
  print "Hello World"

dis.dis(f1)
    4   0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE

    5   5 LOAD_CONST    0 (None)
        8 RETURN_VALUE

dis.dis(f2)
    9   0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE

    10  5 LOAD_CONST    0 (None)
        8 RETURN_VALUE

dis.dis(f3)
    14  0 LOAD_CONST    1 ('Hello World')
        3 PRINT_ITEM
        4 PRINT_NEWLINE            
        5 LOAD_CONST    0 (None)
        8 RETURN_VALUE      

4
ここで注意してください... dis.dis戻り値None:-X
mgilson

文字列としてdisの出力を取得する唯一の方法は、stdoutをある種のIOバッファー(StringIOなど)にリダイレクトすることです。それでも、dis.disいくつかの行番号が報告されていると思うので、直接比較しても機能しない場合があります...
mgilson

とにかくまったく同じレジスタを使用しているかどうかは関係ないので、コードを変更して、なんらかの間抜けな文字列比較を行う代わりに、今すぐマシンコードを目で見てみます。非常に大きな頭を上げてくれてありがとう。
David Marx

19

それらはそれぞれ同じシングルトンを返しますNone-機能的な違いはありません。

return関数から早く抜け出す必要がある場合(この場合はベアのreturn方が一般的です)、または以外のものを返す必要がない限り、ステートメントを省略するのはかなり慣用的だと思いますNone。それは理にかなっておりreturn None、それが以外のものを返す別のパスを持つ関数内にあるときに書くのは慣用的なようですNone。書き込みreturn None明示的にはもっと面白い(とコードを呼び出すと、おそらく、戻り値の両方のタイプを処理する必要があることを)何かを返す別のブランチがあることを読者に視覚的な手がかりです。

多くの場合、Pythonでは、返さNoneれるvoid関数はCの関数のように使用されます-その目的は、一般に、入力引数適切に操作することです(グローバルデータ(shudders)を使用している場合を除く)。None通常、戻ることにより、引数が変更されたことがより明確になります。これによりreturn、「言語の慣習」の観点からステートメントを省略することが理にかなっている理由がもう少し明確になります。

とは言っても、これらの事柄に関して事前に決められた規則が既にあるコードベースで作業している場合は、コードベースが統一された状態を維持できるように、私は間違いなく追随します...


1
または、より一般的には、関数はreturnステートメントにヒットすることなく終了すると、を返しますNone

関数が値を返すことが期待される場合、returnステートメントを省略することは慣用的ではありません。副作用のみを介して動作する関数のみがreturnステートメントを省略できます。
分子

@molecule-ええ、私はおそらくここでの説明で最高の仕事をしなかったと思います。私はそれを上記の(はるかに良い)答えの完全なクローンにせずに更新しようとしました。私はまだこの投稿にとても満足していません...私の一部はそれを削除したいと思っています(上の答えはとても良いので)そして私の一部はそれを保持したいと思っています-これまでのところ9人がそれが良いと思っていました何らかの理由で。多分私は誰かが逃した何かにぶつかったのですか?
mgilson 2016年

1
@ZAB-それは可能ではないと思います。Pythonでは、何でも何でもモンキーパッチを適用できます(これは設計によるものであり、慎重に使用すると優れた機能です)。具体的には、戻り値のある関数と戻り値のない関数をサルパッチングできます。すべての「式ではない」チェックは解析時に行われますが、モンキーパッチのため、実行時までこれは起こりませんでした。IOW、それは完全に異なります。個人的には、現在の振る舞いはかなり合理的である(そして他の高水準言語と整合している)と思いますが、私はあなたが説得する必要があるものではありません:-)。
mgilson 2018年

1
@ZAB -の両方RubyJavascriptのpythonと同じアプローチを取ります。表現に「ボイド」と言っている高級言語の例は確かにありますが、現時点では考えられません(おそらくJava、高級言語を考えれば)...サルのパッチはどうでしょうか。関数(とりわけテストのモックに役立つ)は、Pythonがvoidキーワードを取得して関数が何も返さないという架空の世界で機能しますか?(また、前に述べたように、これが悪いデザインであることを私に納得させる必要はありません。正しいとしても、私は何もできません)
mgilson

4

他の人が答えたように、結果はまったく同じでNoneあり、すべての場合に返されます。

違いは文体的なものですが、PEP8では一貫した使用が必要であることに注意してください。

returnステートメントで一貫している。関数内のすべてのreturnステートメントが式を返すか、どれも返さないかのどちらかです。returnステートメントが式を返す場合、値が返されないすべてのreturnステートメントは、これをreturn Noneとして明示的に示す必要があり、明示的なreturnステートメントが関数の最後にある必要があります(到達可能な場合)。

はい:

def foo(x):
    if x >= 0:
        return math.sqrt(x)
    else:
        return None

def bar(x):
    if x < 0:
        return None
    return math.sqrt(x)

番号:

def foo(x):
    if x >= 0:
        return math.sqrt(x)

def bar(x):
    if x < 0:
        return
    return math.sqrt(x)

https://www.python.org/dev/peps/pep-0008/#programming-recommendations


基本的Noneに、関数で値以外を返す場合、それは戻り値に意味があり、呼び出し元によってキャッチされることを意味します。したがって、を返すときはNone、それも明示的である必要があります。Noneこの場合、意味があることを伝えるために、これは可能な戻り値の1つです。

返す必要がない場合、関数は基本的に関数ではなくプロシージャとして機能するため、returnステートメントを含めないでください。

プロシージャのような関数を作成していて、前に戻る機会がある場合(つまり、その時点ですでに完了しており、残りの関数を実行する必要がない場合)、空のreturnsを使用してリーダーに信号を送ることができます。これは実行の初期段階に過ぎず、None暗黙的に返される値には意味がなく、キャッチすることを意図していません(プロシージャのような関数は常にNoneとにかく戻ります)。


3

機能の点ではこれらはすべて同じですが、それらの違いはコードの可読性とスタイル(検討することが重要です)です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.