Python複数の比較演算子を連結する方法 – チェーン比較の使い方とベストプラクティス

 

比較演算子の連結とは?

Python では複数の比較演算子を連結(チェーン)して、複雑な条件を簡潔に記述できます。この機能により、数学的な表記に近い自然な書き方で範囲チェックや複数条件の判定が可能になります。

基本的な連結比較

1. 範囲チェックの基本

# 従来の書き方
x = 15
if x >= 10 and x <= 20:
    print("xは10以上20以下")

# 連結比較(推奨)
if 10 <= x <= 20:
    print("xは10以上20以下")

# より複雑な範囲
age = 25
if 18 <= age < 65:
    print("成人かつ現役世代")

2. 等価性の連結

# 複数の値が同じかチェック
a, b, c = 5, 5, 5
if a == b == c:
    print("すべて同じ値")

# 文字列での例
name1, name2, name3 = "太郎", "太郎", "太郎"
if name1 == name2 == name3:
    print("すべて同じ名前")

3. 大小関係の連結

# 昇順チェック
x, y, z = 1, 5, 10
if x < y < z:
    print("昇順に並んでいる")

# 降順チェック
a, b, c = 100, 50, 10
if a > b > c:
    print("降順に並んでいる")

# 混合比較
score = 85
if 0 <= score < 60:
    print("不合格")
elif 60 <= score < 80:
    print("合格")
elif 80 <= score <= 100:
    print("優秀")

実践的な使用例

1. 数値範囲の検証

def validate_temperature(temp):
    if -273.15 <= temp <= 1000:
        return "有効な温度"
    return "無効な温度"

def check_percentage(value):
    return 0 <= value <= 100

# 使用例
print(validate_temperature(25))    # 有効な温度
print(check_percentage(85))        # True
print(check_percentage(150))       # False

2. 日付・時間の範囲チェック

def is_business_hour(hour):
    return 9 <= hour <= 17

def is_valid_month(month):
    return 1 <= month <= 12

def is_valid_day(day, month):
    if month in [1, 3, 5, 7, 8, 10, 12]:
        return 1 <= day <= 31
    elif month in [4, 6, 9, 11]:
        return 1 <= day <= 30
    else:  # 2月
        return 1 <= day <= 29

# 使用例
print(is_business_hour(14))        # True
print(is_valid_month(13))          # False
print(is_valid_day(31, 4))         # False

3. 成績評価システム

def get_grade(score):
    if 90 <= score <= 100:
        return "A"
    elif 80 <= score < 90:
        return "B"
    elif 70 <= score < 80:
        return "C"
    elif 60 <= score < 70:
        return "D"
    elif 0 <= score < 60:
        return "F"
    else:
        return "無効なスコア"

# バッチ処理
scores = [95, 85, 75, 65, 55, 105]
for score in scores:
    grade = get_grade(score)
    print(f"スコア{score}: {grade}")

文字列での連結比較

1. アルファベット順の比較

# 文字列の辞書順比較
word = "hello"
if "a" <= word <= "m":
    print("前半のアルファベット")
elif "n" <= word <= "z":
    print("後半のアルファベット")

# 文字の範囲チェック
def is_lowercase_letter(char):
    return "a" <= char <= "z"

def is_digit_char(char):
    return "0" <= char <= "9"

# 使用例
print(is_lowercase_letter("h"))    # True
print(is_digit_char("5"))          # True

2. 文字列長の比較

def validate_password(password):
    length = len(password)
    if 8 <= length <= 20:
        return "有効な長さ"
    return "無効な長さ"

def check_username(username):
    length = len(username)
    return 3 <= length <= 15

# 使用例
print(validate_password("password123"))  # 有効な長さ
print(check_username("user"))           # True

複数データ型での連結

1. 混合データ型の比較

# 数値と文字列の混合(注意が必要)
def compare_mixed():
    try:
        # これはエラーになる
        # result = 1 < "2" < 3
        pass
    except TypeError as e:
        print(f"型エラー: {e}")

# 正しい方法:型を統一
def safe_compare(a, b, c):
    try:
        return a < b < c
    except TypeError:
        return False

print(safe_compare(1, 2, 3))        # True
print(safe_compare(1, "2", 3))      # False

