- Python
Pythonのanyとallの使い方|リストの条件判定と内包表記の早見表
anyとは「1つでも真ならTrue」、allとは「すべて真ならTrue」を返すPythonの組み込み関数です。 どちらもリストなどのイテラブル(for文で1つずつ取り出せるもの)を1つ受け取り、True か False を返します。条件を付けたいときは any(x > 0 for x in nums) のように、かっこの中に内包表記の形で条件を書きます。
この記事では、空リスト・0・空文字・Noneを含む入力ごとの結果を早見表にし、「1つでも含む」「すべて満たす」「1つも満たさない」「ちょうど1つ」といった判定をコピペ用の逆引き表にまとめました。 さらに、ジェネレータ式とリスト内包表記で途中打ち切りが効くかどうかを timeit で計測し、for文とbreakでの書き方との対応、辞書・文字列・NumPy・pandasでの違いまで扱います。コードはすべて Python 3.11.15(NumPy 2.4.4、pandas 3.0.2)で実行し、出力をそのまま載せています。
anyとallの早見表
まずは2つの関数の違いと、よく使う書き方を1枚にまとめます。
| 項目 | any | all |
|---|---|---|
| 意味 | 1つでも真なら True | すべて真なら True |
| 空のイテラブルを渡したとき | False | True |
| 評価を打ち切るタイミング | 最初の真の要素を見つけたとき | 最初の偽の要素を見つけたとき |
| 同じ意味の論理演算 | a or b or c |
a and b and c |
| 戻り値 | 必ず True か False | 必ず True か False |
| 引数 | イテラブルを1つだけ | イテラブルを1つだけ |
やりたいことから書き方を探すときは、次の表を使ってください(詳しい逆引き表は後半にあります)。
| やりたいこと | 書き方 |
|---|---|
| 1つでも条件を満たすか | any(条件 for x in xs) |
| すべて条件を満たすか | all(条件 for x in xs) |
| 1つも条件を満たさないか | not any(条件 for x in xs) |
| 満たさないものが1つでもあるか | not all(条件 for x in xs) |
| ちょうど1つ満たすか | sum(条件 for x in xs) == 1 |
| ある値を含むか | 値 in xs |
| 空ではなく、かつすべて満たすか | bool(xs) and all(条件 for x in xs) |
anyとallの基本の使い方
最初に、いちばん基本の形を動かしてみます。ファイルに保存して python3 ファイル名.py で実行できます。
scores = [72, 85, 90, 58]
# any: 1つでも条件を満たせば True
print(any(s >= 90 for s in scores)) # 90点以上が1人でもいるか
# all: すべてが条件を満たせば True
print(all(s >= 60 for s in scores)) # 全員が60点以上か
# 条件を書かずに渡すと、要素そのものの真偽で判定する
print(any([0, "", None])) # 全部「偽」の値
print(all([1, "a", [0]])) # 全部「真」の値
実行結果(Python 3.11.15):
True
False
False
True
ポイントは2つです。
- 条件を付けるときは、かっこの中に「条件 for 変数 in リスト」と書く(これをジェネレータ式と呼びます。リスト内包表記から角かっこを取った形です)。
- 条件を書かずにリストをそのまま渡すと、要素そのものが真か偽かで判定する。Python では 0、0.0、空文字、None、空のリスト・辞書・タプルなどが「偽」として扱われ、それ以外は「真」として扱われます。
Python の公式ドキュメント(組み込み関数のページ)では、all は「iterable の全ての要素が真ならば(もしくは iterable が空ならば)True を返す」、any は「iterable のいずれかの要素が真ならば True を返し、空なら False を返す」と説明されています。今回このページを開いて確かめました。
入力ごとの結果がわかる真理値の早見表
「0 が入っていたらどうなるのか」「None だけのリストはどうか」といった疑問に、実行結果で答えます。次のスクリプトで16通りの入力を一度に確かめました。
cases = [
[], [True, True], [True, False], [False, False],
[0], [0, 1], [1, 2, 3], [0.0],
[""], ["", "a"], ["a", "b"], ["0"],
[None], [None, 1], [[]], [[], [0]],
]
print(f"{'入力':<16}{'any':<7}{'all'}")
for c in cases:
print(f"{c!r:<18}{any(c)!s:<7}{all(c)}")
実行結果:
入力 any all
[] False True
[True, True] True True
[True, False] True False
[False, False] False False
[0] False False
[0, 1] True False
[1, 2, 3] True True
[0.0] False False
[''] False False
['', 'a'] True False
['a', 'b'] True True
['0'] True True
[None] False False
[None, 1] True False
[[]] False False
[[], [0]] True False
同じ結果を、理由つきの表にまとめます。
| 入力 | any | all | 読み方 |
|---|---|---|---|
[] |
False | True | 空。anyは「真が1つもない」、allは「偽が1つもない」 |
[True, True] |
True | True | すべて真 |
[True, False] |
True | False | 真と偽が混ざる |
[False, False] |
False | False | すべて偽 |
[0] |
False | False | 数値の0は偽 |
[0, 1] |
True | False | 1が真、0が偽 |
[1, 2, 3] |
True | True | 0以外の数値は真 |
[0.0] |
False | False | 小数の0.0も偽 |
[""] |
False | False | 空文字は偽 |
["", "a"] |
True | False | 空でない文字列は真 |
["0"] |
True | True | 文字列の"0"は空ではないので真 |
[None] |
False | False | Noneは偽 |
[None, 1] |
True | False | Noneと真の値が混ざる |
[[]] |
False | False | 中身が空リスト1つ。空リストは偽 |
[[], [0]] |
True | False | [0] は空ではないので真 |
覚え方は「anyは真を探す、allは偽を探す」です。 any は真が1つ見つかれば True、最後まで見つからなければ False。all は偽が1つ見つかれば False、最後まで見つからなければ True になります。
つまずきやすいのは次の3点です。
- 文字列の "0" や "False" は真です。フォームやCSVから読み込んだ値は文字列なので、数値として判定したいときは
int(x) != 0のように変換してから条件を書きます。 [[]]は「空リストが1つ入ったリスト」で、空ではありません。中の要素(空リスト)が偽なので、any も all も False になります。- 0 を「有効な値」として扱いたいときは、要素そのものの真偽ではなく
all(x is not None for x in xs)のように条件を明示します。
all([])がTrueになる理由
all([]) が True になるのは、仕様としてそう決められているからで、理由は3つの見方で説明できます。
1. 「偽の要素が1つもない」から
all は「偽の要素を探して、見つかったら False を返す」関数です。空のリストには要素がないので、偽の要素も見つかりません。したがって True が返ります。公式ドキュメントに載っている同等のコードを見ると、この動きがそのまま読み取れます。
def all(iterable):
for element in iterable:
if not element:
return False
return True # 一度もループに入らなければ、ここに来る
def any(iterable):
for element in iterable:
if element:
return True
return False # 一度もループに入らなければ、ここに来る
2. リストを分割しても結果が変わらないようにするため
all(a + b) は all(a) and all(b) と同じ結果になるのが自然です。ここで b が空リストだった場合、all(a) and all([]) が all(a) と一致するには、all([]) が True である必要があります。同じ考え方で、any(a + b) が any(a) or any(b) と一致するには、any([]) は False である必要があります。足し算で「何も足さない」が 0、掛け算で「何も掛けない」が 1 になるのと同じ関係です。
3. 日常の言葉でも成り立つから
「この箱に入っているペンはすべて赤い」という文は、箱が空のときに反例(赤くないペン)を1本も示せません。論理学ではこれを「空虚な真」と呼び、真として扱います。
とはいえ、「空のときは False にしたい」場面はよくあります。 たとえば「入力された項目がすべて有効か」を調べるとき、項目が0件なら通したくない、という場合です。そのときは空でないことを一緒に確かめます。
items = []
# 空でも True になる
print(all(x > 0 for x in items)) # True
# 空のときは False にしたい
print(bool(items) and all(x > 0 for x in items)) # False
リストやタプルなら bool(items) や len(items) > 0 で空かどうかがわかります。
for文とbreakで書いた場合との対応
any と all は、for文と break で書いていた処理を1行にまとめたものです。対応を並べて確かめます。
nums = [4, 8, 15, 16]
# any と同じ意味の for 文
found = False
for n in nums:
if n > 10:
found = True
break
print(found, any(n > 10 for n in nums))
# all と同じ意味の for 文
ok = True
for n in nums:
if not n > 0:
ok = False
break
print(ok, all(n > 0 for n in nums))
# for-else:break しなかったときだけ else が動く
for n in nums:
if n < 0:
print("負の数があります")
break
else:
print("負の数はありません")
実行結果:
True True
True True
負の数はありません
| for文での書き方 | any / all での書き方 |
|---|---|
| フラグを False で用意し、条件を満たしたら True にして break | any(条件 for x in xs) |
| フラグを True で用意し、条件を満たさなければ False にして break | all(条件 for x in xs) |
| for-else(break しなかったら else) | if not any(条件 for x in xs): |
関数の中で、見つけたら return True、最後に return False |
return any(条件 for x in xs) |
どちらを選ぶかの目安は「True か False だけがほしいかどうか」です。 判定結果だけがほしいなら any / all が短く書けます。見つけた要素を使って別の処理をしたい、途中でログを出したい、といった場合は for文のほうが読みやすくなります。
途中打ち切りはジェネレータ式で効く
any は真が見つかった時点で、all は偽が見つかった時点で、残りの要素を見ずに結果を返します(短絡評価と呼びます)。ただし、かっこの中をジェネレータ式で書くか、リスト内包表記で書くかで、条件の計算回数が変わります。 条件の関数に print を入れて確かめます。
def check(n):
print(" check", n)
return n >= 3
nums = [1, 3, 5, 7]
print("any + ジェネレータ式")
print(any(check(n) for n in nums))
print("any + リスト内包表記")
print(any([check(n) for n in nums]))
print("all + ジェネレータ式")
print(all(check(n) for n in nums))
実行結果:
any + ジェネレータ式
check 1
check 3
True
any + リスト内包表記
check 1
check 3
check 5
check 7
True
all + ジェネレータ式
check 1
False
- ジェネレータ式(
any(check(n) for n in nums))は、3 で条件が真になった時点で止まり、5 と 7 は調べていません。 - リスト内包表記(
any([check(n) for n in nums]))は、まず角かっこの中で4つすべてを計算してリストを作り、そのあとで any が先頭から見ていきます。any 自体は2つ目で止まりますが、条件の計算はすでに全件終わっています。 - all も同じで、最初の 1 が条件を満たさないとわかった時点で止まっています。
timeitで計測した結果
100万件のリストから値を探す処理で、書き方ごとの時間を計測しました。
import sys
import timeit
N = 1_000_000
data = list(range(N))
def loop(target):
for x in data:
if x == target:
return True
return False
def ms(func):
# 5回実行を3セット行い、最も速いセットの1回あたりをミリ秒で返す
return min(timeit.repeat(func, number=5, repeat=3)) / 5 * 1000
print("Python", sys.version.split()[0], "/ 要素数", N)
for label, t in [("先頭で見つかる", 0), ("中央で見つかる", N // 2), ("見つからない", -1)]:
print(label)
print(f" any(ジェネレータ式) {ms(lambda: any(x == t for x in data)):9.4f} ms")
print(f" any([リスト内包表記]) {ms(lambda: any([x == t for x in data])):9.4f} ms")
print(f" for文 + return {ms(lambda: loop(t)):9.4f} ms")
print(f" in 演算子 {ms(lambda: t in data):9.4f} ms")
実行結果(Python 3.11.15、Linux、2コアの検証用コンテナ。数値は環境によって変わります):
Python 3.11.15 / 要素数 1000000
先頭で見つかる
any(ジェネレータ式) 0.0003 ms
any([リスト内包表記]) 14.7191 ms
for文 + return 0.0001 ms
in 演算子 0.0001 ms
中央で見つかる
any(ジェネレータ式) 11.4067 ms
any([リスト内包表記]) 17.6947 ms
for文 + return 5.2536 ms
in 演算子 2.5307 ms
見つからない
any(ジェネレータ式) 22.3012 ms
any([リスト内包表記]) 19.3807 ms
for文 + return 10.6937 ms
in 演算子 5.0907 ms
| 条件を満たす位置 | any(ジェネレータ式) | any(リスト内包表記) | for文 + return | in 演算子 |
|---|---|---|---|---|
| 先頭 | 0.0003 ms | 14.7191 ms | 0.0001 ms | 0.0001 ms |
| 中央 | 11.4067 ms | 17.6947 ms | 5.2536 ms | 2.5307 ms |
| 見つからない | 22.3012 ms | 19.3807 ms | 10.6937 ms | 5.0907 ms |
この結果から読み取れることは次のとおりです。
- 先頭近くで結果が決まる場合、ジェネレータ式はほぼ一瞬で終わります。 リスト内包表記は見つかる位置に関係なく、毎回100万件分のリストを作るので 15 ms 前後かかりました。
- 最後まで見つからない場合は、リスト内包表記のほうがわずかに速い結果でした(22.3 ms と 19.4 ms)。ジェネレータ式は1件ずつ値を受け渡す手間がかかるためです。ただし差は小さく、リスト内包表記は判定用のリストを丸ごとメモリに作ります。
- for文で書いた関数は、どの場合も any より速い結果でした。 それでも any は1行で意図が伝わるので、ここまでの差が問題になる場面以外では any で十分です。
- 「ある値と等しいものがあるか」だけなら in 演算子が最も速く、書き方も最短です。
迷ったらジェネレータ式で書く、と覚えておけば十分です。 早く止まれる場面で大きな差が付き、止まれない場面でも差はわずかだからです。
途中打ち切りを生かす書き方のこつ
any(a(x) and b(x) for x in xs) のように条件を and でつなぐときは、軽い条件を先に、重い条件(正規表現、ファイルやネットワークへのアクセスなど)を後に書きます。 and は左側が偽なら右側を計算しないので、重い処理の回数を減らせます。
目的別のコピペ用逆引き表
よく使う判定を、番号つきでまとめました。下のコードはそのまま貼って動かせます。
| 番号 | やりたいこと | 書き方 |
|---|---|---|
| 1 | 1つでも満たす | any(n > 40 for n in nums) |
| 2 | すべて満たす | all(n > 0 for n in nums) |
| 3 | 1つも満たさない | not any(n < 0 for n in nums) |
| 4 | 満たさないものが1つでもある | not all(n % 2 == 0 for n in nums) |
| 5 | ちょうど1つ満たす | sum(n % 2 == 1 for n in nums) == 1 |
| 6 | 2つ以上満たす、個数を数える | sum(n % 2 == 0 for n in nums) >= 2 |
| 7 | ある値を含む | 15 in nums |
| 8 | 複数の値をすべて含む、どれか含む | all(x in nums for x in (4, 8)) |
| 9 | 空文字がある、すべて入力済み | any(w == "" for w in words)、all(words) |
| 10 | 文字列がキーワードのどれかを含む | any(k in text for k in keywords) |
| 11 | すべての文字が数字 | all(c.isdigit() for c in text) |
| 12 | 昇順に並んでいる | all(a <= b for a, b in zip(nums, nums[1:])) |
| 13 | すべて同じ値、重複がない | all(x == nums[0] for x in nums)、len(set(nums)) == len(nums) |
| 14 | 空ではなく、かつすべて満たす | bool(nums) and all(n > 0 for n in nums) |
| 15 | Noneが1つもない、型が混ざっている | all(x is not None for x in xs) |
| 16 | 最初に条件を満たした要素を取り出す | next((n for n in nums if n > 10), None) |
| 17 | 判定しつつ見つけた値を残す | any((hit := n) > 20 for n in nums) |
nums = [4, 8, 15, 16, 23, 42]
words = ["apple", "", "cherry"]
# 1. 1つでも満たす
print(1, any(n > 40 for n in nums))
# 2. すべて満たす
print(2, all(n > 0 for n in nums))
# 3. 1つも満たさない(すべて満たさない)
print(3, not any(n < 0 for n in nums))
# 4. 満たさないものが1つでもある
print(4, not all(n % 2 == 0 for n in nums))
# 5. ちょうど1つ満たす
print(5, sum(n % 2 == 1 for n in nums) == 1)
# 6. 2つ以上満たす / 満たす個数を数える
print(6, sum(n % 2 == 0 for n in nums) >= 2, sum(n % 2 == 0 for n in nums))
# 7. ある値を含む(等しいかどうかだけなら in が最短)
print(7, 15 in nums)
# 8. 複数の値をすべて含む / どれか1つ含む
print(8, all(x in nums for x in (4, 8)), any(x in nums for x in (99, 42)))
# 9. 空文字が1つでもある / すべて入力済み
print(9, any(w == "" for w in words), all(words))
# 10. 文字列がキーワードのどれかを含む
print(10, any(k in "error: disk full" for k in ("error", "warn")))
# 11. すべての文字が数字(空文字は True になる点に注意)
print(11, all(c.isdigit() for c in "12345"), all(c.isdigit() for c in ""))
# 12. 昇順に並んでいる
print(12, all(a <= b for a, b in zip(nums, nums[1:])))
# 13. すべて同じ値 / 重複がない
print(13, all(x == nums[0] for x in nums), len(set(nums)) == len(nums))
# 14. 空ではなく、かつすべて満たす
print(14, bool(nums) and all(n > 0 for n in nums), bool([]) and all(n > 0 for n in []))
# 15. None が1つもない / 文字列が混ざっている
print(15, all(x is not None for x in [1, None]), any(isinstance(x, str) for x in [1, "a"]))
# 16. 最初に条件を満たした要素そのものがほしい
print(16, next((n for n in nums if n > 10), None), next((n for n in nums if n > 100), None))
# 17. 判定と同時に、見つかった値を変数に残す(Python 3.8 以降)
if any((hit := n) > 20 for n in nums):
print(17, hit)
実行結果:
1 True
2 True
3 True
4 True
5 False
6 True 4
7 True
8 True True
9 True False
10 True
11 True True
12 True
13 False True
14 True False
15 False True
16 15 None
17 23
補足です。
- 5と6の「個数を数える」 は、True が 1、False が 0 として足し算できる性質を使っています。sum は最後まで数えるので、途中打ち切りは効きません。
- 3と4は書き換えができます。 「1つも満たさない」は「すべてが条件の逆を満たす」と同じなので、
not any(n < 0 for n in nums)はall(n >= 0 for n in nums)とも書けます。読んで意味が伝わりやすいほうを選びます。 - 11の空文字は、all の性質どおり True になります。空文字を除きたいときは
text != "" and all(...)とするか、文字列全体にtext.isdigit()を使います(空文字なら False)。 - 16は any ではなく next を使います。 any が返すのは True / False だけなので、要素そのものがほしいときは next にジェネレータ式と既定値を渡します。
- 17の
:=(代入式) は Python 3.8 以降で使えます。any が True を返したときだけ、hit に見つかった値が入っています。
not any と not all の言い換え表
| 書き方 | 意味 | 同じ意味の別の書き方 |
|---|---|---|
any(P) |
1つでも満たす | not all(Pの逆) |
all(P) |
すべて満たす | not any(Pの逆) |
not any(P) |
1つも満たさない | all(Pの逆) |
not all(P) |
満たさないものがある | any(Pの逆) |
辞書と文字列を渡したときの動き
リスト以外を渡したときの動きも確かめます。
stock = {"pen": 0, "note": 2, "": 3}
print(any(stock), all(stock)) # キーを見る("" は偽)
print(any(stock.values()), all(stock.values())) # 値を見る(0 は偽)
print(all(v >= 0 for v in stock.values())) # 値に条件を付ける
print(any(k == "note" and v == 2 for k, v in stock.items())) # キーと値の組
print(any("abc"), all("abc")) # 文字列は1文字ずつ見る
print(any(""), all("")) # 空文字は「空のイテラブル」
print(all("0"), all(["0", "False"])) # 文字列の "0" や "False" は真
print(all([[], []]), any([[0]])) # 入れ子:空リストは偽、[0] は空でないので真
実行結果:
True False
True False
True
True
True True
False True
True True
False True
| 渡すもの | 判定される対象 | 気を付ける点 |
|---|---|---|
| 辞書そのもの | キー | 値を見たいときは .values() を付ける |
辞書.values() |
値 | 0 や空文字の値は偽 |
辞書.items() |
キーと値のタプル | 条件式の中で for k, v in と分けて使う |
| 文字列 | 1文字ずつ | 1文字以上あればどの文字も真。空文字は空のイテラブル |
| 集合・タプル・range | 各要素 | リストと同じ |
辞書をそのまま渡すとキーを見る点が、いちばん気付きにくいところです。 「在庫が1つでもある品目があるか」を調べたいなら any(stock.values())、「すべての在庫が0以上か」なら all(v >= 0 for v in stock.values()) と書きます。
NumPyとpandasでの違い
NumPy の配列や pandas の Series・DataFrame には、専用の any と all が用意されています。組み込みの any / all とは動きが違うので、分けて覚えます。
NumPyの配列
import numpy as np
a = np.array([[1, 0],
[3, 4]])
print(a.any(), a.all()) # 配列全体
print(a.all(axis=0)) # 列ごと
print(a.any(axis=1)) # 行ごと
print((a > 0).all(), np.any(a > 3)) # 条件を付ける
# 2次元配列を組み込みの any に渡すとエラーになる
try:
any(a)
except ValueError as e:
print("ValueError:", e)
# 空の配列・NaN
print(np.array([]).any(), np.array([]).all())
print(np.array([np.nan]).all()) # NaN は 0 ではないので真
実行結果(NumPy 2.4.4):
True False
[ True False]
[ True True]
False True
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
False True
True
- 配列には
a.any()/a.all()(またはnp.any(a)/np.all(a))を使います。axis=0で列ごと、axis=1で行ごとの結果が配列で返ります。 - 2次元配列を組み込みの any に渡すと ValueError になります。 組み込みの any は行を1つずつ取り出して真偽を調べますが、要素が2つ以上ある配列は真偽を1つに決められないためです。エラー文にも
a.any()かa.all()を使うよう書かれています。 - 1次元配列なら組み込みの any でも動きますが、同じ100万件の配列で計測したところ、
(arr == N - 1).any()が約 0.45 ms、any(arr == N - 1)が約 8.2 ms でした。配列には配列のメソッドを使うほうが速くなります。 - NumPy のメソッドは配列全体をまとめて計算するので、途中打ち切りの考え方は組み込み関数とは別です。
pandasのSeriesとDataFrame
import numpy as np
import pandas as pd
s = pd.Series([1, 0, 3])
df = pd.DataFrame({"x": [1, 2, 3], "y": [0, 5, 6]})
print(s.any(), s.all()) # Series 全体
print((s > 0).all(), (s > 2).any()) # 条件を付ける
print(df.all()) # 列ごと(既定は axis=0)
print(df.any(axis=1)) # 行ごと
print((df > 0).all(axis=None)) # 表全体で1つの結果
# 組み込みの any / all に DataFrame を渡すと「列名」を見る
print(any(df), all(df), list(df))
# 空の Series と NaN
e = pd.Series([], dtype=float)
print(e.any(), e.all())
n = pd.Series([np.nan, np.nan])
print(n.any(), n.all()) # 既定は skipna=True
print(n.any(skipna=False), n.all(skipna=False))
# if に Series をそのまま渡すとエラーになる
try:
if s > 0:
pass
except ValueError as e:
print("ValueError:", e)
実行結果(pandas 3.0.2):
True False
False True
x True
y False
dtype: bool
0 True
1 True
2 True
dtype: bool
False
True True ['x', 'y']
False True
False True
True True
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
df.all()は列ごとの結果を返します(既定はaxis=0)。行ごとならaxis=1、表全体で1つの結果がほしいときはaxis=Noneを指定します。- 組み込みの
any(df)は列名を見ます。 DataFrame を for文で回すと列名が取り出されるためで、中身の値は判定されません。DataFrame には必ず.any()/.all()メソッドを使います。 - NaN は既定で読み飛ばされます(
skipna=True)。すべて NaN の Series は、空の Series と同じく any が False、all が True になりました。skipna=Falseを指定すると NaN は 0 ではない値として真に数えられます。 - if に Series をそのまま渡すと ValueError になります。
if (s > 0).all():やif (s > 0).any():のように、どちらの意味かを明示します。
組み込み・NumPy・pandasの比較表
| 項目 | 組み込み any / all | NumPy | pandas |
|---|---|---|---|
| 書き方 | any(xs) |
a.any()、np.any(a) |
s.any()、df.any() |
| 条件の付け方 | any(x > 0 for x in xs) |
(a > 0).any() |
(s > 0).any() |
| 戻り値 | True / False | NumPyの真偽値、または配列 | 真偽値、または Series |
| 行・列ごとの判定 | なし | axis=0、axis=1 |
axis=0、axis=1、axis=None |
| 空のとき | any は False、all は True | 同じ | 同じ |
| NaN の扱い | 真 | 真 | 既定では読み飛ばす |
| 途中打ち切り | あり | 全体をまとめて計算 | 全体をまとめて計算 |
つまずきやすい点とエラー文
実際に出るエラー文と、気付きにくい動きを再現します。
nums = [4, 8, 15]
# 1. イテラブルでないものを渡す
try:
any(5)
except TypeError as e:
print("TypeError:", e)
# 2. 値を2つ並べて渡す
try:
any(1, 2)
except TypeError as e:
print("TypeError:", e)
# 3. ジェネレータ式そのものを if に渡す(any を付け忘れた形)
gen = (n > 100 for n in nums)
print(bool(gen)) # 中身に関係なく True
print(bool([n > 100 for n in nums])) # 空でないリストなので True
print(any(n > 100 for n in nums)) # 正しくは any で包む
# 4. イテレータは読んだ分だけ進む
it = iter([0, 0, 5, 0, 7])
print(any(it), list(it))
実行結果:
TypeError: 'int' object is not iterable
TypeError: any() takes exactly one argument (2 given)
True
True
False
True [0, 7]
| 症状 | 原因 | 直し方 |
|---|---|---|
'int' object is not iterable |
数値など、for文で回せないものを渡した | リストやタプルに入れて渡す |
any() takes exactly one argument (2 given) |
値をカンマで並べて渡した | any([a, b]) のように1つにまとめる。2つ程度なら a or b で足りる |
| if の条件がいつも True になる | any / all を付けずにジェネレータ式やリストを if に渡した | if any(...) と包む |
| 2回目の判定結果が変わる | イテレータやジェネレータを使い回した | リストにしてから渡すか、毎回作り直す |
The truth value of an array ... is ambiguous |
NumPy配列や Series を組み込みの any や if に渡した | .any() / .all() メソッドを使う |
4つ目は少しわかりにくいので補足します。iter() で作ったイテレータやジェネレータは、一度読んだ要素を戻せません。上の例では any が 5 を見つけた時点で止まり、残りの [0, 7] だけがイテレータに残りました。同じデータを何度も判定するときは、リストのまま持っておきます。
直す前と直した後
# 直す前:フラグ変数と for 文
has_error = False
for line in lines:
if "ERROR" in line:
has_error = True
break
if has_error:
notify()
# 直した後:any で1行に
if any("ERROR" in line for line in lines):
notify()
# 直す前:リスト内包表記(全件を計算してから判定)
if all([is_valid(row) for row in rows]):
save(rows)
# 直した後:ジェネレータ式(偽が見つかった時点で止まる)
if all(is_valid(row) for row in rows):
save(rows)
この2つのコードは形の説明用で、lines や rows、notify などは定義していないため、このままでは実行していません(未実行)。
どの書き方を選ぶかの判断表
| 状況 | 選ぶ書き方 | 理由 |
|---|---|---|
| True / False だけがほしい | any / all + ジェネレータ式 | 短く、途中で止まる |
| ある値と等しい要素があるか | in 演算子 |
最も短く、計測でも最も速い |
| 条件を満たす要素そのものがほしい | next(ジェネレータ式, None) |
any は真偽しか返さない |
| 条件を満たす個数がほしい | sum(条件 for x in xs) |
True を1として数えられる |
| 条件を満たす要素を全部ほしい | リスト内包表記 [x for x in xs if 条件] |
結果をリストで受け取れる |
| 判定の途中で別の処理もしたい | for文 + break | 処理を自由に書ける |
| NumPy配列・pandas | .any() / .all() メソッド |
配列全体をまとめて計算できる |
| 空のときは False にしたい | bool(xs) and all(...) |
all は空で True を返すため |
よくある質問
Q. anyとallは、orやandと何が違いますか?
A. 意味は同じで、扱える個数が違います。a or b or c は値を式の中に並べて書きますが、any はリストなど個数が決まっていないものをまとめて判定できます。また、or と and は真偽値ではなく値そのものを返す(0 or "x" は "x")のに対し、any と all は必ず True か False を返します。
Q. ジェネレータ式とリスト内包表記のどちらで書けばよいですか? A. 基本はジェネレータ式(角かっこなし)です。今回の計測では、先頭で結果が決まる場合にジェネレータ式が 0.0003 ms、リスト内包表記が約 14.7 ms でした。最後まで見つからない場合はリスト内包表記がわずかに速い結果でしたが、差は小さく、判定用のリストをメモリに作らないジェネレータ式のほうが扱いやすくなります。
Q. all([])がTrueになるのは不具合ではないのですか?
A. 仕様です。all は「偽の要素が見つかったら False」を返す関数で、空なら偽の要素が見つからないので True になります。空のときに False にしたい場合は bool(xs) and all(...) と書きます。
Q. 条件を満たした要素を取り出したいときはどうしますか?
A. any ではなく next((x for x in xs if 条件), None) を使います。見つからなかったときは2つ目の引数(ここでは None)が返ります。判定と同時に値を残したい場合は、Python 3.8 以降の代入式を使って any((hit := x) > 20 for x in xs) と書けます。
まとめ
- any は「1つでも真なら True」、all は「すべて真なら True」。空を渡すと any は False、all は True になります。
- 0、0.0、空文字、None、空のリストは偽。文字列の "0" や "False" は真として扱われます。
- all([]) が True なのは「偽の要素が1つもない」から。空を除きたいときは
bool(xs) and all(...)と書きます。 - かっこの中はジェネレータ式で書く。先頭で結果が決まる場合、リスト内包表記との差は 0.0003 ms と約 14.7 ms でした。
- 「1つも満たさない」は not any、「ちょうど1つ」は sum(...) == 1、「要素そのもの」は next を使います。
- 辞書をそのまま渡すとキーを見る。値を見るときは
.values()を付けます。 - NumPy と pandas には
.any()/.all()メソッドを使う。pandas は既定で NaN を読み飛ばします。
参考
- Python 公式ドキュメント「組み込み関数」(all、any の説明と同等のコード): https://docs.python.org/ja/3/library/functions.html
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。