Quiz 2

Operators & Expressions

2610 words
13 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Operators & Expressions > **Why read this?** An expression is how you compute new values from existing ones. Every calculator, every formula, every decision your program makes involves operators.

Operators & Expressions

Why read this? An expression is how you compute new values from existing ones. Every calculator, every formula, every decision your program makes involves operators. Mastering operators is like learning the verbs of the Python language — they're how you make things happen.

🎯 Learning Objectives

By the end of this topic, you will be able to:
  1. Use all arithmetic, comparison, logical, and membership operators
  2. Predict expression evaluation using precedence and associativity rules
  3. Distinguish between == (value equality) and is (identity)
  4. Write boolean expressions with and, or, not
  5. Use in to check membership in collections

📋 Prerequisites


📖 Core Content

4.1 What Is an Expression?

Intuition: An expression is any piece of code that produces a value. 2 + 3 is an expression (it produces 5). "Hello" + " " + "World" is an expression (it produces "Hello World"). Even a single variable like name is an expression (it produces the value stored in it).
pseudo
Expression → Python evaluates it → Value
   2 + 3              →              5
  "A" + "B"           →             "AB"
   len("hi")          →              2

4.2 Arithmetic Operators — Review and Extend

OperatorNameExampleResultNotes
+Addition5 + 38Also works on strings (concatenation)
-Subtraction5 - 32Also negation: -x
*Multiplication5 * 315Also string repetition: "Hi" * 3"HiHiHi"
/Division5 / 31.666...Always returns float
//Floor division5 // 31Rounds DOWN, not toward zero
%Modulus5 % 32Remainder after division
**Exponentiation5 ** 31255 to the power 3
Important nuance about // with negative numbers:
python
# runnable
print(7 // 3)    # 2    (2*3=6, remainder 1)
print(-7 // 3)   # -3   (-3*3=-9, remainder 2) ← NOT -2!
print(7 // -3)   # -3
print(-7 // -3)  # 2
Output:
pseudo
2
-3
-3
2
Why? Floor division always rounds DOWN (toward negative infinity), not toward zero. -7/3 = -2.333..., and the floor (round down) of -2.333 is -3, not -2.

4.3 Comparison Operators — Making Decisions

Comparison operators compare two values and return a boolean (True or False).
python
# runnable
a = 10
b = 5
print(a == b)    # False  (equal to)
print(a != b)    # True   (not equal to)
print(a > b)     # True   (greater than)
print(a < b)     # False  (less than)
print(a >= b)    # True   (greater than or equal)
print(a <= b)    # False  (less than or equal)
Output:
pseudo
False
True
True
False
True
False
⚠️ Critical: = is ASSIGNMENT (store a value). == is COMPARISON (check if equal). This is the #1 mistake beginners make!

4.4 Chained Comparisons

Python allows you to chain comparisons naturally:
python
# runnable
x = 15
print(10 < x < 20)    # True (10 < 15 and 15 < 20)
print(10 < x < 12)    # False (15 is not < 12)
# Equivalent to:
print(10 < x and x < 20)  # True
Output:
pseudo
True
False
True
This works for any comparison: a <= b < c > d etc. Python evaluates each pair separately and combines them with and.

4.5 Logical Operators — and, or, not

Logical operators combine multiple boolean values.
python
# runnable
age = 22
has_license = True
# and: both must be True
print(age >= 18 and has_license)   # True (both conditions are True)
# or: at least one must be True
has_car = False
print(has_license or has_car)      # True (has_license is True)
# not: reverses the boolean
is_weekend = False
print(not is_weekend)              # True
Output:
pseudo
True
True
True
(Diagram)

4.6 Short-Circuit Evaluation

Python is lazy — it stops evaluating a logical expression as soon as it knows the answer.
python
# runnable
def get_true():
    print("get_true called")
    return True
def get_false():
    print("get_false called")
    return False
# Short-circuit with and: if first is False, second is NOT evaluated
print(get_false() and get_true())  # get_true is NEVER called!
print("---")
# Short-circuit with or: if first is True, second is NOT evaluated
print(get_true() or get_false())   # get_false is NEVER called!
Output:
pseudo
get_false called
False
---
get_true called
True
Why this matters: If the second operand has side effects (like modifying a variable), those side effects won't happen if short-circuiting kicks in. Also, you can use this to safely check conditions: if x != 0 and 10/x > 2 — if x is 0, the division never happens, avoiding ZeroDivisionError.

4.7 Membership Operators — in and not in

What problem does this solve? You often need to check if something exists inside a collection — like checking if a letter is in a word, or if an item is in a list.
python
# runnable
word = "python"
print("p" in word)       # True
print("z" in word)       # False
print("tho" in word)     # True (substring exists)
print("xyz" not in word) # True (xyz is NOT in word)
# Works with lists too
fruits = ["apple", "banana", "cherry"]
print("banana" in fruits)    # True
print("grape" in fruits)     # False
Output:
pseudo
True
False
True
True
True
False

4.8 Identity Operators — is and is not

Crucial difference: == checks if values are the same. is checks if two variables point to the SAME object in memory.
python
# runnable
a = [1, 2, 3]
b = [1, 2, 3]    # b has the same values as a
c = a             # c points to the SAME list as a
print(a == b)     # True  (values are equal)
print(a is b)     # False (different objects in memory)
print(a is c)     # True  (same object)
# For simple types like small integers, Python sometimes reuses objects
x = 5
y = 5
print(x is y)     # True (Python caches small integers)
Output:
pseudo
True
False
True
True
⚠️ Rule of thumb: Use == for comparing values. Use is for checking None (if x is None:). Never use is to compare numbers or strings in normal code — it behaves unpredictably across implementations.

4.9 Operator Precedence — The Complete Table

When multiple operators appear in an expression, Python follows this order (highest to lowest precedence):
LevelOperatorsDescription
1(...)Parentheses (highest)
2**Exponentiation
3+x, -x, ~xUnary plus, minus, bitwise NOT
4*, /, //, %Multiplication, division, floor division, modulus
5+, -Addition, subtraction
6>Bitwise shifts
7&Bitwise AND
8^Bitwise XOR
9|Bitwise OR
10==, !=, >, =, <=, in, not in, is, is notComparisons, membership, identity
11notLogical NOT
12andLogical AND
13orLogical OR (lowest)
Associativity: When operators have the SAME precedence, associativity decides the order:
  • Left-to-right: Most operators (+, -, *, /, //, %, and, or, etc.)
  • Right-to-left: ** (exponentiation) and assignment operators

4.10 Worked Example 1: Complex Expression Evaluation

python
# runnable
result = 5 + 3 * 2 ** 2 // 4 - 1
print(result)
Step-by-step evaluation:
  1. 2 ** 24 (exponent: highest of the actual operators)
  2. 3 * 4 // 412 // 43 (* and // same precedence, left to right)
  3. 5 + 3 - 17 Output: 7

4.11 Worked Example 2: Logical Expression with Comparisons

python
# runnable
x = 10
y = 20
z = 15
result = x < y and y > z or not x == z
print(result)
Step-by-step:
  1. x < y10 < 20True
  2. y > z20 > 15True
  3. x == z10 == 15False
  4. not FalseTrue
  5. True and TrueTrue
  6. True or TrueTrue Output: True

4.12 Worked Example 3: Leap Year Condition

A year is a leap year if it's divisible by 400, OR divisible by 4 but NOT by 100.
python
# runnable
year = 2024
is_leap = (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0)
print(f"{year} is a leap year? {is_leap}")
year = 1900
is_leap = (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0)
print(f"{year} is a leap year? {is_leap}")
year = 2000
is_leap = (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0)
print(f"{year} is a leap year? {is_leap}")
Output:
pseudo
2024 is a leap year? True
1900 is a leap year? False
2000 is a leap year? True

4.13 Worked Example 4: Safe Division with Short-Circuit

python
# runnable
def divide_safe(a, b):
    # Short-circuit: if b == 0, the division never happens
    return b != 0 and a / b
print(divide_safe(10, 2))    # 5.0
print(divide_safe(10, 0))    # False (b != 0 is False, so a/b never runs)
Output:
pseudo
5.0
False
Note: In real code, you'd use if/else for safety. This example demonstrates short-circuit behavior.

4.14 Worked Example 5: Combining All Operator Types

python
# runnable
age = 25
salary = 50000
has_job = True
credit_score = 720
# Loan eligibility: age >= 21, salary > 30000, has job, good credit
eligible = age >= 21 and salary > 30000 and has_job and credit_score >= 650
print(f"Loan eligible: {eligible}")
# Also check if they're in a "premium" category
premium = salary > 100000 or (salary > 50000 and credit_score > 750)
print(f"Premium customer: {premium}")
# Not a risky candidate
risky = not has_job or credit_score < 600
print(f"Risky: {risky}")
Output:
pseudo
Loan eligible: True
Premium customer: False
Risky: False

📐 Key Concepts Reference

OperatorTypeDescriptionExampleResult
+ArithmeticAddition5 + 38
-ArithmeticSubtraction5 - 32
*ArithmeticMultiplication5 * 315
/ArithmeticFloat division5 / 31.666...
//ArithmeticFloor division5 // 31
%ArithmeticModulus5 % 32
**ArithmeticExponentiation5 ** 3125
==ComparisonEqual to5 == 3False
!=ComparisonNot equal to5 != 3True
>ComparisonGreater than5 > 3True
<ComparisonLess than5 < 3False
>=ComparisonGreater or equal5 >= 3True
<=ComparisonLess or equal5 <= 3False
andLogicalBoth TrueTrue and FalseFalse
orLogicalEither TrueTrue or FalseTrue
notLogicalNegatenot TrueFalse
inMembershipIs member of"a" in "cat"True
isIdentitySame objectx is NoneTrue/False

⚠️ Common Pitfalls

Pitfall 1: Confusing = with ==

The mistake: if x = 5: instead of if x == 5: The error: SyntaxError: invalid syntax. Maybe you meant '=='? Why: Single = is assignment (a statement), not a comparison (an expression). Fix: Use == for comparisons. Remember: "checking equality uses two equals."

Pitfall 2: and/or Return Values (Not Boolean)

The mistake: Thinking and/or always return True/False. The truth: and and or return the value of one of the operands, not necessarily a boolean.
python
print(0 and 5)    # 0 (falsy value returned)
print(3 and 5)    # 5 (last truthy value)
print(0 or 5)     # 5 (first truthy value)
print(3 or 5)     # 3 (first truthy value)
Fix: If you need a boolean, use bool() or compare: if bool(x and y):

Pitfall 3: Floating-Point Equality

The mistake: 0.1 + 0.2 == 0.3 The result: False (surprise!) Why: Floating-point numbers can't represent some decimals exactly in binary.
python
print(0.1 + 0.2)  # 0.30000000000000004
print(0.1 + 0.2 == 0.3)  # False
Fix: Use abs((0.1 + 0.2) - 0.3) < 1e-10 (check if difference is tiny).

Pitfall 4: is for Value Comparison

The mistake: if x is 1000: when you want if x == 1000: Why: Python may or may not reuse objects for large integers. It works sometimes, fails other times. Fix: Always use == for comparing values. Use is only for None, True, False.

📝 Practice Questions

Q1: Evaluate step-by-step: 10 + 2 * 3 ** 2 - 6 // 4
Answer:
pseudo
10 + 2 * 3 ** 2 - 6 // 4
= 10 + 2 * 9 - 6 // 4    (exponent: 3**2 = 9)
= 10 + 18 - 6 // 4        (multiply: 2*9 = 18)
= 10 + 18 - 1             (floor division: 6//4 = 1)
= 27
Q2: What's the output?
python
print(5 > 3 and 2 < 4 or not 7 == 7)
Answer:
pseudo
True
Step-by-step:
  1. 5 > 3True
  2. 2 < 4True
  3. True and TrueTrue
  4. 7 == 7True
  5. not TrueFalse
  6. True or FalseTrue Q3: What's the difference between print(10 / 3) and print(10 // 3)?
Answer:
  • 10 / 33.3333333333333335 (float division, precise)
  • 10 // 33 (floor division, rounds down)
/ always returns float. // returns int when both operands are int (but float if either is float). Q4: What does this code output and why?
python
print("a" in "apple")
print("app" in "apple")
print("x" not in "apple")
Answer:
pseudo
True
True
True
  • "a" is a character in "apple" → True
  • "app" is a substring of "apple" → True
  • "x" is NOT in "apple"not in returns True Q5: Fix the error in this code:
python
x = input("Number: ")
if x % 2 == 0:
    print("Even")
Answer: Error: TypeError: not all arguments converted during string formatting or similar. Fix: Convert input to int: x = int(input("Number: ")) input() returns a string. The % operator on strings does something different (formatting). Q6: What does -7 // 3 evaluate to? Why?
Answer: -7 // 3-3
Because floor division rounds DOWN to negative infinity. -7/3 = -2.333.... Rounding down gives -3 (more negative). Not -2 (which would be rounding toward zero). Q7: Write a condition that checks if a number n is between 1 and 100 (inclusive).
Answer:
python
# runnable
n = 50
if 1 <= n <= 100:
    print(f"{n} is between 1 and 100")
Or: if n >= 1 and n <= 100: Q8: What does this output?
python
print(False or True and False)
Answer:
pseudo
False
  • True and FalseFalse (and has higher precedence than or)
  • False or FalseFalse Q9: Write a program that checks if a character entered by the user is a vowel.
Answer:
python
# runnable
ch = input("Enter a letter: ").lower()
is_vowel = ch in "aeiou"
print(f"Is '{ch}' a vowel? {is_vowel}")
Q10: What's the value of this expression?
python
(15 % 4) == 3 and (2 ** 3) > 10 or "py" in "python"
Answer:
pseudo
True
Step-by-step:
  1. 15 % 43
  2. 3 == 3True
  3. 2 ** 38
  4. 8 > 10False
  5. True and FalseFalse
  6. "py" in "python"True
  7. False or TrueTrue

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.