2. リストでの連結比較

# リストの辞書順比較
list1 = [1, 2, 3]
list2 = [1, 2, 4]
list3 = [1, 3, 0]

if list1 < list2 < list3:
    print("辞書順で並んでいる")
else:
    print("順序が異なる")

# リスト長の比較
def check_list_sizes(lst1, lst2, lst3):
    return len(lst1) <= len(lst2) <= len(lst3)

lists = [[1], [1, 2], [1, 2, 3]]
print(check_list_sizes(*lists))     # True

論理演算との組み合わせ

1. and演算子との併用

def validate_user_data(age, income, credit_score):
    # 複数の範囲チェックを組み合わせ
    age_ok = 18 <= age <= 65
    income_ok = 30000 <= income <= 1000000
    credit_ok = 600 <= credit_score <= 850
    
    return age_ok and income_ok and credit_ok

# 使用例
print(validate_user_data(30, 50000, 750))  # True
print(validate_user_data(17, 50000, 750))  # False

2. or演算子との併用

def is_extreme_temperature(temp):
    # 極端に高いか低い温度
    return temp <= -10 or temp >= 40

def is_weekend_or_holiday(day_type):
    # 文字列での範囲外チェック
    return day_type == "土曜日" or day_type == "日曜日" or day_type == "祝日"

# より効率的な書き方
def is_weekend_or_holiday_v2(day_type):
    return day_type in ["土曜日", "日曜日", "祝日"]

print(is_extreme_temperature(-15))  # True
print(is_extreme_temperature(25))   # False

関数型プログラミングでの活用

1. リスト内包表記での使用

# 範囲内の数値をフィルタリング
numbers = [1, 5, 10, 15, 20, 25, 30]
valid_range = [x for x in numbers if 10 <= x <= 20]
print(valid_range)  # [10, 15, 20]

# 複数条件でのフィルタリング
data = [
    {"name": "太郎", "age": 25, "score": 85},
    {"name": "花子", "age": 30, "score": 92},
    {"name": "次郎", "age": 35, "score": 78}
]

high_performers = [
    person for person in data 
    if 20 <= person["age"] <= 40 and 80 <= person["score"] <= 100
]
print(len(high_performers))  # 2

2. filter関数での使用

# 有効な年齢をフィルタリング
ages = [15, 20, 25, 30, 70, 80]
working_age = list(filter(lambda age: 18 <= age <= 65, ages))
print(working_age)  # [20, 25, 30]

# 複数条件での使用
def is_valid_score(score_data):
    score, max_score = score_data
    return 0 <= score <= max_score

score_pairs = [(85, 100), (120, 100), (75, 80)]
valid_scores = list(filter(is_valid_score, score_pairs))
print(valid_scores)  # [(85, 100), (75, 80)]

パフォーマンスの考慮事項

1. 連結比較 vs 論理演算子

import timeit

x = 15

# 連結比較(推奨)
def chained_comparison():
    return 10 <= x <= 20

# 論理演算子
def logical_comparison():
    return x >= 10 and x <= 20

# パフォーマンス比較
time1 = timeit.timeit(chained_comparison, number=1000000)
time2 = timeit.timeit(logical_comparison, number=1000000)

print(f"連結比較: {time1:.6f}秒")
print(f"論理演算: {time2:.6f}秒")

2. 短絡評価の活用

def expensive_function():
    print("高コストな処理実行")
    return 50

# 効率的な順序
def efficient_check(x):
    # 簡単なチェックを最初に
    if 0 <= x <= 100:
        expensive_result = expensive_function()
        return 40 <= expensive_result <= 60
    return False

# 使用例
print(efficient_check(50))   # 高コストな処理実行、True
print(efficient_check(-10))  # False(高コストな処理は実行されない)

エラーハンドリング

1. 型エラーの対処

def safe_range_check(value, min_val, max_val):
    try:
        return min_val <= value <= max_val
    except TypeError:
        return False

# 使用例
print(safe_range_check(5, 1, 10))      # True
print(safe_range_check("5", 1, 10))    # False
print(safe_range_check(None, 1, 10))   # False

2. None値の処理

