Skip to content
Hello Python
1/8

Variables & Data Types

Topic 1 of 8, with 4 concept checks. Names, values, and Python's built-in types

Trace names, values, and runtime types

Names and objects

Follow what each name refers to, how rebinding changes that reference, and where Python discovers a value's type at runtime before you reason about larger expressions.

Core lesson 01

Mutable objects change in place (id() stays the same). Immutable objects can't — any 'change' creates a brand new object.

Every value in Python is an object with an identity, type, and value. Mutability is about whether that value can change after creation. Mutable types (list, dict, set) can be edited in place — the object's id() stays constant. Immutable types (int, float, str, tuple, bool, frozenset) can never be altered; operations that look like edits actually build and return a new object.

Python example
a = [1, 2, 3]
print(id(a))
a.append(4)
print(id(a))          # same id -> mutated in place

s = "hi"
print(id(s))
s = s + "!"
print(id(s))          # different id -> new object

What to remember

What's the difference between mutable and immutable types in Python? Name two of each.

Common footguns

  • Assuming `tuple` is 'fully' immutable — a tuple containing a list still lets you mutate that inner list.
  • Passing a mutable object into a function and being surprised the caller's copy changed too — Python passes references, not copies.
IMMUTABLE (int, str, tuple)        MUTABLE (list, dict, set)

 x = 5      id: 0x1001            a = [1,2]    id: 0x2001
 x = x+1                          a.append(3)
 x -> id: 0x1002 (NEW object)     a -> id: 0x2001 (SAME object)

Core lesson 02

No — 1 + '1' raises a TypeError. Python coerces compatible numeric types, but never silently converts between unrelated types.

'Dynamically typed' means variables aren't declared with a fixed type. 'Strongly typed' means Python still refuses to operate on incompatible types without an explicit conversion. int + float works because both are numeric and Python defines a coercion path between them. int + str has no defined coercion, so Python raises rather than guessing what you meant.

Python example
print(1 + 2.0)     # 3.0  (int/float coercion is fine)
try:
    print(1 + "1")
except TypeError as e:
    print("TypeError:", e)
print(str(1) + "1")  # "11" once you're explicit

What to remember

Does Python automatically coerce types for 1 + '1'?

Common footguns

  • Relying on implicit conversion in other languages (JS's `1 + '1' === '11'`) and expecting the same here.
  • Forgetting that `input()` always returns a str — `input() + 1` fails until you wrap it in `int(...)`.

Core lesson 03

== compares values (calls __eq__). is compares identity — are these literally the same object in memory.

Every object has a unique id() for its lifetime. `is` checks whether two names refer to that same id. `==` instead calls the object's `__eq__` method to compare value equality, which you can define however makes sense for a custom class. Two different objects can be `==` equal while being distinct in memory (`is` False).

Python example
a = [1, 2, 3]
b = a
c = [1, 2, 3]
print(b is a)    # True  -- same object
print(c is a)    # False -- different object
print(c == a)    # True  -- same value

What to remember

What's the difference between is and ==?

Common footguns

  • Using `x == None` instead of `x is None` — works most of the time but isn't idiomatic and can misbehave with custom __eq__.
  • Small integers (-5 to 256) and short strings are cached by CPython, so `is` can accidentally return True for them — don't rely on this.
a = [1,2,3]        +------+       +---------+
b = a              |  a  ---------->| [1,2,3] |<--- b also points here
b is a -> True     +------+       +---------+   id: 0x3001

c = [1,2,3]        +------+       +---------+
                    |  c  ---------->| [1,2,3] |  id: 0x4002 (different box)
c == a -> True (same values)
c is a -> False (different boxes)

Core lesson 04

type(1/2) is float (0.5). type(1//2) is int (0). / always true-divides; // floors the result.

Python 2 made `/` behave like floor division for two ints, which caused endless bugs. Python 3 fixed this: `/` is always true division and returns a float. `//` is floor division — it rounds toward negative infinity and returns an int if both operands are ints, or a float if either operand is a float.

Python example
print(1 / 2)     # 0.5
print(1 // 2)    # 0
print(7 // 2)    # 3
print(-7 // 2)   # -4  (floors toward -inf, not toward 0)
print(7.0 // 2)  # 3.0 (float in -> float out)

What to remember

What is type(1/2) vs type(1//2) in Python 3?

Common footguns

  • Expecting `//` to truncate toward zero like C — it floors instead, so negative results can surprise you.
  • Porting Python 2 code where `/` meant integer division and silently getting floats now.

Python lab

Browser Python lab

Runtime · idle

Python loads on your first run. Your code stays in this browser.

Best practices

  • Use descriptive snake_case names for variables (PEP 8).
  • Avoid shadowing Python built-ins (list, dict, str, type) as variable names.
  • Add type hints for clarity in larger codebases: `age: int = 25`.
  • Prefer `is None` / `is not None` over `== None`.

Apply the concept in Interview practice

Two SumeasyLeetCode #1 · O(n) time, O(n) space

Store value→index in a dict while iterating once. For each number, check whether target−num is already a key.

Open problem
FizzBuzzeasyHackerRank · O(n) time, O(1) space

Loop 1..n. If divisible by 15 print FizzBuzz, by 3 print Fizz, by 5 print Buzz, otherwise print the number.

Open problem
Making AnagramseasyHackerRank · O(n) time, O(k) space

Use collections.Counter on both strings; the answer is the total count of characters that don't overlap between the two counters.

Open problem
Reverse IntegermediumLeetCode #7 · O(log n) time, O(1) space

Pop digits with % 10 and // 10, rebuild the reversed number, and check for 32-bit signed overflow before returning — no string conversion needed.

Open problem
Palindrome NumbereasyLeetCode #9 · O(log n) time, O(1) space

Without converting to a string, reverse the second half of the number mathematically and compare it to the first half.

Open problem

Concept checks

Q01

What's the difference between mutable and immutable types in Python? Name two of each.

Q02

Does Python automatically coerce types for 1 + '1'?

Q03

What's the difference between is and ==?

Q04

What is type(1/2) vs type(1//2) in Python 3?