web-dev-qa-db-ja.com

pythonʻany`が値の代わりにブール値を返すのはなぜですか?

andorは、評価した最後の要素を返しますが、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/

45
doda

この問題は、2005年にGuido VanRossumがPython 2.5にanyallを追加することを提案したときに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]

anyallを実装したRaymondHettinger、 応答 特にanyallandおよびor

時間が経つにつれて、私はこれらや他のitertoolsレシピについてのフィードバックを得てきました。これらのレシピやGuidoのバージョンでは、True/Falseの戻り値に異議を唱える人は誰もいません。

Guidoのバージョンは、いずれか/すべてが述語であるという通常の期待と一致します。また、Python独自の「and」と「or」の実装で現在人々が経験しているようなエラーや混乱を回避します。

最後の要素を返すことは悪ではありません。それは奇妙で、予想外で、自明ではありません。これでトリッキーになりたいという衝動に抵抗してください。

メーリングリストは大体同意し、今日のように実装を残しました。

45

andorは、常にオペランドの1つを返すように適切に定義できます。ただし、anyallは、入力シーケンスから値を返すように常に適切に定義できるとは限りません。具体的には、リストが空の場合はそうすることができません。現在、この状況ではanyallの両方で明確に定義された結果が得られます。anyはFalseを返し、allはTrueを返します。 時々ブール値を返し、時々シーケンスからアイテムを返すことを余儀なくされます。これは、不快で驚くべきインターフェースになります。シンプルで一貫性がある方がはるかに優れています。

21
Weeble

開始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)
5
Xavier Guihot

私はこれと同じ質問をしました python-ideas で、その理由はany()all()がシーケンスが空のときに値を返す必要があるためだと言われました。これらの値はFalseおよびTrueである必要があります。これは私には弱い議論のように思えます。

関数は今は変更できませんが、最初のtrue-ishまたはfalse-を返した場合、それらはより便利であり、一般化するandおよびor演算子のより良い類似物になると思います。彼らが遭遇したish値。

5
Ned Batchelder

andorの動作は、歴史的な理由から存在します。

Pythonに三項演算/条件式が含まれる前は、条件に値を使用する場合はandorを使用していました。このような式は次のようになります。条件式構文で書き直されました:

true_val if condition else false_val

基本的に、これらは2つの関数でオーバーロードされており、互換性の理由から、変更されていません。

つまり、not他の操作をオーバーロードする理由です。 anyはそれがあなたに言うべきであるように思われます条件がどのアイテムにも当てはまるかどうか、これはブール値なので、boolを返す必要があります。

3
agf

Anyはブール値を返します。これは、引数のいずれかが真であるかどうかを検討する前に、引数をブール値のリストとして効果的に処理するためです。 is評価する要素を返しますが、これはたまたまブール値です。

anyのバージョンをいつ使用しますか?それがブールのリストにあるなら、あなたはすでに正しい答えを持っています。それ以外の場合は、Noneから保護しているだけで、次のように表現される可能性があります。

filter(lambda x: x != None, l)[0]

または:

[x for x in l if x != None][0]

これは、より明確な意図の表明です。

0
cmh

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

andorの動作は、当時利用できなかった条件式のドロップインとして歴史的に有用でした。

0
phihag