Operators Overview
Programming is essentially "performing operations on data." In Lesson 02 we learned about variables; now let's learn about operators — what computational capabilities Python offers. Arithmetic, comparison, logical decisions, string concatenation... After this lesson, you'll solve many real-world problems with Python.
1. Arithmetic Operators
We've used a few operators in Lesson 02. Here's the complete list:
| Operator | Name | Example | Result | Notes |
|---|---|---|---|---|
+ |
Addition | 5 + 3 |
8 |
Also works for string concatenation |
- |
Subtraction | 5 - 3 |
2 |
Also used as negation: -5 |
* |
Multiplication | 5 * 3 |
15 |
Also works for string repetition |
/ |
Division | 5 / 3 |
1.666... |
Always returns a float |
// |
Floor division | 5 // 3 |
1 |
Rounds down, discards fractional part |
% |
Modulo | 5 % 3 |
2 |
Remainder of division |
** |
Exponentiation | 5 ** 3 |
125 |
5 to the power of 3 |
Two Operators Worth Noting
/ (Division) quirk:
print(4 / 2) # Output 2.0, not 2
Many people pause at this: 4 divided by 2 is clearly 2, so why does Python output 2.0? Because Python's / always returns a float, even when divisible evenly. This keeps results predictable — you see / and know the result will be float.
// (Floor division) trap:
print(7 // 3) # Output 2 (7 ÷ 3 = 2.333, floored = 2)
print(-7 // 3) # Output -3 ← may not be what you expect
-7 // 3 gives -3, not -2. Python's // is floor division (rounds toward negative infinity), not "truncation toward zero." On the number line, -2.333 floored is -3. If you want truncation toward zero, use int(-7 / 3), which gives -2.
// as "floor division" rather than "integer division" — "integer division" implies truncation, which doesn't hold for negative numbers.
Example: Inches and Centimeters Conversion (Difficulty ⭐)
# Inches to centimeters: 1 inch = 2.54 cm
# A standard ruler length
inches = 12
# Convert using multiplication
cm = inches * 2.54
# Output (notice cm is automatically a float)
print(f"{inches} inches = {cm} cm")
# Reverse: cm → inches (using division)
cm_value = 30
inches_value = cm_value / 2.54
print(f"{cm_value} cm = {inches_value:.2f} inches")
# Try floor division and modulo — how many 5-inch segments in 12 inches?
count = 12 // 5 # Floor: 2
remainder = 12 % 5 # Modulo: 2 inches remaining
print(f"12 inches can be divided into {count} segments of 5 inches, with {remainder} inches left")
Output:
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. Comparison Operators
Comparison operators evaluate relationships between values and always return a boolean (True or False). They're the foundation of conditional logic.
| Operator | Name | Example | Result |
|---|---|---|---|
== |
Equal to | 5 == 3 |
False |
!= |
Not equal to | 5 != 3 |
True |
> |
Greater than | 5 > 3 |
True |
< |
Less than | 5 < 3 |
False |
>= |
Greater than or equal | 5 >= 5 |
True |
<= |
Less than or equal | 5 <= 3 |
False |
age = 18
print(age == 18) # True (exactly 18)
print(age != 18) # False (not "not equal")
print(age > 21) # False (not old enough for US drinking age)
print(age >= 18) # True (exactly adult age, meets the condition)
Chained Comparisons
Python supports a concise syntax rare in other languages:
x = 15
print(10 < x < 20) # True (equivalent to 10 < x and x < 20)
print(0 < x < 10) # False
This reads more naturally than 10 < x and x < 20, like mathematical notation.
is and is not (Identity Comparison)
Strictly speaking, is isn't a comparison operator, but it's often compared with ==:
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True (same contents)
print(a is b) # False (but not the same object)
print(a is c) # True (c is just an alias for a)
==compares value: "Are the contents the same?"iscompares identity: "Do these reference the same object?"
In daily development, 99% of the time you use ==. The convention is to use is only when checking for None: if result is None:.
Example: Race Group Classification (Difficulty ⭐)
# 100-meter sprint grouping rules
# Age 12–15 → Junior group
# Age 16–20 → Youth group
participant_age = 14
# Use comparison operators to determine the group
is_teen_group = 12 <= participant_age <= 15 # Chained comparison
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}")
# Using == and !=
age_verified = True
print(f"Age verified: {age_verified == True}")
print(f"Age not verified: {age_verified != True}")
Output:
Participant age: 14
Junior group (12-15): True
Youth group (16-20): False
Age verified: True
Age not verified: False
3. Logical Operators
Logical operators combine multiple conditions, and the result is also a boolean. They're used everywhere in if statements and loop conditions.
| Operator | Name | Example | Result | Notes |
|---|---|---|---|---|
and |
Logical AND | True and False |
False |
True only if both are true |
or |
Logical OR | True or False |
True |
True if at least one is true |
not |
Logical NOT | not True |
False |
Negation |
age = 20
has_id_card = True
# and: both conditions must be met
print(age >= 18 and has_id_card) # True (adult and has ID)
# or: at least one condition
print(age >= 18 or has_id_card) # True (actually both are met)
# not: negation
print(not has_id_card) # False (not True = False)
Truth Table
| 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 |
Short-Circuit Evaluation
Python's logical operators have an important feature: short-circuit evaluation.
# For and: if the left side is False, the right side is never evaluated
def say_yes():
print("say_yes was called")
return True
print(False and say_yes()) # Output False — say_yes never ran
print(True and say_yes()) # Output "say_yes was called" and True
# For or: if the left side is True, the right side is not evaluated
print(True or say_yes()) # Output True — say_yes never ran
This is very useful in practice:
# Only get username if user exists — avoids None.get() error
user = None
username = user and user.get("name") # user is None (falsy), short-circuits, username = None
print(username) # None
user = {"name": "Xiao Ming"}
username = user and user.get("name") # user is truthy, evaluates right side, username = "Xiao Ming"
print(username) # Xiao Ming
user and user.get("name") pattern is common in Python — it ensures "safe access": if the left side is falsy, return it directly without evaluating the potentially error-prone right side.
Example: Check if a Number is "Special" (Difficulty ⭐⭐)
Combine comparison and logical operators to check if a number meets certain "special conditions."
# Check if a number is "special"
# Definition: between 10-99, and is a multiple of 7 or contains the digit 7
num = 49
# Condition 1: between 10-99 (chained comparison)
in_range = 10 <= num <= 99
# Condition 2: multiple of 7 (modulo + comparison)
multiple_of_7 = num % 7 == 0
# Condition 3: contains digit 7 (tens digit = 7 or ones digit = 7)
tens_digit = num // 10 # Extract tens digit
ones_digit = num % 10 # Extract ones digit
contains_7 = (tens_digit == 7) or (ones_digit == 7)
# Combine all conditions with logical operators
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 is a multiple of 7
# Verify short-circuit — if first condition fails, the rest won't run
num2 = 200 # Out of range
is_special2 = (10 <= num2 <= 99) and (num2 % 7 == 0)
print(f"\nNumber {num2}: first condition is False, second won't execute — {is_special2}")
Output:
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. Assignment Operators
Beyond basic =, Python provides compound assignment operators:
x = 10 # Basic assignment
x += 3 # Equivalent to x = x + 3, result: 13
x -= 2 # Equivalent to x = x - 2, result: 11
x *= 2 # Equivalent to x = x * 2, result: 22
x /= 4 # Equivalent to x = x / 4, result: 5.5
x //= 2 # Equivalent to x = x // 2, result: 2.0
x %= 2 # Equivalent to x = x % 2, result: 0.0
x = 3 # Equivalent to x = x 3, result: 0.0
Note that x = 10 is an integer, but after x /= 4 it becomes 5.5 (float), because / always returns a float. Use //= if you need an integer result.
# Typical increment in a loop
score = 0
score += 10 # Add 10 points
score += 20 # Add another 20
score += 15 # Add another 15
print(f"Final score: {score}") # 45
# Strings also work with compound assignment
message = "Hello"
message += " " # Add a space
message += "World"
print(message) # "Hello World"
x += 1 is Python's way of "increment by 1." Other languages write x++. Python has no ++ operator; use += 1.
5. String Operators
Strings have their own "operations" — not exactly mathematical, but using the same symbols.
| Operator | Purpose | Example | Result |
|---|---|---|---|
+ |
Concatenation | "Hello" + " " + "World" |
"Hello World" |
* |
Repetition | "Ha" * 3 |
"HaHaHa" |
in |
Membership | "Py" in "Python" |
True |
not in |
Non-membership | "xyz" not in "Python" |
True |
# String concatenation
first_name = "Zhang"
last_name = "San"
full_name = first_name + last_name
print(full_name) # Output "Zhang San"
# String repetition — great for drawing separator lines
line = "=" * 30
print(line) # Output 30 equals signs
# Membership check (in / not in)
text = "Hello, Python!"
print("Python" in text) # True — "Python" is part of text
print("Java" in text) # False — text doesn't contain "Java"
print("Java" not in text) # True — indeed "not in there"
+ only works between two strings, not between a string and a number. "Age: " + 25 will error. Convert the number first: "Age: " + str(25). * only works between a string and an integer — "AB" * 3 is fine, "AB" * "CD" is not.
Example: Generate a Business Card with String Operations (Difficulty ⭐⭐)
# Generate a simple business card using string operations
name = "Li Ming"
title = "Python Engineer"
company = "Tech Co., Ltd."
# Concatenate card content with +
card_line1 = "Name: " + name
card_line2 = "Title: " + title
card_line3 = "Company: " + company
# Generate separator with *
separator = "-" * 25
# Combine into full card
business_card = separator + "\n" + card_line1 + "\n" + card_line2 + "\n" + card_line3 + "\n" + separator
print("Generated Business Card:")
print(business_card)
# Check if it contains specific info with in
search_term = "Python"
print(f"\nDoes card contain \"{search_term}\"? {search_term in business_card}")
# Exclude certain info with not in
print(f"Card doesn't contain \"Manager\": {\"Manager\" not in business_card}")
Output:
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. Operator Precedence
Just like math has "multiplication before addition," Python has operator precedence.
| Priority | Category | Operators | Notes |
|---|---|---|---|
| High | Exponentiation | ** |
Right-associative |
| ↓ | Unary | +x, -x, not |
Positive/negative, logical NOT |
| ↓ | Arithmetic | *, /, //, % |
Multiply, divide, floor, modulo |
| ↓ | Arithmetic | +, - |
Add, subtract |
| ↓ | Comparison | ==, !=, >, <, >=, <= |
Comparisons |
| ↓ | Logical | not |
Logical NOT |
| ↓ | Logical | and |
Logical AND |
| ↓ | Logical | or |
Logical OR |
| Low | Assignment | =, +=, etc. |
Assignment |
# Multiplication before addition
result = 2 + 3 * 4
print(result) # 14 (3*4=12, then +2)
# Comparison has lower priority than arithmetic
print(2 + 3 * 4 > 10) # True (14 > 10)
# Logical has lowest priority — do comparisons first, then combine logically
age = 20
print(age > 18 and age < 60) # True (first age>18 and age<60, then and)
# Exponentiation is right-associative
print(2 3 2) # 512 (first 3²=9, then 2⁹=512)
print((2 3) 2) # 64 (with parentheses, first 2³=8, then 8²=64)
# Parentheses change precedence — just like math
result = (2 + 3) * 4
print(result) # 20 (first 2+3=5, then ×4)
Example: Mortgage Calculator (Difficulty ⭐⭐)
# Calculate monthly mortgage payment (equal payment)
# Formula: monthly = loan × monthly_rate × (1 + monthly_rate)^months ÷ [(1 + monthly_rate)^months - 1]
# Assume 1,000,000 loan, 4.5% annual rate, 30 years
loan_amount = 1_000_000 # Total loan (underscores are for readability, Python 3.6+)
annual_rate = 0.045 # Annual interest rate
years = 30
months = years * 12 # Number of payments
monthly_rate = annual_rate / 12 # Monthly interest rate
# Break it down step by step
rate_power = (1 + monthly_rate) ** months # (1 + monthly rate)^months
numerator = loan_amount * monthly_rate * rate_power # Numerator
denominator = rate_power - 1 # Denominator
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")
Output:
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 are just for human readability — Python ignores them. This is a Python 3.6+ feature for visual number separation. Can't remember precedence? Use parentheses — the formula above is clear to anyone with parentheses.
7. Floating-Point Precision Issues
Every programmer encounters this:
print(0.1 + 0.2) # Output 0.30000000000000004
print(0.3) # Output 0.3
print(0.1 + 0.2 == 0.3) # Output False ← they're not equal!
This isn't a Python bug — it's a fundamental limitation of storing floats in binary. Just as decimal can't precisely represent 1/3 = 0.33333..., binary can't precisely represent 0.1.
When to Watch Out
- Financial calculations (involving money) — never use
floatdirectly; use thedecimalmodule - Comparisons — don't use
==to compare floats; use difference checking
# Correct way to compare floats
result = 0.1 + 0.2
epsilon = 1e-10 # A very small number, about 0.0000000001
print(abs(result - 0.3) < epsilon) # Output True
- Display formatting — use f-string to specify decimal places
print(f"{0.1 + 0.2:.2f}") # Output 0.30
# Real example: adding 0.1 ten times
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 — display is fine
== to compare floats directly" and "use the decimal module for money."
8. Numeric Type Conversion
Python provides several functions for converting between numeric types:
# int → float
print(float(3)) # Output 3.0
# float → int (truncates toward zero, not rounding)
print(int(3.14)) # Output 3
print(int(-2.8)) # Output -2 (truncation toward zero)
# string → number (only if the string actually represents a number)
print(int("42")) # Output 42
print(float("3.14")) # Output 3.14
# number → string
print(str(3.14)) # Output "3.14"
# int() can also specify base
print(int("FF", 16)) # Output 255 (hexadecimal FF to decimal)
print(int("1010", 2)) # Output 10 (binary 1010 to decimal)
Example: Type Conversion in Practice (Difficulty ⭐)
# Full workflow: input → convert → calculate → output
user_input = "25" # Note: this is a string, not a number
# What happens without conversion?
# print(user_input + 5) ← uncomment to see the error
# Correct approach: convert with int() first
age = int(user_input)
# Now arithmetic works normally
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")
# Reverse: convert result back to string for output
output_message = "You are " + str(age) + " years old"
print(output_message)
Output:
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
Common Use Cases
- E-commerce price calculation: Unit price × quantity + shipping - coupon — one expression to compute the final amount. Combine discount and threshold conditions with logical operators.
- Permission checks:
is_admin or (is_logged_in and has_permission). - Game damage calculation: Attack × crit multiplier - defense; crit check with comparison:
random.random() < crit_rate. - Data sampling: Check if a number is even (
n % 2 == 0) or if a year is a leap year (year % 4 == 0 and year % 100 != 0 or year % 400 == 0). - Time conversion: Convert seconds to "hours:minutes:seconds" using floor division and modulo.
- Input validation: Check if user input is in a valid range —
0 < score <= 100(chained comparison), or check for illegal characters —bad_char in username.
❓ FAQ
== and is? When should I use each?== compares values ("are the contents the same?"), is compares identity ("are they the same object?"). Example: a = [1, 2]; b = [1, 2]; c = a — a == b is True (same values), but a is b is False (different list objects); a is c is True (c is just an alias). In daily development, 99% of the time use ==. For checking None, convention is is: if result is None:.
⚠️ Q: What pitfalls does short-circuit evaluation of and/or have in practice? A: The most common pitfall: user_input = input() or "default" — if input() returns an empty string (falsy), or short-circuits and takes the default. This is common but can be confusing for beginners. Another trap: putting a function call on the right side of and — if the left side is falsy, the function won't execute, potentially skipping important operations. Good practice: if the right expression has side effects, don't rely on short-circuit behavior; write separate statements.
Q: When should I use / vs //? A: If you need a precise decimal result (e.g., 7 ÷ 3 = 2.333...), use /. If you only need an integer result (e.g., dividing 7 apples among 3 people — 2 each, 1 left over), use // with %. If you're a beginner and unsure, use / by default — at least you won't lose precision. Switch to // when you specifically need integer results.
Q: What does right-associative mean? Why is it designed this way? A: Right-associative means 2 3 2 is parsed as 2 (3 2), i.e., first calculate 3² = 9, then 2⁹ = 512. Left-to-right would give (2³)² = 8² = 64, a completely different result. This matches mathematical convention: a^b^c is interpreted starting from the upper right. Use parentheses to force order: (2 3) ** 2 gives 64.📖 Summary
- 7 arithmetic operators:
+-*///%**;/always returns float,//floors toward negative infinity - 6 comparison operators:
==!=><>=<=; Python supports chained comparison like10 < x < 20 - 3 logical operators:
and(true if both true),or(true if at least one is true),not(negation); all use short-circuit evaluation - String operators:
+concatenation,*repetition,in/not inmembership - Precedence:
**> unary > arithmetic > comparison >not>and>or> assignment. When in doubt, use parentheses - Floats can't be precisely compared with
==; use difference checkingabs(a - b) < epsilon
📝 Exercises
-
Basic (Difficulty ⭐): Define
a=10,b=3,c=20. Calculate and output:a + b * c,(a + b) * c,a ** b,a // b,c % a,a > b and c > 15. Guess the results first, then verify. -
Intermediate (Difficulty ⭐⭐): Given
year = 2026, determine if it's a leap year. Leap year rule: divisible by 4 but not by 100, or divisible by 400. Hint:year % 4 == 0checks divisibility by 4. -
Challenge (Difficulty ⭐⭐⭐): Write a simple temperature alarm system. Given
current_temp = 38,high_alarm = 37,low_alarm = 5. Trigger an alarm if the current temperature exceeds the high limit or drops below the low limit. If the temperature is near the edge (within ±2 degrees), issue a "caution" instead of "alarm." Use only arithmetic, comparison, and logical operators. Hint:abs(current_temp - high_alarm) <= 2checks if near the high edge.



