Last 30 Days
No notifications
A variable is a name that refers to a value stored in memory. Python is dynamically typed β you don't declare types explicitly; the interpreter infers them at runtime.
name = "Alice" # str
age = 25 # int
height = 5.7 # float
is_student = True # bool
nothing = None # NoneType| Type | Example | Description |
| int | 42, -7, 0 | Whole numbers (unlimited precision) |
| float | 3.14, -0.5, 1e10 | Decimal numbers (64-bit IEEE 754) |
| str | "hello", 'world' | Text β immutable sequence of characters |
| bool | True, False | Logical values (subclass of int) |
| NoneType | None | Represents absence of a value |
type(42) # <class 'int'>
isinstance(42, int) # Trueint("10") # 10
float("3.14") # 3.14
str(100) # "100"
bool(0) # False
x = 10 # x is int
x = "hello" # x is now str β no error!a, b, c = 1, 2, 3
x = y = z = 0 # All set to 0
a, b = b, a # Swap values!| Rule | Valid | Invalid |
Start with letter or _ | _count, name | 2name |
| No spaces or special chars | my_var | my-var, my var |
| Case-sensitive | Name β name | β |
| No reserved keywords | score | class, if, for |
Variables are how you give names to data. In Python this is unusually flexible β no type declarations, no var / let, just name = value and you're off. Underneath, Python is doing something more interesting than other languages: variables are *labels* attached to *objects*, not boxes that hold values.
x = 42This creates an integer object 42 somewhere in memory and binds the name x to it. Reassign x = "hi" and x now points to a string object β the original 42 is unchanged (and may be garbage-collected if nothing else references it).
| Type | Example | Notes |
int | 42, -7 | arbitrary precision (no overflow) |
float | 3.14 | 64-bit IEEE 754 |
str | "hi", 'a' | unicode by default |
bool | True, False | a subclass of int (True == 1) |
NoneType | None | the "no value" singleton |
list | [1, 2, 3] | ordered, mutable |
tuple | (1, 2) | ordered, immutable |
dict | {"a": 1} | keyβvalue, mutable |
set | {1, 2, 3} | unique values, mutable |
age and Age are different.snake_case for variables/functions, UPPER_SNAKE for constants, PascalCase for classes.list, dict, type, id, sum.int("42") # 42
int(3.9) # 3 (truncates, doesn't round)
float("3.14") # 3.14
str(42) # "42"
bool(0), bool(1), bool(""), bool("a") # False, True, False, TrueKey rule: Python won't auto-convert between strings and numbers β "3" + 4 raises TypeError. Convert explicitly.
1. Comparing floats with ==. 0.1 + 0.2 == 0.3 is False. Use math.isclose or Decimal for money.
2. Mutable default arguments. def f(items=[]): shares the list across calls β horrifying bug. Use items=None and assign inside.
3. is vs ==. is checks *identity* (same object), == checks *equality*. Use is only for None, True, False.
4. Shadowing built-ins. list = [1,2] breaks every later list(...) call.
5. int("3.5"). Crashes β strings with decimals aren't ints. Go through float first.
6. Confusing assignment with equality. = assigns; == compares. if x = 5 is a syntax error in Python (small mercy).
x = 42
x.bit_length() # 6 β ints have methods
type(x) # <class 'int'>
id(x) # memory addressEven None, True, and integers are objects with attributes and methods. This uniformity is why Python feels consistent.
int, float, str, bool, tuple, frozenset, bytes. Reassignment makes a *new* object.list, dict, set, custom classes. You can change them in place.a = [1, 2, 3]
b = a # same list, two names
b.append(4)
print(a) # [1, 2, 3, 4] β surprise!Use b = a.copy() (or a[:] / list(a)) when you want an independent copy.
Every value can act as a boolean. Falsy values: False, None, 0, 0.0, "", [], {}, set(). Everything else is truthy.
name = ""
if name: # idiomatic; same as: if len(name) > 0
greet(name)None and SentinelsNone is the standard "absence of value". Always test with is / is not:
if result is None:
...
if user is not None:
...CPython caches small ints (-5 to 256). So a = 5; b = 5; a is b is True β but a = 1000; b = 1000; a is b is *implementation-defined* and may be False. Don't rely on is for value comparison; use ==.
Similarly, short strings that look like identifiers are *interned* and share memory. Useful trivia, never rely on it.
age: int = 25
name: str = "Alice"
tags: list[str] = []def greet(user: str, count: int = 1) -> str:
return f"hi {user}" * count
Type hints are *not enforced at runtime*. They're documentation that mypy / pyright check statically, and your IDE uses them for autocomplete and error squiggles. On any project >100 lines, turn them on.
from decimal import Decimal
Decimal("0.1") + Decimal("0.2") # Decimal('0.3') β exactFor financial code, use Decimal. For exact rational math, fractions.Fraction. Floats are fine for science, deadly for accounting.
Python uses reference counting + a cyclic garbage collector. When the last name pointing to an object is gone, memory is freed automatically. del x removes the binding (and if it was the last, frees the object). Tools: sys.getrefcount, gc module, tracemalloc for leak hunting.
1. Predict the type and value: bool([]), int("007"), str(True), float("3.14e2"). Run them, confirm.
2. Demonstrate the mutable-default-argument bug, then fix it with the None pattern.
3. Add type hints to a small function and run mypy file.py (or rely on Pylance) to confirm there are no warnings.
4. Compare a is b vs a == b for a, b = 5, 5 and a, b = 1000, 1000 β explain the difference.