Variables and Types¶
In Python, you don't declare variables. You just assign values to names, and Python figures out the type automatically. This is called dynamic typing.
Your First Variables¶
# These are all valid assignments — no type declaration needed
name = "Alice"
age = 30
height = 5.7
is_student = True
nothing = None
That's it. Python sees "Alice" and knows it's a string. It sees 30 and knows it's an integer. You never write int age = 30; like you would in Java or C.
The Built-In Types¶
Python has a small set of core types built into the language:
| Type | Examples | Description |
|---|---|---|
int | 0, 42, -7, 1_000_000 | Whole numbers, any size |
float | 3.14, -0.5, 1.5e10 | Decimal numbers (IEEE 754 double) |
complex | 3+4j, 1j | Complex numbers |
bool | True, False | Boolean — subclass of int |
str | "hello", 'world' | Text (Unicode) |
bytes | b"data" | Raw binary data |
list | [1, 2, 3] | Ordered, mutable sequence |
tuple | (1, 2, 3) | Ordered, immutable sequence |
dict | {"key": "value"} | Key-value mapping |
set | {1, 2, 3} | Unordered unique values |
frozenset | frozenset({1, 2}) | Immutable set |
NoneType | None | Represents "no value" |
Checking Types¶
x = 42
print(type(x)) # <class 'int'>
print(isinstance(x, int)) # True
name = "Alice"
print(type(name)) # <class 'str'>
# isinstance is better than type() == ... for checking
# because it handles inheritance properly
print(isinstance(True, int)) # True! bool is a subclass of int
print(type(True) == int) # False — it's exactly bool
Dynamic Typing — Names, Not Variables¶
Here's the key mental model: in Python, a name is just a label stuck on an object. The object has a type; the name doesn't.
x = 42 # name 'x' points to the integer 42
x = "hello" # name 'x' now points to the string "hello"
x = [1, 2, 3] # name 'x' now points to a list
This is totally valid Python. The type of x changed — but really, x itself doesn't have a type. The object has a type. x is just a name pointing at different objects over time.
Compare this to a statically-typed language where a variable's type is fixed at declaration and you'd get a compile error trying to assign an int, then a string, to the same variable.
id() — Object Identity¶
Every object in Python has a unique identity (its memory address in CPython):
a = 42
b = 42
print(id(a)) # e.g. 140235681234560
print(id(b)) # might be the SAME — CPython caches small integers
# For lists, always different objects:
x = [1, 2]
y = [1, 2]
print(id(x) == id(y)) # False — two separate list objects
Integer caching
CPython caches integers from -5 to 256. So a = 42; b = 42; a is b is True — they literally point to the same object. Above 256, new objects are created each time. Never rely on this in production code; use == for value comparison.
Type Conversion (Casting)¶
You can explicitly convert between types:
# To integer
int("42") # 42
int(3.9) # 3 — truncates, does NOT round
int(True) # 1
int("0xFF", 16) # 255 — base 16
# To float
float("3.14") # 3.14
float(42) # 42.0
# To string
str(42) # "42"
str(3.14) # "3.14"
str(True) # "True"
# To bool
bool(0) # False
bool("") # False
bool([]) # False — empty list is falsy
bool(None) # False
bool(42) # True — any non-zero int is truthy
bool("hello") # True — non-empty string is truthy
bool([0]) # True — list with one element is truthy
Truthiness — Every Object Has a Boolean Value¶
In Python, every object can be used in a boolean context (like an if statement). The rules:
Falsy values (evaluate to False in boolean context): - None - False - 0, 0.0, 0j (numeric zeros) - "", b"" (empty sequences) - [], (), {}, set() (empty containers) - Any object whose __bool__() returns False or __len__() returns 0
Everything else is truthy.
items = []
if items: # False — empty list is falsy
print("has items")
else:
print("empty") # This runs
name = "Alice"
if name: # True — non-empty string is truthy
print(f"Hello, {name}")
This is why Python code often writes if items: instead of if len(items) > 0: — they mean the same thing and the first is more idiomatic.
None — The Absence of a Value¶
None is Python's null value. It's a singleton — there's exactly one None object in any Python program:
result = None
# The idiomatic way to check for None:
if result is None:
print("no result yet")
# Never use == for None comparison:
if result == None: # works but not idiomatic — use 'is'
pass
None is what functions return when they don't explicitly return anything:
def do_something():
x = 1 + 1 # does work but returns nothing
result = do_something()
print(result) # None
print(type(result)) # <class 'NoneType'>
Multiple Assignment and Unpacking¶
# Assign the same value to multiple names
a = b = c = 0
# Tuple unpacking — assign multiple names at once
x, y = 10, 20
print(x) # 10
print(y) # 20
# Swap two variables — clean Python idiom
x, y = y, x
# Extended unpacking (Python 3)
first, *rest = [1, 2, 3, 4, 5]
print(first) # 1
print(rest) # [2, 3, 4, 5]
*most, last = [1, 2, 3, 4, 5]
print(most) # [1, 2, 3, 4]
print(last) # 5
first, *middle, last = [1, 2, 3, 4, 5]
print(middle) # [2, 3, 4]
Naming Conventions (PEP 8)¶
| Convention | Example | Used for |
|---|---|---|
snake_case | my_variable, user_name | Variables, functions, modules |
SCREAMING_SNAKE | MAX_SIZE, PI | Constants |
PascalCase | MyClass, HttpClient | Classes |
_leading_underscore | _internal | Intended for internal use |
__double_leading | __mangled | Name mangling in classes |
__dunder__ | __init__, __str__ | Special/magic methods |
Pick meaningful names
user_count beats uc. calculate_total_price beats calc. Future-you (and your teammates) will thank you.