and
とor
は、評価した最後の要素を返しますが、Pythonの組み込み関数any
を返さないのはなぜですか?
このように自分で実装するのはとても簡単だということですが、それでもなぜなのか疑問に思っています。
def any(l):
for x in l:
if x:
return x
return x
編集:
以下の回答に追加するために、この問題に関するあなたがたの強力な皇帝の同じメーリングリストからの実際の引用があります:
常にTrueとFalseを返すのか、それとも最初のフェール/パス要素を返すのか?私もブログを書く前にそれで遊んで、エンドケース(シーケンスが空の場合、またはすべての要素がテストに失敗した場合)を満足のいくものにすることはできないことに気付きました:引数がブール値の反復可能である場合、Noneを選択すると奇妙に感じます、そして引数がブール値以外のオブジェクトの反復可能である場合、Falseを選択すると奇妙に感じます。
Guido van Rossum(ホームページ: http://www.python.org/~guido/ )
この問題は、2005年にGuido VanRossumがPython 2.5にany
とall
を追加することを提案したときにPython開発者のメーリングリストで取り上げられました。
Bill Janssen requested 次のように実装されていること
def any(S):
for x in S:
if x:
return x
return S[-1]
def all(S):
for x in S:
if not x:
return x
return S[-1]
any
とall
を実装したRaymondHettinger、 応答 特にany
とall
がand
およびor
:
時間が経つにつれて、私はこれらや他のitertoolsレシピについてのフィードバックを得てきました。これらのレシピやGuidoのバージョンでは、True/Falseの戻り値に異議を唱える人は誰もいません。
Guidoのバージョンは、いずれか/すべてが述語であるという通常の期待と一致します。また、Python独自の「and」と「or」の実装で現在人々が経験しているようなエラーや混乱を回避します。
最後の要素を返すことは悪ではありません。それは奇妙で、予想外で、自明ではありません。これでトリッキーになりたいという衝動に抵抗してください。
メーリングリストは大体同意し、今日のように実装を残しました。
and
とor
は、常にオペランドの1つを返すように適切に定義できます。ただし、any
とall
は、入力シーケンスから値を返すように常に適切に定義できるとは限りません。具体的には、リストが空の場合はそうすることができません。現在、この状況ではany
とall
の両方で明確に定義された結果が得られます。any
はFalseを返し、all
はTrueを返します。 時々ブール値を返し、時々シーケンスからアイテムを返すことを余儀なくされます。これは、不快で驚くべきインターフェースになります。シンプルで一貫性がある方がはるかに優れています。
開始Python 3.8
、および 代入式(PEP 572) (:=
演算子)、代わりに、any
式の証人または反例を明示的にキャプチャすることもできます。 all
式:
PEPの説明 からいくつかの例を引用するには:
if any(len(long_line := line) >= 100 for line in lines):
print("Extremely long line:", long_line)
if all((nonblank := line).strip() == '' for line in lines):
print("All lines are blank")
else:
print("First non-blank line:", nonblank)
私はこれと同じ質問をしました python-ideas で、その理由はany()
とall()
がシーケンスが空のときに値を返す必要があるためだと言われました。これらの値はFalse
およびTrue
である必要があります。これは私には弱い議論のように思えます。
関数は今は変更できませんが、最初のtrue-ishまたはfalse-を返した場合、それらはより便利であり、一般化するand
およびor
演算子のより良い類似物になると思います。彼らが遭遇したish値。
and
とor
の動作は、歴史的な理由から存在します。
Pythonに三項演算/条件式が含まれる前は、条件に値を使用する場合はand
とor
を使用していました。このような式は次のようになります。条件式構文で書き直されました:
true_val if condition else false_val
基本的に、これらは2つの関数でオーバーロードされており、互換性の理由から、変更されていません。
つまり、not他の操作をオーバーロードする理由です。 any
はそれがあなたに言うべきであるように思われます条件がどのアイテムにも当てはまるかどうか、これはブール値なので、bool
を返す必要があります。
Any
はブール値を返します。これは、引数のいずれかが真であるかどうかを検討する前に、引数をブール値のリストとして効果的に処理するためです。 is評価する要素を返しますが、これはたまたまブール値です。
any
のバージョンをいつ使用しますか?それがブールのリストにあるなら、あなたはすでに正しい答えを持っています。それ以外の場合は、None
から保護しているだけで、次のように表現される可能性があります。
filter(lambda x: x != None, l)[0]
または:
[x for x in l if x != None][0]
これは、より明確な意図の表明です。
any
の値がFalseであるか、入力の値の1つである可能性があるかどうかはすぐにはわかりません。また、ほとんどの用途は次のようになります
tmp = any(iterable)
if tmp:
tmp.doSomething()
else:
raise ValueError('Did not find anything')
それは 飛躍する前に見てください 、したがって非パイソンです。比較:
next(i for i in iterable if i).doSomething()
# raises StopIteration if no value is true
and
とor
の動作は、当時利用できなかった条件式のドロップインとして歴史的に有用でした。