Pythonジェネレータと関数が「def」キーワードを共有するのはなぜですか?


10

以下を検討してください。

def some_function():
    return 1

def some_generator():
    yield 1

上記のコードでsome_functionは、は関数some_generatorですが、はジェネレーターです。それらは非常に似ています。

コードを読み取るときに発生する問題は、「関数」のすべての行をスキャンして、yield実際に関数なのかジェネレータなのかを判断する前に、キーワードを探す必要があることです。

ジェネレーターに別のキーワードを使用する方が理にかなっているように思えます、例えば:

gen some_generator():
    yield 1

defジェネレータと関数の両方にキーワードを使用するメリットは何ですか?関数とジェネレータを分離するために新しいキーワードが導入されていないのはなぜですか?


本当の答えはわかりませんが、リストを返す関数を書き始め、それが正しいと思われるときにジェネレーターに変換することがよくあります。構文を一致させると、これがより自然になります。
Gort the Robot、2015

2
@StevenBurnap Derekが提案するgen代わりにのようなものを使用するdefことは、その変換を大幅に面倒にすることにはなりません。
jamesdlin 2015年

2
一般に、言語デザイナーは通常、不要なキーワードを追加しないようにします。追加するキーワードはすべて、プログラムが他の目的で使用することを許可されていない識別子です。
jamesdlin 2015年

@jamesdlin:しかし、質問は新しいキーワードが必要になるだろうと主張しています。
ジョルジョ

1
@jamesdlin:もちろん、関数とジェネレーターは、本体を見ることで区別できますが、別のキーワードを使用するとコードが読みやすくなるという疑問があります。
ジョルジョ

回答:


14

「ジェネレータと関数の両方にdefキーワードを使用するメリットは何ですか?」

それらは機械的に異なりますが、実際に私がそれらを使用する場合、それらは概念的には事実上同じであることがよくあります(range()vs を呼び出すことについてはあまり考えていませんxrange())。

関数の内容をすばやく理解するという観点からは、を使用すると何かが失われることに同意しますがdef、関数内で物事が難読化されすぎてはいけません。

暗黙的であっても、return None長い条件文の後に関数の意図された動作を混乱させる可能性があります(return None最終的な動作またはロジックの見落としとして意図されていたように)。しかし、それらはそれについての私の信念にすぎません。

私の主張は特に説得力があるとは思わないので、私はPEP 255そのまま使用します。

問題:「def」の代わりに別の新しいキーワード(たとえば、「gen」または「generator」)を導入するか、構文を変更して、ジェネレーター関数と非ジェネレーター関数を区別します。

短所:実際には(あなたがそれらについてどう思うか)、ジェネレーター 関数ですが、ひねりを加えて再開可能です。それらがどのように設定されるかのメカニズムは比較的小さな技術的な問題であり、新しいキーワードを導入することは、ジェネレーターがどのように開始されるかのメカニズム(ジェネレーターの人生の重要な、しかしごく一部)を過度に強調するのに役立ちます。

プロ:実際には(あなたがどう思うか)、ジェネレーター関数は実際にはまるで魔法のようにジェネレーターイテレーターを生成するファクトリー関数です。この点で、それらは非ジェネレーター関数とは根本的に異なり、関数よりもコンストラクターのように振る舞うので、「def」を再利用することはせいぜい混乱するだけです。体内に埋め込まれた「収量」ステートメントは、セマンティクスが非常に異なることを示す十分な警告ではありません。

BDFL:「def」が残ります。どちらの議論も完全に説得力があるわけではないので、言語デザイナーの直感に相談しました。PEPで提案されている構文は正確であり、暑すぎず、寒すぎないことがわかります。しかし、ギリシャ神話に登場するDelphiのOracleのように、その理由はわかりません。そのため、PEP構文に対する引数に対する反論はありません。私が思いつくことができる最高の(反論に同意することを除いて...すでに作られた)は "FUD"です。これが最初から言語の一部だったとしたら、それがAndrew Kuchlingの「Python Warts」ページになったのではないかと私は大いに疑っています。


1
PEP 492で追加された新しいawait(および async withand async for)構文構成体は、と非常によく似ており、justの代わりにを使用して宣言するために、それらが使用されている関数を必要とすることに注意してください。yield fromasync defdef
Feuermurmel、2015

2
  1. 新しいキーワードを追加すると、既存のプログラムが壊れるリスクがあります。 言語デザイナーは一般に、新しい言語を追加しないようにします。特に、言語がすでに人気を得た後に追加された言語機能の場合はそうです。追加するすべてのキーワードは、プログラムが他の目的で使用することを許可されていない識別子であるため、キーワードを追加すると既存のプログラムが壊れる可能性があります。言語設計者は、新しいキーワードの利点とコストを比較検討する必要があります。

  2. ジェネレーターに個別のキーワードを定義することには多くのメリットがあるとは思えません。シンボルが関数の名前に対応するかジェネレーターの名前に対応するかを理解することは、呼び出し元にとって重要なことであり、呼び出し元はそれを実装するために使用されたキーワードを調べる必要がない(場合によってはできない)はずです。これは、より良い命名規則とドキュメントの責任です。


1

ジェネレータは、遅延評価する関数です。それらは基本的に同じものであることを考えると、同じキーワードを使用することは理にかなっています。1つのオプションは、コメントを使用して、特定のインスタンスのどれがどれかを識別することです。

def some_function(): #This is a function.
    return 1

def some_generator(): #This is a generator.
    yield 1

0

私はそれがよりPythonicであるからだと思いますが、私は何を知っていますか?;)

そんなに大事なことだとは思いません。両方を覚える必要がないので、覚えやすくなります。

編集:PEPは言うかもしれません、あなたはそこで調査することができます。


ありがとう!実際、PEPは言っています!ジェネレーターの新しいキーワードに関する賛否両論と最終決定については、PEP-255を参照してください。
Derek Kwok、2015年

Pythonicの意味:「Pythonで行われる方法」?
ジョルジオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.