Variables and Data Types
Table of Contents
In the Introduction to Python, we used variables and saw the basic types like str, int, and float. This tutorial goes deeper — we’ll look at how Python handles types, what mutability means, how to convert between types, and the string and number operations you’ll use constantly.
How Variables Work in Python
In Python, variables don’t store values directly — they’re names that point to objects in memory. When you write x = 42, Python creates an integer object 42 and makes x point to it.
x = 42
y = x # y points to the same object as x
print(y) # 42
x = 100 # x now points to a new object; y is unaffected
print(y) # 42
You can verify this with id(), which returns an object’s memory address:
a = [1, 2, 3]
b = a
print(id(a) == id(b)) # True — same object
b = [1, 2, 3]
print(id(a) == id(b)) # False — different objects with same content
This distinction matters most with mutable types like lists, which we’ll cover shortly.
Naming Rules
Python variable names must start with a letter or underscore, and can contain letters, digits, and underscores. The convention is snake_case:
user_name = "Alice" # good
max_retries = 3 # good
_internal = True # leading underscore = "private by convention"
PI = 3.14159 # ALL_CAPS = constant by convention
PI = 3.14159 can be reassigned. The ALL_CAPS naming is just a signal to other developers that the value shouldn’t change.
Numeric Types
Python has three numeric types: int, float, and complex.
Integers
Integers have unlimited precision — they can be as large as your memory allows:
big = 10 ** 100 # a googol — no overflow
print(type(big)) # <class 'int'>
# Underscores for readability
population = 8_000_000_000
print(population) # 8000000000
Floats
Floats are 64-bit double-precision numbers. Like all floating-point implementations, they have precision limits:
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
# Use round() or math.isclose() for comparisons
import math
print(math.isclose(0.1 + 0.2, 0.3)) # True
print(round(0.1 + 0.2, 1)) # 0.3
Arithmetic Operations
print(10 + 3) # 13 addition
print(10 - 3) # 7 subtraction
print(10 * 3) # 30 multiplication
print(10 / 3) # 3.333 true division (always returns float)
print(10 // 3) # 3 floor division (rounds down)
print(10 % 3) # 1 modulo (remainder)
print(2 ** 10) # 1024 exponentiation
/ always returns a float in Python 3, even for 10 / 2 (which gives 5.0). Use // when you want an integer result.
Strings
Strings are immutable sequences of characters. You can use single quotes, double quotes, or triple quotes:
single = 'hello'
double = "hello"
multi = """This is
a multi-line
string."""
Common String Operations
name = "Alice"
print(len(name)) # 5
print(name.upper()) # ALICE
print(name.lower()) # alice
print(name.startswith("A")) # True
print(name.replace("ice", "an")) # Alan
# Indexing and slicing
print(name[0]) # A
print(name[-1]) # e
print(name[1:4]) # lic
F-Strings and Formatting
F-strings can contain any valid expression:
x = 10
y = 3
print(f"{x} / {y} = {x / y:.2f}") # 10 / 3 = 3.33
print(f"{'hello':>20}") # right-align in 20 chars
print(f"{1000000:,}") # 1,000,000
print(f"{0.85:.0%}") # 85%
String Methods for Cleaning Data
These come up constantly when processing user input or file data:
raw = " Hello, World! "
print(raw.strip()) # "Hello, World!" — removes leading/trailing whitespace
print(raw.lstrip()) # "Hello, World! "
print(raw.rstrip()) # " Hello, World!"
csv_line = "alice,bob,charlie"
print(csv_line.split(",")) # ['alice', 'bob', 'charlie']
words = ["alice", "bob", "charlie"]
print(", ".join(words)) # "alice, bob, charlie"
Booleans and Truthiness
Python’s bool type has two values: True and False. But many other values have a “truthiness” that matters in if statements:
# Falsy values
print(bool(0)) # False
print(bool(0.0)) # False
print(bool("")) # False
print(bool([])) # False
print(bool(None)) # False
# Everything else is truthy
print(bool(1)) # True
print(bool("hello")) # True
print(bool([1, 2])) # True
This means you can write concise checks:
name = ""
if not name:
print("Name is empty")
items = [1, 2, 3]
if items:
print(f"Got {len(items)} items")
None
None is Python’s equivalent of “no value.” It’s not the same as 0, False, or an empty string:
result = None
# Always use 'is' to check for None, not ==
if result is None:
print("No result yet")
is None and is not None rather than == None. The is operator checks identity (same object), which is the correct way to test for None.
Type Conversion
Python doesn’t do implicit type coercion the way JavaScript does. You need to convert explicitly:
# String to number
age = int("25")
price = float("9.99")
# Number to string
s = str(42)
# This fails — Python won't guess
# print("Age: " + 25) # TypeError
print("Age: " + str(25)) # "Age: 25"
print(f"Age: {25}") # "Age: 25" — f-strings handle it
Conversion functions raise errors on invalid input:
# int("hello") # ValueError: invalid literal for int()
# int("3.14") # ValueError — use float() first, then int()
print(int(float("3.14"))) # 3
print(int(3.9)) # 3 — truncates, doesn't round
print(round(3.9)) # 4
Mutable vs Immutable
This is one of the most important concepts in Python. Immutable types can’t be changed after creation. Mutable types can.
| Immutable | Mutable |
|---|---|
int, float, bool |
list |
str |
dict |
tuple |
set |
Why does this matter? Because mutable objects can be changed through any variable that references them:
a = [1, 2, 3]
b = a # b points to the SAME list
b.append(4)
print(a) # [1, 2, 3, 4] — a is affected too!
# To make an independent copy:
c = a.copy() # or list(a) or a[:]
c.append(5)
print(a) # [1, 2, 3, 4] — a is NOT affected
Strings are immutable, so “modifying” a string always creates a new one:
s = "hello"
s2 = s.upper() # creates a new string "HELLO"
print(s) # "hello" — original unchanged
Multiple Assignment
Python lets you assign multiple variables in one line:
x, y, z = 1, 2, 3
print(x, y, z) # 1 2 3
# Swap without a temp variable
x, y = y, x
print(x, y) # 2 1
# Same value
a = b = c = 0
Checking Types
Use type() to see a value’s type and isinstance() to check against one or more types:
x = 42
print(type(x)) # <class 'int'>
print(isinstance(x, int)) # True
print(isinstance(x, (int, float))) # True — checks multiple types
isinstance() is preferred over type() for checks because it handles inheritance correctly.
What’s Next
Now that you understand how Python handles variables and types, you’re ready to explore functions — how to define them, pass arguments, and return values. Functions are where Python really starts to feel powerful.