演算子の概要
プログラミングとは本質的に「データに対する操作」です。レッスン 02 では変数を学びました。次は演算子について学びましょう——Python が提供する計算機能です。算術、比較、論理判断、文字列連結……このレッスンが終われば、Python で多くの実世界の問題を解決できるようになります。
1. 算術演算子
レッスン 02 でいくつかの演算子を使いました。完全なリストは以下の通りです:
| 演算子 | 名前 | 例 | 結果 | 備考 |
|---|---|---|---|---|
+ |
加算 | 5 + 3 |
8 |
文字列連結にも使用 |
- |
減算 | 5 - 3 |
2 |
負号としても使用:-5 |
* |
乗算 | 5 * 3 |
15 |
文字列の繰り返しにも使用 |
/ |
除算 | 5 / 3 |
1.666... |
常に float を返す |
// |
切り捨て除算 | 5 // 3 |
1 |
切り捨て、小数部分を破棄 |
% |
剰余 | 5 % 3 |
2 |
除算の余り |
** |
累乗 | 5 ** 3 |
125 |
5 の 3 乗 |
注目すべき 2 つの演算子
/(除算)の特徴:
print(4 / 2) # 出力 2.0、2 ではない
多くの人がここで戸惑います:4 割る 2 は明らかに 2 なのに、なぜ Python は 2.0 を出力するのでしょうか?Python の / は常に float を返すからです。たとえ割り切れてもです。これにより結果が予測可能になります——/ を見れば結果が float になるとわかります。
//(切り捨て除算)の落とし穴:
print(7 // 3) # 出力 2(7 ÷ 3 = 2.333、切り捨て = 2)
print(-7 // 3) # 出力 -3 ← 予想と違うかもしれません
-7 // 3 は -3 を返し、-2 ではありません。Python の // は切り捨て除算(負の無限大方向への丸め)であり、「ゼロ方向への切り捨て」ではありません。数直線上で、-2.333 の切り捨ては -3 です。ゼロ方向への切り捨てが必要な場合は int(-7 / 3) を使います。これは -2 を返します。
// は「整数除算」ではなく「切り捨て除算」と考えましょう。「整数除算」は切り捨てを意味し、負の数では成り立ちません。
例:インチとセンチメートルの変換(難易度 ⭐)
# インチからセンチメートル:1 インチ = 2.54 cm
# 標準的な定規の長さ
inches = 12
# 乗算を使って変換
cm = inches * 2.54
# 出力(cm は自動的に float になる)
print(f"{inches} inches = {cm} cm")
# 逆:cm → インチ(除算を使用)
cm_value = 30
inches_value = cm_value / 2.54
print(f"{cm_value} cm = {inches_value:.2f} inches")
# 切り捨て除算と剰余を試す — 12 インチは 5 インチのセグメントいくつ?
count = 12 // 5 # 切り捨て:2
remainder = 12 % 5 # 剰余:2 インチ残り
print(f"12 inches can be divided into {count} segments of 5 inches, with {remainder} inches left")
出力:
12 inches = 30.48 cm
30 cm = 11.81 inches
12 inches can be divided into 2 segments of 5 inches, with 2 inches left
2. 比較演算子
比較演算子は値間の関係を評価し、常にブール値(True または False)を返します。条件ロジックの基礎です。
| 演算子 | 名前 | 例 | 結果 |
|---|---|---|---|
== |
等しい | 5 == 3 |
False |
!= |
等しくない | 5 != 3 |
True |
> |
より大きい | 5 > 3 |
True |
< |
より小さい | 5 < 3 |
False |
>= |
以上 | 5 >= 5 |
True |
<= |
以下 | 5 <= 3 |
False |
age = 18
print(age == 18) # True(ちょうど 18)
print(age != 18) # False(「等しくない」ではない)
print(age > 21) # False(米国の飲酒年齢に達していない)
print(age >= 18) # True(ちょうど成人年齢、条件を満たす)
連鎖比較
Python は他の言語では珍しい簡潔な構文をサポートしています:
x = 15
print(10 < x < 20) # True(10 < x and x < 20 と同等)
print(0 < x < 10) # False
これは 10 < x and x < 20 よりも自然に読めます。数学の表記法のようです。
is と is not(同一性比較)
厳密には is は比較演算子ではありませんが、== とよく比較されます:
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True(同じ内容)
print(a is b) # False(しかし同じオブジェクトではない)
print(a is c) # True(c は a の別名)
==は値を比較:「内容は同じか?」isは同一性を比較:「これらは同じオブジェクトを参照しているか?」
日常の開発では、99% のケースで == を使います。is を使うのは None をチェックするときだけというのが慣習です:if result is None:。
例:レースグループ分類(難易度 ⭐)
# 100 メートルスプリントのグループ分けルール
# 12~15 歳 → ジュニアグループ
# 16~20 歳 → ユースグループ
participant_age = 14
# 比較演算子を使ってグループを判定
is_teen_group = 12 <= participant_age <= 15 # 連鎖比較
is_youth_group = participant_age >= 16 and participant_age <= 20
print(f"Participant age: {participant_age}")
print(f"Junior group (12-15): {is_teen_group}")
print(f"Youth group (16-20): {is_youth_group}")
# == と != を使用
age_verified = True
print(f"Age verified: {age_verified == True}")
print(f"Age not verified: {age_verified != True}")
出力:
Participant age: 14
Junior group (12-15): True
Youth group (16-20): False
Age verified: True
Age not verified: False
3. 論理演算子
論理演算子は複数の条件を組み合わせ、結果もブール値になります。if 文やループ条件で頻繁に使用します。
| 演算子 | 名前 | 例 | 結果 | 備考 |
|---|---|---|---|---|
and |
論理 AND | True and False |
False |
両方が true の場合のみ true |
or |
論理 OR | True or False |
True |
少なくとも 1 つが true なら true |
not |
論理 NOT | not True |
False |
否定 |
age = 20
has_id_card = True
# and:両方の条件を満たす必要がある
print(age >= 18 and has_id_card) # True(成人で ID あり)
# or:少なくとも 1 つの条件
print(age >= 18 or has_id_card) # True(実際には両方満たしている)
# not:否定
print(not has_id_card) # False(not True = False)
真理値表
| a | b | a and b | a or b | not a |
|---|---|---|---|---|
| True | True | True | True | False |
| True | False | False | True | False |
| False | True | False | True | True |
| False | False | False | False | True |
ショートサーキット評価
Python の論理演算子には重要な機能があります:ショートサーキット評価です。
# and の場合:左辺が False なら右辺は評価されない
def say_yes():
print("say_yes was called")
return True
print(False and say_yes()) # 出力 False — say_yes は実行されない
print(True and say_yes()) # 出力 "say_yes was called" と True
# or の場合:左辺が True なら右辺は評価されない
print(True or say_yes()) # 出力 True — say_yes は実行されない
これは実際のプログラミングで非常に便利です:
# ユーザーが存在する場合のみユーザー名を取得 — None.get() エラーを回避
user = None
username = user and user.get("name") # user は None(falsy)、ショートサーキット、username = None
print(username) # None
user = {"name": "Xiao Ming"}
username = user and user.get("name") # user は truthy、右辺を評価、username = "Xiao Ming"
print(username) # Xiao Ming
user and user.get("name") パターンは Python でよく使われます——「安全なアクセス」を保証します。左辺が falsy なら直接それを返し、エラーの可能性がある右辺は評価しません。
例:数値が「特別」かどうかを確認(難易度 ⭐⭐)
比較演算子と論理演算子を組み合わせて、数値が特定の「特別な条件」を満たすかどうかを確認します。
# 数値が「特別」かどうかを確認
# 定義:10~99 の範囲で、7 の倍数または 7 を含む
num = 49
# 条件 1:10~99 の範囲(連鎖比較)
in_range = 10 <= num <= 99
# 条件 2:7 の倍数(剰余 + 比較)
multiple_of_7 = num % 7 == 0
# 条件 3:7 を含む(十の位が 7 または一の位が 7)
tens_digit = num // 10 # 十の位を抽出
ones_digit = num % 10 # 一の位を抽出
contains_7 = (tens_digit == 7) or (ones_digit == 7)
# すべての条件を論理演算子で結合
is_special = in_range and (multiple_of_7 or contains_7)
print(f"Number: {num}")
print(f"In range (10-99): {in_range}")
print(f"Multiple of 7: {multiple_of_7}")
print(f"Contains digit 7: {contains_7}")
print(f"Is special: {is_special}") # True — 49 は 7 の倍数
# ショートサーキットの確認 — 最初の条件が偽なら残りは実行されない
num2 = 200 # 範囲外
is_special2 = (10 <= num2 <= 99) and (num2 % 7 == 0)
print(f"\nNumber {num2}: first condition is False, second won't execute — {is_special2}")
出力:
Number: 49
In range (10-99): True
Multiple of 7: True
Contains digit 7: False
Is special: True
Number 200: first condition is False, second won't execute — False
4. 代入演算子
基本的な = に加えて、Python は複合代入演算子を提供します:
x = 10 # 基本代入
x += 3 # x = x + 3 と同等、結果:13
x -= 2 # x = x - 2 と同等、結果:11
x *= 2 # x = x * 2 と同等、結果:22
x /= 4 # x = x / 4 と同等、結果:5.5
x //= 2 # x = x // 2 と同等、結果:2.0
x %= 2 # x = x % 2 と同等、結果:0.0
x = 3 # x = x 3 と同等、結果:0.0
x = 10 は整数ですが、x /= 4 の後は 5.5(float)になることに注意してください。これは / が常に float を返すためです。整数結果が必要な場合は //= を使用してください。
# ループ内での典型的なインクリメント
score = 0
score += 10 # 10 点追加
score += 20 # さらに 20 追加
score += 15 # さらに 15 追加
print(f"Final score: {score}") # 45
# 文字列でも複合代入は動作
message = "Hello"
message += " " # スペースを追加
message += "World"
print(message) # "Hello World"
x += 1 は Python の「1 をインクリメント」の方法です。他の言語では x++ と書きます。Python には ++ 演算子はありません。+= 1 を使用してください。
5. 文字列演算子
文字列には独自の「演算」があります——厳密には数学的ではありませんが、同じ記号を使用します。
| 演算子 | 目的 | 例 | 結果 |
|---|---|---|---|
+ |
連結 | "Hello" + " " + "World" |
"Hello World" |
* |
繰り返し | "Ha" * 3 |
"HaHaHa" |
in |
メンバーシップ | "Py" in "Python" |
True |
not in |
非メンバーシップ | "xyz" not in "Python" |
True |
# 文字列連結
first_name = "Zhang"
last_name = "San"
full_name = first_name + last_name
print(full_name) # 出力 "Zhang San"
# 文字列の繰り返し — 区切り線の描画に便利
line = "=" * 30
print(line) # 30 個の等号を出力
# メンバーシップチェック(in / not in)
text = "Hello, Python!"
print("Python" in text) # True — 「Python」は text の一部
print("Java" in text) # False — text に「Java」は含まれない
print("Java" not in text) # True — 確かに「含まれていない」
+ は 2 つの文字列間でのみ機能し、文字列と数値の間では機能しません。"Age: " + 25 はエラーになります。先に数値を変換してください:"Age: " + str(25)。* は文字列と整数の間でのみ機能します——"AB" * 3 は OK、"AB" * "CD" は不可です。
例:文字列演算で名刺を生成(難易度 ⭐⭐)
# 文字列演算を使って簡単な名刺を生成
name = "Li Ming"
title = "Python Engineer"
company = "Tech Co., Ltd."
# + でカード内容を連結
card_line1 = "Name: " + name
card_line2 = "Title: " + title
card_line3 = "Company: " + company
# * で区切り線を生成
separator = "-" * 25
# 完全なカードに結合
business_card = separator + "\n" + card_line1 + "\n" + card_line2 + "\n" + card_line3 + "\n" + separator
print("Generated Business Card:")
print(business_card)
# in で特定の情報を含むか確認
search_term = "Python"
print(f"\nDoes card contain \"{search_term}\"? {search_term in business_card}")
# not in で特定の情報を除外
print(f"Card doesn't contain \"Manager\": {\"Manager\" not in business_card}")
出力:
Generated Business Card:
-------------------------
Name: Li Ming
Title: Python Engineer
Company: Tech Co., Ltd.
-------------------------
Does card contain "Python"? True
Card doesn't contain "Manager": True
6. 演算子の優先順位
数学に「乗算は加算より先」があるように、Python にも演算子の優先順位があります。
| 優先順位 | カテゴリ | 演算子 | 備考 |
|---|---|---|---|
| 高 | 累乗 | ** |
右結合 |
| ↓ | 単項 | +x、-x、not |
正/負、論理 NOT |
| ↓ | 算術 | *、/、//、% |
乗算、除算、切り捨て、剰余 |
| ↓ | 算術 | +、- |
加算、減算 |
| ↓ | 比較 | ==、!=、>、<、>=、<= |
比較 |
| ↓ | 論理 | not |
論理 NOT |
| ↓ | 論理 | and |
論理 AND |
| ↓ | 論理 | or |
論理 OR |
| 低 | 代入 | =、+= など |
代入 |
# 乗算は加算より先
result = 2 + 3 * 4
print(result) # 14(3*4=12、+2)
# 比較は算術より優先順位が低い
print(2 + 3 * 4 > 10) # True(14 > 10)
# 論理は最も低い — 先に比較を行い、その後論理結合
age = 20
print(age > 18 and age < 60) # True(最初に age>18 と age<60、次に and)
# 累乗は右結合
print(2 3 2) # 512(最初に 3²=9、次に 2⁹=512)
print((2 3) 2) # 64(括弧あり:最初に 2³=8、次に 8²=64)
# 括弧で優先順位を変更 — 数学と同じ
result = (2 + 3) * 4
print(result) # 20(最初に 2+3=5、次に ×4)
例:住宅ローンの計算(難易度 ⭐⭐)
# 月々の住宅ローン支払額を計算(均等払い)
# 計算式:月額 = 借入額 × 月利 × (1 + 月利)^月数 ÷ [(1 + 月利)^月数 - 1]
# 借入額 1,000,000、年利 4.5%、30 年と仮定
loan_amount = 1_000_000 # 借入総額(アンダースコアは可読性のため、Python 3.6+)
annual_rate = 0.045 # 年利
years = 30
months = years * 12 # 支払回数
monthly_rate = annual_rate / 12 # 月利
# 段階的に分解
rate_power = (1 + monthly_rate) ** months # (1 + 月利)^月数
numerator = loan_amount * monthly_rate * rate_power # 分子
denominator = rate_power - 1 # 分母
monthly_payment = numerator / denominator
print(f"Loan amount: {loan_amount:,} yuan")
print(f"Annual rate: {annual_rate * 100}%")
print(f"Loan term: {years} years")
print(f"Monthly payment: {monthly_payment:.2f} yuan")
print(f"Total repayment: {monthly_payment * months:,.2f} yuan")
print(f"Total interest: {monthly_payment * months - loan_amount:,.2f} yuan")
出力:
Loan amount: 1,000,000 yuan
Annual rate: 4.5%
Loan term: 30 years
Monthly payment: 5,066.85 yuan
Total repayment: 1,824,066.95 yuan
Total interest: 824,066.95 yuan
1_000_000 のアンダースコアは人間の可読性のためだけです——Python はそれらを無視します。これは Python 3.6+ の機能で、数値を見やすく区切ります。優先順位を覚えられませんか?括弧を使いましょう——上の式は括弧のおかげで誰にでも明確です。
7. 浮動小数点数の精度問題
すべてのプログラマーが遭遇する問題です:
print(0.1 + 0.2) # 出力 0.30000000000000004
print(0.3) # 出力 0.3
print(0.1 + 0.2 == 0.3) # 出力 False ← 等しくない!
これは Python のバグではなく、浮動小数点数を2 進数で保存することの根本的な限界です。10 進数で 1/3 = 0.33333... を正確に表現できないのと同様に、2 進数では 0.1 を正確に表現できません。
注意すべきケース
- 金融計算(お金に関わるもの)——
floatを直接使わず、decimalモジュールを使用 - 比較—— float の比較に
==を使わず、差分チェックを使用
# float の正しい比較方法
result = 0.1 + 0.2
epsilon = 1e-10 # 非常に小さい数、約 0.0000000001
print(abs(result - 0.3) < epsilon) # 出力 True
- 表示フォーマット—— f-string で小数点以下の桁数を指定
print(f"{0.1 + 0.2:.2f}") # 出力 0.30
# 実際の例:0.1 を 10 回加算
total = 0.0
for i in range(10):
total += 0.1
print(f"Accumulated result: {total}") # 0.9999999999999999
print(f"Exactly 1.0: {total == 1.0}") # False
print(f"Formatted: {total:.2f}") # 1.00 — 表示は問題ない
== を直接使わない」そして「お金の計算には decimal モジュールを使う」。
8. 数値型変換
Python は数値型間の変換関数をいくつか提供しています:
# int → float
print(float(3)) # 出力 3.0
# float → int(ゼロ方向への切り捨て、四捨五入ではない)
print(int(3.14)) # 出力 3
print(int(-2.8)) # 出力 -2(ゼロ方向への切り捨て)
# 文字列 → 数値(文字列が実際に数値を表している場合のみ)
print(int("42")) # 出力 42
print(float("3.14")) # 出力 3.14
# 数値 → 文字列
print(str(3.14)) # 出力 "3.14"
# int() は基数も指定可能
print(int("FF", 16)) # 出力 255(16 進数 FF を 10 進数に)
print(int("1010", 2)) # 出力 10(2 進数 1010 を 10 進数に)
例:実際の型変換(難易度 ⭐)
# 完全なワークフロー:入力 → 変換 → 計算 → 出力
user_input = "25" # 注意:これは文字列であり、数値ではない
# 変換しないとどうなるか?
# print(user_input + 5) ← コメントを外してエラーを確認
# 正しい方法:最初に int() で変換
age = int(user_input)
# これで算術演算が正常に動作
age_next_year = age + 1
print(f"You entered: {user_input} (type: {type(user_input)})")
print(f"After conversion: {age} (type: {type(age)})")
print(f"Next year you'll be {age_next_year} years old")
# 逆:結果を文字列に変換して出力
output_message = "You are " + str(age) + " years old"
print(output_message)
出力:
You entered: 25 (type: <class 'str'>)
After conversion: 25 (type: <class 'int'>)
Next year you'll be 26 years old
You are 25 years old
よくあるユースケース
- E コマースの価格計算:単価 × 数量 + 送料 - クーポン——1 つの式で最終金額を計算。割引やしきい値の条件を論理演算子で組み合わせる。
- 権限チェック:
is_admin or (is_logged_in and has_permission) - ゲームのダメージ計算:攻撃力 × クリティカル倍率 - 防御力。クリティカル判定は比較で:
random.random() < crit_rate - データサンプリング:数値が偶数かどうか(
n % 2 == 0)、年がうるう年かどうか(year % 4 == 0 and year % 100 != 0 or year % 400 == 0) - 時間変換:秒を「時:分:秒」に変換するのに切り捨て除算と剰余を使用。
- 入力検証:ユーザー入力が有効範囲内かどうか——
0 < score <= 100(連鎖比較)、または不正文字のチェック——bad_char in username
❓ よくある質問
== と is の違いは何ですか?それぞれいつ使うべきですか?== は値を比較(「内容は同じか?」)、is は同一性を比較(「同じオブジェクトか?」)します。例:a = [1, 2]; b = [1, 2]; c = a の場合、a == b は True(同じ値)ですが、a is b は False(異なるリストオブジェクト)。a is c は True(c は別名)。日常の開発では 99% == を使います。None のチェックでは慣習的に is を使います:if result is None:。and/or のショートサーキット評価にはどのような落とし穴がありますか?
A:最も一般的な落とし穴:user_input = input() or "default" で、input() が空文字列(falsy)を返した場合、or はショートサーキットしてデフォルト値を採用します。これは便利ですが、初心者には分かりにくいです。もう 1 つの落とし穴:and の右側に関数呼び出しを置いた場合、左辺が falsy だと関数は実行されず、重要な処理がスキップされる可能性があります。良い習慣:右辺の式に副作用がある場合は、ショートサーキットに頼らず、別々の文に書きましょう。
/ と // はいつ使い分ければよいですか?/ を使います。整数結果のみが必要な場合(例:7 つのリンゴを 3 人で分ける——1 人 2 個、1 個余り)は、// と % を使います。初心者で迷ったら、デフォルトで / を使いましょう——少なくとも精度を失うことはありません。整数結果が具体的に必要な場合に // に切り替えてください。** が右結合とはどういう意味ですか?なぜそのように設計されているのですか?2 3 2 が 2 (3 2) として解析されること、つまり最初に 3² = 9 を計算し、次に 2⁹ = 512 を計算することを意味します。左から右だと (2³)² = 8² = 64 となり、まったく異なる結果になります。これは数学の慣習に従っています:a^b^c は右上から解釈されます。順序を強制するには括弧を使います:(2 3) 2 は 64。📖 まとめ
- 7 つの算術演算子:
+-*///%**。/は常に float を返し、//は負の無限大方向に切り捨て - 6 つの比較演算子:
==!=><>=<=。Python は10 < x < 20のような連鎖比較をサポート - 3 つの論理演算子:
and(両方 true で true)、or(少なくとも 1 つ true で true)、not(否定)。すべてショートサーキット評価を使用 - 文字列演算子:
+連結、*繰り返し、in/not inメンバーシップ - 優先順位:
**> 単項 > 算術 > 比較 >not>and>or> 代入。迷ったら括弧を使う - float は
==で正確に比較できない。差分チェックabs(a - b) < epsilonを使用
📝 練習問題
-
基本(難易度 ⭐):
a=10、b=3、c=20を定義し、a + b * c、(a + b) * c、a ** b、a // b、c % a、a > b and c > 15を計算して出力してください。まず結果を予想し、その後確認しましょう。 -
中級(難易度 ⭐⭐):
year = 2026を指定して、うるう年かどうかを判定してください。うるう年のルール:4 で割り切れるが 100 では割り切れない、または 400 で割り切れる。ヒント:year % 4 == 0で 4 で割り切れるかどうかを確認。 -
挑戦(難易度 ⭐⭐⭐):簡単な温度警報システムを書いてください。
current_temp = 38、high_alarm = 37、low_alarm = 5が与えられています。現在の温度が上限を超えるか下限を下回った場合に警報を発します。温度が境界付近(±2 度以内)の場合は「警報」ではなく「注意報」を出します。算術演算子、比較演算子、論理演算子のみを使用してください。ヒント:abs(current_temp - high_alarm) <= 2で上限付近かどうかを確認。



