Python Basics October 23 ,2025

Operators and Expressions 

This section explains Python operators and expressions in depth. For each operator category you’ll get: the conceptual meaning, syntax, worked examples, common pitfalls, performance/implementation notes where relevant, and best practices. Where useful, I show the underlying bit-level or evaluation behaviour so you truly understand what’s happening, not just what to type.

Quick terminology

  • Operator — a symbol or keyword that tells Python to perform an operation (e.g., +, and, is).
  • Operand — the value(s) the operator acts on.
  • Expression — any combination of operators and operands that produces a value.
  • Evaluation — how and when Python computes the value of an expression.

1. Arithmetic operators

Arithmetic operators perform numeric calculations. They typically operate on int, float, complex, or any user-defined numeric types that implement the corresponding special methods.

Operators and meanings

  • + : addition
  • - : subtraction (also unary negation)
  • * : multiplication
  • / : true division — always returns float (even if operands are integers)
  • // : floor division — returns the floor of the quotient (type: int for integer operands, float for float operands)
  • % : modulo (remainder)
  • ** : exponentiation (power)
  • +x, -x : unary plus and minus

Examples and explanation

a = 7
b = 3

a + b       # 10           -> addition
a - b       # 4            -> subtraction
a * b       # 21           -> multiplication
a / b       # 2.3333333333 -> true division (float)
a // b      # 2            -> floor division (7 / 3 = 2.333..., floor -> 2)
a % b       # 1            -> remainder of 7 divided by 3
a ** b      # 343          -> 7 to the power 3

