In the previous tutorial, we installed Python and wrote our first program. Now let’s learn about the building blocks of every Python program: variables and types.

By the end of this tutorial, you will know how to create variables, work with different data types, format strings with f-strings, and convert between types.

Variables in Python

A variable stores a value. In Python, you create a variable by assigning a value with =:

name = "Alex"
age = 25
height = 1.75

Notice something? There are no type declarations. In Java, you would write String name = "Alex". In Python, you just write name = "Alex". Python figures out the type automatically.

This is called dynamic typing. The variable does not have a fixed type. It gets its type from the value you assign.

x = 42          # x is an integer
x = "hello"    # now x is a string — no error!
x = [1, 2, 3]  # now x is a list

You can reassign a variable to any type at any time. This is flexible, but it also means you need to be careful.

Basic Data Types

Python has five basic data types.

int — Integer Numbers

age = 25
count = -10
big_number = 1_000_000  # Underscores for readability

Integers have no decimal point. They can be positive, negative, or zero. Unlike many languages, Python integers have no size limit. You can store numbers as large as you want.

float — Decimal Numbers

height = 1.75
temperature = -3.5
pi = 3.14159

Floats have a decimal point. They are used for measurements, calculations, and scientific data.

str — Strings (Text)

name = "Alex"
greeting = 'Hello'  # Single or double quotes both work
poem = """This is
a multi-line
string."""

Strings are sequences of characters. You can use single quotes, double quotes, or triple quotes for multi-line strings.

bool — True or False

is_student = True
has_permission = False

Booleans have only two values: True and False. Note the capital letters. true (lowercase) is not valid in Python.

None — The Absence of a Value

middle_name = None

None is Python’s version of null. It means “no value” or “nothing.” It is not the same as 0, False, or an empty string "".

value = None
print(value is None)    # True
print(value == 0)       # False
print(value == False)   # False
print(value == "")      # False

Always use is (not ==) to check for None.

Checking Types

Use type() to check the type of a value:

print(type("hello"))    # <class 'str'>
print(type(42))         # <class 'int'>
print(type(3.14))       # <class 'float'>
print(type(True))       # <class 'bool'>
print(type(None))       # <class 'NoneType'>

Use isinstance() to check if a value is a specific type:

age = 25
print(isinstance(age, int))         # True
print(isinstance(age, str))         # False
print(isinstance(3.14, (int, float)))  # True — check multiple types

isinstance() is better than type() for type checking because it also works with inheritance.

Type Hints

Python is dynamically typed, but you can add type hints to make your code clearer:

username: str = "Sam"
score: int = 100
temperature: float = 36.6
active: bool = False
nickname: str | None = None  # Can be str or None

Type hints do not change how the code runs. Python ignores them at runtime. But they help you and other developers understand the code. They also let tools like VS Code give better autocomplete suggestions.

We will use type hints throughout this series. It is a good habit to start early.

f-Strings

f-strings are the modern way to format strings in Python. Add f before the quotes and put variables inside curly braces {}:

name = "Alex"
age = 25
print(f"Hello, {name}! You are {age} years old.")
# Output: Hello, Alex! You are 25 years old.

Expressions Inside f-Strings

You can put any expression inside the curly braces:

print(f"2 + 3 = {2 + 3}")           # Output: 2 + 3 = 5
print(f"{'hello'.upper()}")          # Output: HELLO
print(f"{'Python'!r}")              # Output: 'Python' (with quotes)

Number Formatting

pi = 3.14159
print(f"{pi:.2f}")         # Output: 3.14 (2 decimal places)
print(f"{1000000:,}")      # Output: 1,000,000 (comma separator)
print(f"{0.75:.0%}")       # Output: 75% (percentage)

f-String Debugging

Python 3.8 added a useful feature. Add = after the variable name to print both the name and value:

x = 42
y = "hello"
print(f"{x=}")    # Output: x=42
print(f"{y=}")    # Output: y='hello'

This is great for quick debugging. You do not need to type print(f"x = {x}") anymore.

Alignment

print(f"{'Left':<20}|{'Right':>20}")
# Output: Left                |               Right

print(f"{'Centered':^20}")
# Output:       Centered

String Methods

Strings have many useful methods. Here are the most important ones.

Changing Case

text = "Hello, World!"
print(text.upper())      # HELLO, WORLD!
print(text.lower())      # hello, world!
print(text.title())      # Hello, World!
print(text.capitalize()) # Hello, world!

Removing Whitespace

text = "  Hello, World!  "
print(text.strip())      # "Hello, World!" — removes both sides
print(text.lstrip())     # "Hello, World!  " — left side only
print(text.rstrip())     # "  Hello, World!" — right side only

Searching and Replacing

text = "Hello, World!"
print(text.find("World"))       # 7 (index where "World" starts)
print(text.find("Java"))        # -1 (not found)
print(text.replace("World", "Python"))  # "Hello, Python!"
print(text.count("l"))          # 3
print(text.startswith("Hello")) # True
print(text.endswith("!"))       # True

Splitting and Joining

# Split a string into a list
sentence = "Python is fun"
words = sentence.split(" ")
print(words)  # ['Python', 'is', 'fun']

# Join a list into a string
print("-".join(words))  # "Python-is-fun"
print(" ".join(words))  # "Python is fun"

String Slicing

You can extract parts of a string using slicing. The syntax is string[start:end]:

