any() / all() / bool()
| 対応: | Python 2(2000) |
|---|
『any()』はイテラブルの要素のいずれかが真であればTrueを返し、『all()』はすべての要素が真であればTrueを返します。『bool()』は値をTrueまたはFalseに変換します。これらは条件判定をリスト全体に一括適用したいときに役立ちます。
構文
# いずれかがTrueならTrue any(iterable) # すべてがTrueならTrue all(iterable) # 値をbool型に変換 bool(value)
関数一覧
| 関数・演算子 | 概要 |
|---|---|
| any(iterable) | 要素のいずれかが真ならTrue。イテラブルが空の場合はFalse。 |
| all(iterable) | すべての要素が真ならTrue。イテラブルが空の場合はTrue。 |
| bool(value) | valueを真偽値に変換する。 |
| not 式 | 真偽値を反転する。 |
サンプルコード
any_all.py
# any: いずれかが条件を満たすか
nums = [2, 4, 6, 7, 10]
print(any(n % 2 != 0 for n in nums)) # True(7が奇数)
# any: リストに特定の値があるか
items = ['item_a', 'item_b', 'item_c']
print(any(x.startswith('item_b') for x in items)) # True
print(any(x.startswith('z') for x in items)) # False
# all: すべてが条件を満たすか
scores = [80, 90, 75, 88]
print(all(s >= 60 for s in scores)) # True(全員合格)
passwords = ['abc123', 'xyz', 'password!']
print(all(len(p) >= 8 for p in passwords)) # False('xyz'が短い)
# 空のイテラブル
print(any([])) # False(1つも真がない)
print(all([])) # True(反例がない = 真空的真)
# bool: 値の真偽変換
print(bool(0)) # False
print(bool(1)) # True
print(bool('')) # False
print(bool('hello')) # True
print(bool([])) # False
print(bool([0])) # True(0を含むリストは真)
print(bool(None)) # False
# not: 真偽値の反転
x = 5
print(not x > 10) # True
print(not x > 0) # False
# any/all と条件式の組み合わせ
def is_valid_user(user):
required = ['name', 'email', 'age']
return all(key in user for key in required)
user1 = {'name': 'user_1', 'email': 'user_1@wp-p.info', 'age': 20}
user2 = {'name': 'user_2', 'email': 'user_2@wp-p.info'}
print(is_valid_user(user1)) # True
print(is_valid_user(user2)) # False(ageがない)
実行すると次のように出力されます。
python3 any_all.py True True False True False False True False True False True False True False True False True False
よくあるミス
よくあるミス1: all([])がTrueになる
空のイテラブルに対して『all()』は『True』を返します。「全員が条件を満たす」という文脈で空リストを渡すと、意図しない『True』が返ります。
members = [] # 空リスト
# 空リストにall()を使うと常にTrueになる
if all(score > 60 for score in members):
print('全員合格') # ← 誰もいないのに「全員合格」になってしまう
次のように記述します。
# 空チェックを先に行う
if members and all(score > 60 for score in members):
print('全員合格')
else:
print('対象者なし、または不合格者あり')
よくあるミス2: any([])がFalseになる
空のイテラブルに対して『any()』は『False』を返します。「誰かが条件を満たすか」のチェックで空リストを渡すと、常に『False』になります。
candidates = []
# 空リストにany()を使うと常にFalseになる
if not any(score > 90 for score in candidates):
print('高得点者なし') # ← 対象者がいないのに「高得点者なし」と表示される
次のように記述します。
# 空かどうかを区別する
if not candidates:
print('対象者なし')
elif not any(score > 90 for score in candidates):
print('高得点者なし')
よくあるミス3: ジェネレータ式を2回使う
ジェネレータ式は一度消費されると空になります。同じジェネレータを複数の関数に渡すと、2回目は空になります。
scores = [85, 92, 78, 95, 60] gen = (s for s in scores if s > 80) # 同じジェネレータを複数回使うと2回目は空 print(any(gen)) # True(正しい) print(all(gen)) # True(ジェネレータが空なので常にTrueになってしまう)
次のように記述します。
# リストに変換するか、毎回新しいジェネレータ式を使う filtered = [s for s in scores if s > 80] print(any(filtered)) # True print(all(filtered)) # False(78が含まれていないので)
実践パターン
バリデーション・権限チェック・データ検証など実務でよく使うパターンです。
from collections import namedtuple
# データ定義
Record = namedtuple('Record', ['name', 'group', 'score'])
team_x = [
Record('item_a', 'X', 850),
Record('item_b', 'X', 780),
Record('item_c', 'X', 820),
]
# all(): 全員がスコア800以上か?
if all(r.score >= 800 for r in team_x):
print('チームXは全員が基準値以上')
else:
print('チームXに800未満のメンバーがいる')
# any(): 誰かがスコア850以上か?
if any(r.score >= 850 for r in team_x):
print('チームに高スコアのメンバーがいる')
else:
print('高スコアのメンバーはいない')
# any() でリスト内の特定要素を確認
names = [r.name for r in team_x]
print(any('item_a' in name for name in names)) # True
# all() で全フィールドの検証
def is_valid_record(r):
return bool(r.name) and bool(r.group) and r.score > 0
print(all(is_valid_record(r) for r in team_x)) # True
any_all_practice.py
python3 any_all_practice.py チームXに800未満のメンバーがいる チームに高スコアのメンバーがいる True True
概要
『any()』と『all()』は短絡評価(ショートサーキット)を行います。『any()』は最初にTrueの要素が見つかった時点で評価を終了し、『all()』は最初にFalseの要素が見つかった時点で評価を終了します。そのためジェネレータ式と組み合わせると、条件を満たした時点で後続の要素を評価しないため効率的です。
空のイテラブルに対する挙動として、any([])はFalse、all([])はTrueを返します。all([])がTrueになるのは「すべての要素が条件を満たす」の反例がないためで、数学の「空集合の上の全称量化」と同じ論理です。
Pythonでは0・空文字列・空リスト・None・0.0などが偽(falsy)として扱われます。bool()はこのPythonの真偽値変換規則(『__bool__』メソッド)に基づいて変換します。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。