def validate_range_with_none(value, min_val=None, max_val=None):
    if value is None:
        return False
    
    if min_val is not None and max_val is not None:
        return min_val <= value <= max_val
    elif min_val is not None:
        return value >= min_val
    elif max_val is not None:
        return value <= max_val
    else:
        return True

# 使用例
print(validate_range_with_none(5, 1, 10))    # True
print(validate_range_with_none(5, min_val=1)) # True
print(validate_range_with_none(None, 1, 10))  # False

実際のアプリケーション例

1. Webフォーム検証

class FormValidator:
    def validate_age(self, age):
        return isinstance(age, int) and 0 <= age <= 120
    
    def validate_email_length(self, email):
        return isinstance(email, str) and 5 <= len(email) <= 100
    
    def validate_password_strength(self, password):
        if not isinstance(password, str):
            return False
        
        length_ok = 8 <= len(password) <= 50
        has_upper = any('A' <= c <= 'Z' for c in password)
        has_lower = any('a' <= c <= 'z' for c in password)
        has_digit = any('0' <= c <= '9' for c in password)
        
        return length_ok and has_upper and has_lower and has_digit

# 使用例
validator = FormValidator()
print(validator.validate_age(25))                    # True
print(validator.validate_password_strength("Pass123")) # True

2. データ分析での範囲フィルタ

def analyze_sales_data(sales_data):
    # 正常範囲の売上データを抽出
    normal_sales = [
        sale for sale in sales_data 
        if 0 <= sale["amount"] <= 1000000 and 
           1 <= sale["month"] <= 12
    ]
    
    # 四分位範囲での異常値検出
    amounts = [sale["amount"] for sale in normal_sales]
    if amounts:
        q1 = sorted(amounts)[len(amounts)//4]
        q3 = sorted(amounts)[3*len(amounts)//4]
        iqr = q3 - q1
        
        outliers = [
            sale for sale in normal_sales
            if not (q1 - 1.5*iqr <= sale["amount"] <= q3 + 1.5*iqr)
        ]
        
        return normal_sales, outliers
    
    return [], []

# 使用例
sales = [
    {"amount": 50000, "month": 3},
    {"amount": 75000, "month": 4},
    {"amount": 2000000, "month": 5},  # 異常値
    {"amount": 60000, "month": 6}
]

normal, outliers = analyze_sales_data(sales)
print(f"正常データ数: {len(normal)}")
print(f"異常値数: {len(outliers)}")

よくある間違いと対処法

1. 浮動小数点数での比較

# 浮動小数点の精度問題
def problematic_range_check():
    x = 0.1 + 0.2  # 0.30000000000000004
    return 0.0 <= x <= 0.5  # True だが予期しない値

# 正しい方法
import math

def safe_float_range_check(value, min_val, max_val, tolerance=1e-9):
    return min_val - tolerance <= value <= max_val + tolerance

# または Decimal を使用
from decimal import Decimal

def decimal_range_check():
    x = Decimal('0.1') + Decimal('0.2')  # 正確に 0.3
    return Decimal('0.0') <= x <= Decimal('0.5')

print(decimal_range_check())  # True

2. 文字列の数値比較

# 間違った文字列数値比較
strings = ["1", "10", "2", "20"]
# "10" < "2" は True になる(辞書順)

# 正しい方法
def numeric_string_range(s, min_val, max_val):
    try:
        num = float(s)
        return min_val <= num <= max_val
    except ValueError:
        return False

print(numeric_string_range("15", 10, 20))  # True
print(numeric_string_range("abc", 10, 20)) # False

まとめ

Python の連結比較演算子を効果的に使うポイント:

推奨される使用場面

  • 範囲チェック: 10 <= x <= 20 の形式
  • 順序確認: a < b < c で昇順チェック
  • 等価性確認: a == b == c で複数値の一致
  • 数学的な表現: より自然で読みやすいコード

注意すべき点

  • 型の統一: 異なる型での比較は避ける
  • 浮動小数点: 精度問題に注意
  • パフォーマンス: 複雑な式では短絡評価を活用
  • 可読性: 過度に複雑な連結は避ける

連結比較演算子を適切に使用することで、より Pythonic で読みやすいコードが書けるようになります。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座