word = "Python"
print(word[0])      # P — first character
print(word[-1])     # n — last character
print(word[0:3])    # Pyt — characters 0, 1, 2
print(word[2:])     # thon — from index 2 to the end
print(word[:3])     # Pyt — from the start to index 3
print(word[::2])    # Pto — every second character
print(word[::-1])   # nohtyP — reversed

Slicing uses [start:end:step]. The start is included, but the end is not. This is a common source of confusion for beginners.

Numbers and Arithmetic

Python supports all standard math operations:

a = 10
b = 3

print(a + b)    # 13 — addition
print(a - b)    # 7 — subtraction
print(a * b)    # 30 — multiplication
print(a / b)    # 3.3333... — division (always returns float)
print(a // b)   # 3 — floor division (rounds down)
print(a % b)    # 1 — modulo (remainder)
print(a ** b)   # 1000 — power (10 to the power of 3)

Notice that / always returns a float, even when dividing evenly:

print(10 / 2)   # 5.0 (float, not int)
print(10 // 2)  # 5 (int)

Use // when you need an integer result.

Type Conversions

You can convert between types using built-in functions:

# String to number
num = int("42")        # 42
price = float("19.99") # 19.99

# Number to string
text = str(42)         # "42"
text = str(3.14)       # "3.14"

# Float to int (truncates, does not round!)
whole = int(3.9)       # 3 (not 4!)

# Number to bool
print(bool(0))         # False
print(bool(1))         # True
print(bool(-5))        # True

Be careful with int() on floats. It truncates (cuts off the decimal), it does not round. If you want rounding, use round():

print(int(3.9))    # 3 — truncated
print(round(3.9))  # 4 — rounded

Truthy and Falsy Values

In Python, every value is either “truthy” or “falsy.” This matters when you use values in conditions.

Falsy values (evaluate to False):

bool(False)    # False
bool(0)        # False
bool(0.0)      # False
bool("")       # False — empty string
bool(None)     # False
bool([])       # False — empty list
bool({})       # False — empty dict
bool(set())    # False — empty set

Everything else is truthy (evaluates to True):

bool(True)       # True
bool(1)          # True
bool(-1)         # True
bool("hello")    # True — non-empty string
bool([1, 2, 3])  # True — non-empty list

This lets you write clean conditions:

name = ""
if name:
    print(f"Hello, {name}!")
else:
    print("Name is empty.")

Instead of if name != "", you can simply write if name. This is more Pythonic.

Augmented Assignment Operators

Python has shorthand operators for updating variables:

x = 10

x += 5    # Same as x = x + 5 → 15
x -= 3    # Same as x = x - 3 → 12
x *= 2    # Same as x = x * 2 → 24
x //= 4   # Same as x = x // 4 → 6
x **= 2   # Same as x = x ** 2 → 36
x %= 10   # Same as x = x % 10 → 6

These work with strings too:

greeting = "Hello"
greeting += ", World!"  # "Hello, World!"
greeting *= 2           # "Hello, World!Hello, World!"

Constants

Python does not have true constants. By convention, use UPPERCASE names for values that should not change:

MAX_RETRIES = 3
API_URL = "https://api.example.com"
PI = 3.14159

Nothing stops you from changing these values. But the uppercase name signals to other developers: “Do not modify this.”

Multiple Assignment

You can assign multiple variables in one line:

# Assign the same value
x = y = z = 0

# Assign different values
name, age, city = "Alex", 25, "Berlin"

# Swap values (no temp variable needed!)
a, b = 1, 2
a, b = b, a  # Now a=2, b=1

The swap trick is one of Python’s most elegant features. In most languages, you need a temporary variable.

Common Mistakes

Confusing = and ==

= is assignment. == is comparison:

x = 5       # Assigns 5 to x
x == 5      # Checks if x equals 5 (returns True)

Integer vs Float Division

print(7 / 2)   # 3.5 (float division)
print(7 // 2)  # 3 (integer division)

If you expect an integer and use /, you will get a float.

None Is Not 0, False, or ""

value = None
print(value == 0)       # False
print(value == False)   # False
print(value == "")      # False
print(value is None)    # True

Always check None with is, not ==.

Practical Example: User Profile

Let’s combine everything into a practical example:

# User profile with type hints
name: str = "Alex"
age: int = 25
height: float = 1.75
is_student: bool = False
email: str | None = None

# Display profile
print(f"{'Name:':<12} {name}")
print(f"{'Age:':<12} {age}")
print(f"{'Height:':<12} {height:.2f}m")
print(f"{'Student:':<12} {'Yes' if is_student else 'No'}")
print(f"{'Email:':<12} {email or 'Not provided'}")

# Calculate birth year (approximately)
birth_year = 2026 - age
print(f"{'Born:':<12} ~{birth_year}")

Output:

Name:        Alex
Age:         25
Height:      1.75m
Student:     No
Email:       Not provided
Born:        ~2001

This uses variables, type hints, f-strings with alignment, ternary expressions, and the or operator for default values.

Source Code

You can find the code for this tutorial on GitHub:

kemalcodes/python-tutorial — tutorial-03-variables

Run the examples:

python src/py03_variables.py

Run the tests:

python -m pytest tests/test_py03.py -v

What’s Next?

In the next tutorial, we will learn about control flow: if/elif/else, for loops, while loops, and Python’s match/case statement.