Key points

  • / returns a floating point: 4 / 2 == 2.0.
  • // returns the floor. For negatives, floor is toward negative infinity:
    • Example: -7 // 3 == -3 because -7 / 3 == -2.333..., floor is -3.
  • % satisfies the relation:
    a == (a // b) * b + (a % b) — with // as floor division, so for negatives % gives a non-negative remainder when divisor is positive.
  • ** has higher precedence than unary minus: -2**2 is parsed as -(2**2) → -4. Use parentheses for clarity.
  • Exponentiation can be expensive for large powers (consider pow(a, b, mod) if you want modular exponentiation).

Pitfalls

  • Mixing int and float yields float results; watch for floating-point precision errors (e.g., 0.1 + 0.2 != 0.3 exactly).
  • Floor division and modulo for negative numbers can be unintuitive — test examples when negative operands are possible.

2. Comparison operators

Comparison (relational) operators compare values and return bool (True/False).

Operators

  • == : equality
  • != : inequality
  • < : less than
  • > : greater than
  • <= : less than or equal
  • >= : greater than or equal

Examples & notes

3 == 3      # True
3 != 4      # True
2 < 5       # True
5 <= 5      # True
'abc' < 'b' # True, lexicographic comparison of strings

Important behaviour

  • Comparisons for sequences (strings, lists, tuples) are lexicographic: Python compares element by element.
  • You can chain comparisons: a < b <= c is equivalent to a < b and b <= c but evaluated more efficiently and safely (middle expression evaluated once).
    • Example: 1 < x <= 10
  • == compares values (calls __eq__), while is (see Identity) compares object identity.

Pitfalls

  • Floating-point comparisons: avoid direct equality (==) on floating-point results unless you control the calculation — prefer tolerance-based checks: abs(a - b) < 1e-9.

3. Logical operators

Logical operators combine boolean expressions.

Operators

  • and — logical AND
  • or — logical OR
  • not — logical NOT

Evaluation rules (truthiness)

Python uses truthiness: any object can be tested in boolean context. By default:

  • False values: False, None, numeric zero (0, 0.0), empty sequences/collections ('', [], {}, ()), and objects that implement __bool__() returning False.
  • Everything else is considered True.

Short-circuiting behaviour (important)

  • A and B: evaluate A; if A is falsey, return A (do not evaluate B); otherwise evaluate and return B.
  • A or B: evaluate A; if A is truthy, return A (do not evaluate B); otherwise evaluate and return B.
  • not A: return True if A is falsey, else False.

Note: and/or return the actual operand value, not necessarily a bool. Only when used in conditional contexts does Python coerce to bool.

Examples

# Short-circuit behavior
def expensive():
    print("called")
    return True

False and expensive()   # returns False, expensive() not called
True or expensive()     # returns True, expensive() not called

# Return values
1 and 2      # returns 2 (since 1 is truthy, returns second operand)
0 and 2      # returns 0 (first is falsey)
'' or 'fallback'  # returns 'fallback'

Best practice

  • Use and/or for boolean logic. Avoid relying on the non-boolean return values unless you intentionally want fallback behaviour (common idiom: value or default).
  • Be careful when expressions have side effects — short-circuiting can skip those effects.

4. Bitwise operators

Bitwise operators operate on integers at the level of their binary representation.

Operators

  • & : bitwise AND
  • | : bitwise OR
  • ^ : bitwise XOR (exclusive OR)
  • ~ : bitwise NOT (ones’ complement)
  • << : left shift
  • >> : right shift (arithmetic for signed integers in Python; conceptually logical for non-negative ints)

Python integers are of arbitrary precision (no fixed width), so bitwise operations work on an infinite-length two's complement representation conceptually; practically you can treat them as operating on the binary form of the integer.

Examples (showing binary)

Represent numbers in binary with bin():

a = 0b1010   # 10
b = 0b0111   # 7

a & b   # 0b0010 -> 2
a | b   # 0b1111 -> 15
a ^ b   # 0b1101 -> 13
~a      # bitwise NOT, returns -11 in Python because ~x == -(x+1)

# Shifts
1 << 3  # 8   (1 * 2**3)
16 >> 2 # 4   (16 // 2**2)

Understanding ~

  • ~x equals -(x + 1). Example: ~0 == -1, ~1 == -2.

Shifts

  • x << n multiplies x by 2**n.
  • x >> n divides x by 2**n using floor division for non-negative numbers; for negative numbers it arithmetic-shifts (preserves sign), which can be surprising.

Use cases

  • Low-level bit twiddling, flags, masks, compact storage, cryptography primitives, performance-sensitive code.

Pitfalls

  • Because Python int is unbounded, there’s no overflow; left-shifting very large values consumes memory/time.
  • Avoid bit tricks that depend on fixed-width representations unless you explicitly mask bits.

5. Assignment operators

Assignment operators assign values to variables. Python supports simple assignment and augmented assignment operators (compound assignment).

Simple assignment

  • = : assigns right-hand value to left-hand target(s)
x = 5
a, b = 1, 2    # tuple unpacking

Augmented assignment

  • +=, -=, *=, /=, //=, %=, **=, &=, |=, ^=, <<=, >>=

Example and semantics:

x = 5
x += 3   # x = x + 3 -> 8

lst = [1, 2]
lst += [3]   # modifies list in place -> lst is now [1, 2, 3]

For mutable objects, augmented assignments may mutate the object in place (calling __iadd__), whereas for immutable objects they create a new object.

Chained assignment

a = b = 0  # both refer to the same object initially (0 is immutable)

Best practice

  • Use augmented assignment for clarity and potential in-place performance.
  • Be mindful with mutables — a = b leads to aliasing; mutate a and b both see change if same object.

6. Membership operators (in, not in)

Membership operators check whether a value is contained in a container.

Operators

  • x in y — True if x is an element of y
  • x not in y — negation of in

Containers supported

  • Sequences (strings, lists, tuples)
  • Sets, dict (checks keys), custom objects implementing __contains__

Examples

'a' in 'abc'      # True
3 in [1, 2, 3]    # True
'k' in {'k': 1}   # True (checks keys)
5 not in range(10) # False

Performance notes

  • in is O(1) average for set and dict (hash-based).
  • in is O(n) for lists and tuples (linear scan).
  • For large membership checks, prefer set when appropriate.

Pitfalls

  • For dict, in checks keys, not values; use .values() if you need values (but that's O(n)).
  • For custom classes, implement __contains__ to support in.

7. Identity operators (is, is not)

Identity operators test whether two references point to the same object (identity), not whether their values are equal.

Operators

  • is — True if both operands refer to the same object (id(a) == id(b))
  • is not — negation

Examples and notes

a = []
b = []
a == b      # True -> values equal (both empty lists)
a is b      # False -> different objects

c = a
a is c      # True -> same object

Subtleties

  • Small integers and short strings are interned or cached by CPython for performance. Example: a = 256; b = 256; a is b may be True, while for larger integers it may be False. This is an implementation detail — do not rely on it.
  • Use == to test equality of value; use is only to check identity or to test singletons like None:

    if x is None: ...
    

    This is the recommended pattern.

Pitfalls

  • is with literals can give surprising results because of interning. Always use == for numeric/string equality checks.

8. Operator precedence and associativity

When an expression has multiple operators, precedence determines which operator is applied first; associativity determines the order when operators have the same precedence.

Precedence table (highest → lowest)

(Condensed, common operators; higher appears earlier)

  1. Parentheses: () — explicit grouping (highest precedence)
  2. Exponentiation: ** — right-associative
  3. Unary plus/minus, bitwise NOT: +x, -x, ~x
  4. Multiplicative: *, /, //, %
  5. Additive: +, -
  6. Bitwise shifts: <<, >>
  7. Bitwise AND: &
  8. Bitwise XOR: ^
  9. Bitwise OR: |
  10. Comparisons: <, <=, >, >=, !=, == (note: chained comparisons are special)
  11. not (Boolean NOT)
  12. and
  13. or
  14. Conditional expression: if-else (ternary) — A if cond else B
  15. Lambda: lambda (lowest precedence among expressions)

Associativity

  • Most binary operators are left-associative (evaluated left-to-right): e.g., a - b - c is (a - b) - c.
  • Exponentiation is right-associative: 2 ** 3 ** 2 is 2 ** (3 ** 2) → 2 ** 9 → 512.
  • Chained comparisons are evaluated such that expressions like a < b < c are a < b and b < c but b is evaluated once.

Example (why precedence matters)

3 + 4 * 2      # 11 -> multiplication first
(3 + 4) * 2    # 14 -> parentheses override precedence

2 ** 3 ** 2    # 512 -> 3 ** 2 = 9, then 2 ** 9

Best practice

  • Use parentheses to make intent explicit. Even if you “know” precedence, parentheses improve readability and avoid subtle bugs.

9. Compound expressions

Compound expressions combine multiple operators and sub-expressions. They can include nested function calls, comprehensions, ternary expressions, and chained comparisons.

Examples

# Ternary conditional
result = "even" if n % 2 == 0 else "odd"

# Combined with function calls
print("Positive") if x > 0 else print("Non-positive")

# Comprehension with condition
squares = [x**2 for x in range(10) if x % 2 == 0]

Evaluation order

  • Python evaluates left-to-right for most parts, respects precedence, and short-circuits logical operators.
  • In comprehensions the loop expression is evaluated in order as specified.

Tips

  • Prefer readable compound expressions; avoid overly complex single-line expressions. Break into multiple statements if it improves clarity and debuggability.

10. Short-circuit evaluation (in-depth)

Short-circuiting is a key evaluation optimisation for and and or and is crucial when expressions have side effects or costly computations.

Details

  • A and B:
    • Evaluate A. If A is falsey, Python returns A immediately (does not evaluate B).
    • If A is truthy, evaluate and return B.
  • A or B:
    • Evaluate A. If A is truthy, return A immediately.
    • Otherwise evaluate and return B.

Practical uses

  • Safe attribute access or fallback:

    value = obj and obj.attribute  # returns attribute if obj is truthy, else obj (often None)
    name = input_name or "Guest"   # fallback to "Guest" if input_name is empty or None
    
  • Guarding expensive operations:

    if short_circuit_condition() and expensive_check():
        ...
    

    If the first function returns falsey, expensive_check() is not called.

Side effects and gotchas

  • If the second operand has side effects (like function call, mutation, I/O), those side effects may be skipped. This can be used intentionally but can also hide bugs.
  • Example with file operations:

    file_obj = open(path) if os.path.exists(path) and os.path.getsize(path) > 0 else None
    

    If os.path.exists(path) is False, os.path.getsize(path) is not called — desired to avoid error.

Example illustrating return value (non-boolean)

# returns the first truthy value
result = [] or 0 or "" or None or "fallback"  # "fallback"

Best practice

  • Use short-circuit intentionally for guards and lazy evaluation.
  • Do not write code whose correctness depends on non-obvious short-circuit side effects. Keep logic explicit for maintainability.

11. Example-based explanations — putting it all together

Example 1 — Combined arithmetic, comparison, and logical operators

a = 4
b = 7
c = 2

# compound expression
if (a + b * c) % 2 == 0 and not (b < 0):
    print("Even result and b non-negative")

Evaluation steps:

  1. b * c → 7 * 2 = 14
  2. a + 14 → 4 + 14 = 18
  3. 18 % 2 → 0
  4. 0 == 0 → True
  5. b < 0 → False; not (False) → True
  6. True and True → True → prints

Example 2 — Bitwise mask and membership

PERM_READ  = 0b100
PERM_WRITE = 0b010
PERM_EXEC  = 0b001

perms = PERM_READ | PERM_WRITE  # 0b110

# Check write permission
if perms & PERM_WRITE:
    print("Write allowed")

perms & PERM_WRITE evaluates to 0b010 (truthy), so condition passes.

Example 3 — Identity vs equality

a = [1, 2, 3]
b = a
c = [1, 2, 3]

a == c   # True -> same contents
a is c   # False -> different objects
a is b   # True  -> alias to same list

Example 4 — Short-circuit preventing errors

user = None

# Safe access: only evaluate second part if user is truthy
if user and user.profile.is_active:
    print("Active")
# If user is None, user.profile would raise AttributeError; short-circuit prevents it.

Example 5 — Precedence gotcha

x = 2
y = 3

# What is the result?
z = -x ** y
# Parsed as: z = -(x ** y) -> -(2 ** 3) -> -8

# To get (-x) ** y
z_correct = (-x) ** y  # (-2) ** 3 -> -8 (same in this odd case)
# But for even y: (-2) ** 2 -> 4 vs -(2 ** 2) -> -4

12. Best practices and performance tips

  • Readability first: Use parentheses liberally for clarity, even when not required by precedence.
  • Use == for value equality and is for identity checks (primarily for None).
  • Prefer and/or for boolean logic rather than bitwise &/| unless you deliberately want bit-level operations or to use NumPy array boolean logic (where & is overloaded).
  • Watch mutability with augmented assignment: x += y may mutate x in-place if x is mutable.
  • Avoid depending on CPython implementation details (like small integer/string interning).
  • For performance-sensitive numeric code, bitwise operators are cheap, but avoid very large shifts that create huge integers.
  • When checking membership many times, prefer set over list for O(1) average lookup.
  • Prefer f-strings and format for readable output when printing expression results.

13. Short exercises (practice)

  1. Compute (5 + 3) ** 2 // 7 and show each evaluation step.
  2. Implement a function that checks whether a number has the 3rd bit set (bit positions starting at 0).
  3. Demonstrate with code how and and or return operands (not just True/False).

Final notes

This guide covered the semantics and practical use of Python operators. Operators are basic building blocks; understanding evaluation order, short-circuiting, and the difference between value and identity comparisons prevents many subtle bugs. 

 

Next Blog- Control Flow in Python

Sanjiv
0

You must logged in to post comments.

Get In Touch

G06, Kristal Olivine Bellandur near Bangalore Central Mall, Bangalore Karnataka, 560103

+91-8076082435

techiefreak87@gmail.com