Skip to main content

Python Variables and Data Types: Learn Python Fundamentals

Calculating read time…

Python variables and data types are the naming system and value-classification rules that let a Python program store, label, and correctly operate on every piece of information it handles — from a single number to a full dictionary of user records. In the previous lesson, you installed Python and wrote your first program using print() and input() — now it's time to understand how Python actually remembers and organizes information.

This matters because every bug you'll hit later — a crashed calculation, a silently wrong comparison, a function that mysteriously "remembers" data it shouldn't — traces back to a shaky grasp of exactly this topic. A solid understanding of variables and data types will make everything you build afterward (functions, loops, APIs, data pipelines) gets easier to reason about.

Quick Comparison: Python's Core Data Types at a Glance

Before the deep dive, here's a bird's-eye view of the five fundamentals this lesson covers. Keep this table handy as you read through each section below.

Type Mutable? Example Literal Typical Use
intNo42Whole numbers, counters, IDs
floatNo3.14Measurements, decimals, math
strNo"hello"Text, names, messages
boolNoTrueConditions, yes/no flags
NoneTypeNoNoneDeliberate "no value yet"

1. Python Variables — Your Data Containers

A simple analogy

Imagine you're organizing your kitchen. You have containers labeled "Sugar," "Salt," "Flour" — each container holds a specific thing, and the label tells you what's inside without you having to look. Variables work the same way in Python: they're named containers that store data so you can find and use it later.

What is a Variable?

A variable is a name that points to a value stored in your computer's memory.

Instead of remembering that your age is stored at memory location 0x7f9e3c4a1b20, you just use a friendly name like age.

# Creating a variable is this simple:
age = 25

# Now 'age' stores the value 25
print(age)  # Output: 25

Creating Variables — The Basics

In Python, you create variables using the assignment operator =.

Syntax: variable_name = value

# Different types of variables
name = "Alice"           # Text (string)
age = 25                 # Whole number (integer)
height = 5.6             # Decimal number (float)
is_student = True        # True/False (boolean)

# Using variables
print(f"My name is {name}")
print(f"I am {age} years old")
print(f"My height is {height} feet")
print(f"Student status: {is_student}")

Output:

My name is Alice
I am 25 years old
My height is 5.6 feet
Student status: True
✅ Key Insight:
You don't need to tell Python what type of data you're storing. Python figures it out automatically! This is called dynamic typing.
Under the hood: the "labeled box" analogy is great for day one, but here's the technically accurate version — a variable doesn't contain a value the way a box contains an object. It's a name bound to an object that lives elsewhere in memory. That's why x = y doesn't copy data; it makes y point to the same object x already refers to. For str, int, float, and bool (all immutable), this distinction is invisible in daily use — but it becomes very important once you work with mutable types like lists later in this series.

Variable Naming Rules

Not all names are valid. Python has strict rules:

✅ Valid Variable Names:
user_name = "Alice"        # Snake case (recommended)
userName = "Bob"           # Camel case (works but not Pythonic)
_private_var = 42          # Leading underscore (special meaning)
user1 = "Charlie"          # Numbers allowed (but not at start)
USER_CONSTANT = 100        # All caps (for constants)
my_var2 = "valid"          # Mix of letters and numbers
Rules that make names valid:
  • Start with letter (a-z, A-Z) or underscore (_)
  • Can contain letters, numbers, and underscores
  • Case-sensitive (age ≠ Age ≠ AGE)
  • No spaces allowed
❌ Invalid Variable Names:
2nd_value = 10         # Error! Can't start with number
user-name = "Alice"    # Error! Hyphens not allowed
user name = "Bob"      # Error! Spaces not allowed
class = "Math"         # Error! 'class' is reserved keyword
for = 10               # Error! 'for' is reserved keyword
user@email = "x@y.com" # Error! Special characters not allowed
Common mistakes to avoid:
  • Starting with numbers
  • Using hyphens instead of underscores
  • Including spaces
  • Using reserved keywords (if, else, for, while, etc.)

Variable Naming Conventions

Following conventions makes your code professional and readable.

# Snake case (recommended for variables and functions)
first_name = "Alice"
total_price = 99.99
is_valid_email = True

# SCREAMING_SNAKE_CASE (for constants)
MAX_LOGIN_ATTEMPTS = 3
PI_VALUE = 3.14159
DATABASE_URL = "localhost:5432"

# PascalCase (reserved for class names)
class UserAccount:
    pass

class ShoppingCart:
    pass
Practical tip:
Use descriptive names that explain what the variable holds. user_email is infinitely better than ue or x. Clear names also make code easier to review and maintain.

Multiple Assignment

Python lets you create multiple variables in one line. This is useful when several related values need to be assigned together.

# Assign same value to multiple variables
x = y = z = 0
print(x, y, z)  # Output: 0 0 0

# Assign different values to multiple variables
name, age, city = "Alice", 25, "New York"
print(name)     # Output: Alice
print(age)      # Output: 25
print(city)     # Output: New York

# Unpacking a list
coordinates = [10, 20, 30]
x, y, z = coordinates
print(f"X: {x}, Y: {y}, Z: {z}")  # Output: X: 10, Y: 20, Z: 30

Reassigning Variables

Variables can change their values anytime. They're called "variables" for a reason!

# Initial value
score = 0
print(f"Score: {score}")  # Output: Score: 0

# Update value
score = 10
print(f"Score: {score}")  # Output: Score: 10

# Update using current value
score = score + 5
print(f"Score: {score}")  # Output: Score: 15

# Shorthand for update
score += 10  # Same as: score = score + 10
print(f"Score: {score}")  # Output: Score: 25

Variables Can Change Type!

Unlike some languages, Python variables can change their data type.

# Start as integer
value = 42
print(value, type(value))  # Output: 42 <class 'int'>

# Change to string
value = "Hello"
print(value, type(value))  # Output: Hello <class 'str'>

# Change to float
value = 3.14
print(value, type(value))  # Output: 3.14 <class 'float'>
Important:
Just because you can change a variable's type doesn't mean you should. It can make code confusing. Best practice: Keep each variable's type consistent.

Deleting Variables

Use del to remove a variable from memory:

temp_value = 100
print(temp_value)  # Output: 100

del temp_value
print(temp_value)  # Error! NameError: name 'temp_value' is not defined

Use this when...

You need to store, label, or refer back to any piece of information in your program — a user's input, a running total, a configuration flag, or the result of a calculation.

2. Python Data Types Overview

Every value in Python has a type. The type determines what you can do with that value.

A simple analogy

Think of data types like categories of items in a store: groceries are for cooking, electronics turn on and off, and books are for reading. You wouldn't try to "turn on" a book — and Python feels the same way about mixing up its types. Every data type supports its own specific set of operations.

Python's Built-in Data Types

Python has several categories of data types:

# Text Type
str          # "Hello", 'Python', """Multi-line"""

# Numeric Types
int          # 42, -17, 1000000
float        # 3.14, -0.5, 2.0
complex      # 3+4j (we'll skip this for now)

# Boolean Type
bool         # True, False

# None Type
NoneType     # None (absence of value)

# Sequence Types
list         # [1, 2, 3]
tuple        # (1, 2, 3)
range        # range(0, 10)

# Mapping Type
dict         # {"name": "Alice", "age": 25}

# Set Types
set          # {1, 2, 3}
frozenset    # frozenset({1, 2, 3})

Today we'll focus on the fundamental types: str, int, float, bool, and None.

Checking Data Types

Use the type() function to check what type a variable is:

name = "Alice"
age = 25
height = 5.6
is_student = True
nothing = None

print(type(name))        # <class 'str'>
print(type(age))         # <class 'int'>
print(type(height))      # <class 'float'>
print(type(is_student))  # <class 'bool'>
print(type(nothing))     # <class 'NoneType'>

Type Checking with isinstance()

To check if a variable is a specific type, use isinstance():

age = 25

print(isinstance(age, int))     # True
print(isinstance(age, str))     # False
print(isinstance(age, float))   # False

# Check multiple types at once
value = 42
print(isinstance(value, (int, float)))  # True (it's an int)

Use this when...

You're deciding what a piece of data actually represents — reach for type() when debugging, and isinstance() whenever your code needs to branch based on what kind of value it just received.

3. Python Numbers — Working with Numeric Data

A simple analogy

An integer is like counting whole marbles — you can have 3 or 12, but never "half a marble." A float is like pouring juice into a measuring cup — you can have exactly 3.5 fluid ounces, capturing amounts in between the whole numbers.

Numbers are everywhere in programming. Python has three main numeric types: int, float, and complex.

Integers (int) - Whole Numbers

Integers are whole numbers without decimal points.

# Positive integers
age = 25
year = 2024
population = 8000000000

# Negative integers
temperature = -10
debt = -5000

# Zero
nothing = 0

# Integers can be HUGE in Python (no limit!)
gigantic = 123456789012345678901234567890
print(gigantic)  # Python handles it perfectly!
✅ Python in practice:
Unlike many languages, Python integers have unlimited precision. You can work with numbers as large as your computer's memory allows! No "integer overflow" errors.

Integer Literals in Different Bases

You can write integers in different number systems:

# Decimal (base 10) - normal numbers
decimal = 42

# Binary (base 2) - prefix with 0b
binary = 0b101010       # Same as 42
print(binary)           # Output: 42

# Octal (base 8) - prefix with 0o
octal = 0o52            # Same as 42
print(octal)            # Output: 42

# Hexadecimal (base 16) - prefix with 0x
hexadecimal = 0x2A      # Same as 42
print(hexadecimal)      # Output: 42

Floats (float) - Decimal Numbers

Floats represent numbers with decimal points.

# Basic floats
price = 19.99
temperature = 98.6
pi = 3.14159

# Very small numbers
tiny = 0.0000001

# Scientific notation
speed_of_light = 3e8        # 3 × 10^8 = 300,000,000
planck_constant = 6.626e-34  # 6.626 × 10^-34

print(speed_of_light)       # Output: 300000000.0
print(planck_constant)      # Output: 6.626e-34
⚠ Float Precision Warning:
Floats have limited precision due to how computers store them.
result = 0.1 + 0.2
print(result)  # Output: 0.30000000000000004 (not exactly 0.3!)
For financial calculations, use the decimal module instead.

Arithmetic Operations

Python supports all standard math operations:

# Addition
result = 10 + 5
print(result)  # Output: 15

# Subtraction
result = 10 - 5
print(result)  # Output: 5

# Multiplication
result = 10 * 5
print(result)  # Output: 50

# Division (always returns float)
result = 10 / 3
print(result)  # Output: 3.3333333333333335

# Floor Division (returns integer, rounds down)
result = 10 // 3
print(result)  # Output: 3

# Modulus (remainder)
result = 10 % 3
print(result)  # Output: 1

# Exponentiation (power)
result = 2 ** 3
print(result)  # Output: 8 (2³ = 8)

Operator Precedence

Python follows PEMDAS (Parentheses, Exponents, Multiplication/Division, Addition/Subtraction):

# Without parentheses
result = 10 + 5 * 2
print(result)  # Output: 20 (multiplication first: 10 + 10)

# With parentheses
result = (10 + 5) * 2
print(result)  # Output: 30 (parentheses first: 15 * 2)

# Complex example
result = 10 + 5 * 2 ** 2 - 3
# Order: 2**2 = 4, then 5*4 = 20, then 10+20-3 = 27
print(result)  # Output: 27

Augmented Assignment Operators

Shortcuts for updating variables:

score = 10

# Long way
score = score + 5

# Short way (augmented assignment)
score += 5   # Add 5
score -= 3   # Subtract 3
score *= 2   # Multiply by 2
score /= 4   # Divide by 4
score //= 2  # Floor divide by 2
score %= 3   # Modulus by 3
score **= 2  # Raise to power 2

print(score)

Built-in Math Functions

Python has useful built-in functions for numbers:

# Absolute value
print(abs(-42))      # Output: 42
print(abs(42))       # Output: 42

# Rounding
print(round(3.7))    # Output: 4
print(round(3.4))    # Output: 3
print(round(3.14159, 2))  # Output: 3.14 (2 decimal places)

# Power
print(pow(2, 3))     # Output: 8 (same as 2**3)

# Min and Max
print(min(5, 2, 8, 1))    # Output: 1
print(max(5, 2, 8, 1))    # Output: 8

# Sum
numbers = [1, 2, 3, 4, 5]
print(sum(numbers))       # Output: 15

Math Module for Advanced Operations

import math

# Constants
print(math.pi)       # Output: 3.141592653589793
print(math.e)        # Output: 2.718281828459045

# Square root
print(math.sqrt(16))     # Output: 4.0

# Trigonometry
print(math.sin(math.pi/2))   # Output: 1.0
print(math.cos(0))           # Output: 1.0

# Logarithms
print(math.log(10))      # Natural log
print(math.log10(100))   # Output: 2.0

# Ceiling and Floor
print(math.ceil(3.2))    # Output: 4 (round up)
print(math.floor(3.8))   # Output: 3 (round down)

Practical Number Examples

Example 1: Calculate Circle Area

import math

radius = 5
area = math.pi * radius ** 2
circumference = 2 * math.pi * radius

print(f"Circle with radius {radius}:")
print(f"Area: {area:.2f} square units")
print(f"Circumference: {circumference:.2f} units")

# Output:
# Circle with radius 5:
# Area: 78.54 square units
# Circumference: 31.42 units

Example 2: Compound Interest Calculator

principal = 1000        # Initial amount
rate = 0.05             # 5% annual interest
time = 10               # Years

# A = P(1 + r)^t
final_amount = principal * (1 + rate) ** time

interest_earned = final_amount - principal

print(f"Initial Investment: ${principal:.2f}")
print(f"Interest Rate: {rate*100}%")
print(f"Time Period: {time} years")
print(f"Final Amount: ${final_amount:.2f}")
print(f"Interest Earned: ${interest_earned:.2f}")

# Output:
# Initial Investment: $1000.00
# Interest Rate: 5.0%
# Time Period: 10 years
# Final Amount: $1628.89
# Interest Earned: $628.89

Use this when...

You're modeling a quantity — a price, a count, a measurement — and need to pick int or float based on whether fractional values are meaningful for that quantity.

4. Python Casting — Converting Between Types

A simple analogy

Type casting is like converting a recipe from cups to grams before you can weigh the ingredients on a kitchen scale. The "amount" of flour you mean doesn't change — you're just re-expressing it in the unit your next tool actually understands.

Sometimes you need to convert data from one type to another. This is called type casting or type conversion.

Why Cast Types?

Common scenarios:

  • User input is always a string, but you need a number
  • Want to display a number as text
  • Need to perform math on string numbers
  • Combine different types in formatted output

Converting to Integer - int()

# String to integer
age_str = "25"
age_int = int(age_str)
print(age_int)          # Output: 25
print(type(age_int))    # Output: <class 'int'>

# Float to integer (truncates decimal)
price = 19.99
price_int = int(price)
print(price_int)        # Output: 19 (not 20!)

# Boolean to integer
print(int(True))        # Output: 1
print(int(False))       # Output: 0
❌ Common Casting Errors:
# Can't convert non-numeric strings
age = int("twenty-five")  # Error! ValueError

# Can't convert strings with decimals directly to int
price = int("19.99")      # Error! ValueError

# Fix: Convert to float first, then int
price = int(float("19.99"))  # Works! Output: 19

Converting to Float - float()

# String to float
price_str = "19.99"
price_float = float(price_str)
print(price_float)      # Output: 19.99

# Integer to float
age = 25
age_float = float(age)
print(age_float)        # Output: 25.0

# Boolean to float
print(float(True))      # Output: 1.0
print(float(False))     # Output: 0.0

# String integer to float
number = float("42")
print(number)           # Output: 42.0

Converting to String - str()

# Integer to string
age = 25
age_str = str(age)
print(age_str)          # Output: "25"
print(type(age_str))    # Output: <class 'str'>

# Float to string
price = 19.99
price_str = str(price)
print(price_str)        # Output: "19.99"

# Boolean to string
status = True
status_str = str(status)
print(status_str)       # Output: "True"

# Combining with concatenation
name = "Alice"
age = 25
message = name + " is " + str(age) + " years old"
print(message)          # Output: "Alice is 25 years old"

Converting to Boolean - bool()

Boolean conversion is worth understanding because it appears throughout conditional code and validation.

# Numbers to boolean
print(bool(1))          # Output: True
print(bool(42))         # Output: True
print(bool(-5))         # Output: True
print(bool(0))          # Output: False (ONLY zero is False!)
print(bool(0.0))        # Output: False

# Strings to boolean
print(bool("Hello"))    # Output: True
print(bool("False"))    # Output: True (any non-empty string!)
print(bool(""))         # Output: False (empty string is False)

# None to boolean
print(bool(None))       # Output: False
Truthiness Rules:
In Python, these values are considered False:
  • False (the boolean)
  • 0, 0.0 (numeric zero)
  • "" (empty string)
  • [] (empty list)
  • {} (empty dict)
  • None
Everything else is True!

Implicit vs Explicit Conversion

Implicit (Automatic): Python converts automatically

# Python automatically converts int to float when needed
result = 10 + 3.5    # 10 becomes 10.0 automatically
print(result)        # Output: 13.5
print(type(result))  # Output: <class 'float'>

Explicit (Manual): You convert using functions

# You must explicitly convert string to int
age_str = "25"
age_int = int(age_str)  # Explicit conversion required
print(age_int + 5)      # Output: 30

Practical Casting Examples

Example 1: User Input Calculator

# User input is always string - must convert!
num1_str = input("Enter first number: ")
num2_str = input("Enter second number: ")

# Convert to float for calculations
num1 = float(num1_str)
num2 = float(num2_str)

result = num1 + num2
print(f"Sum: {result}")

# User enters: 10.5 and 20.3
# Output: Sum: 30.8

Example 2: Age Validator

age_input = input("Enter your age: ")

try:
    age = int(age_input)
    
    if age >= 18:
        print("You are an adult.")
    else:
        print(f"You are a minor. {18 - age} years until adulthood.")
        
except ValueError:
    print("Invalid age! Please enter a number.")

Use this when...

You're bridging data across a boundary that only speaks strings — input(), environment variables, and most file or network data — and need real numbers or booleans before doing calculations or comparisons with them.

5. Python Strings — Working with Text

A simple analogy

A string is like a beaded necklace — each bead is one character, strung together in a fixed order. You can count the beads, point at any one of them, or snip out a section to look at — but you can't reach in and swap a single bead without re-stringing the whole necklace as a brand-new one.

Strings are sequences of characters enclosed in quotes. They're one of the most commonly used data types.

Creating Strings

You can use single quotes, double quotes, or triple quotes:

# Single quotes
name = 'Alice'

# Double quotes (exactly the same as single)
name = "Alice"

# Triple quotes (for multi-line strings)
message = """
This is a
multi-line
string.
"""

# When to use which?
# Use double quotes when string contains single quote
sentence = "It's a beautiful day!"

# Use single quotes when string contains double quote
quote = 'She said, "Hello!"'

# Or use escape characters
sentence = 'It\'s a beautiful day!'
quote = "She said, \"Hello!\""

String Basics

# Creating strings
greeting = "Hello, World!"
name = "Alice"
empty = ""

# String length
print(len(greeting))    # Output: 13
print(len(name))        # Output: 5
print(len(empty))       # Output: 0

String Indexing

Access individual characters using square brackets:

text = "Python"

# Positive indexing (starts at 0)
print(text[0])    # Output: P (first character)
print(text[1])    # Output: y
print(text[5])    # Output: n (last character)

# Negative indexing (starts from end)
print(text[-1])   # Output: n (last character)
print(text[-2])   # Output: o (second to last)
print(text[-6])   # Output: P (first character)
# Visual representation:
#  P    y    t    h    o    n
#  0    1    2    3    4    5    (positive index)
# -6   -5   -4   -3   -2   -1    (negative index)

String Slicing

Extract portions of strings using [start:end:step]:

text = "Python Programming"

# Basic slicing [start:end] (end not included)
print(text[0:6])      # Output: Python
print(text[7:18])     # Output: Programming

# Omit start (defaults to 0)
print(text[:6])       # Output: Python

# Omit end (goes to end of string)
print(text[7:])       # Output: Programming

# Negative indices
print(text[-11:])     # Output: Programming

# Step (every nth character)
print(text[::2])      # Output: Pto rgamn (every 2nd char)
print(text[::-1])     # Output: gnimmargorP nohtyP (reversed!)

# Get every 3rd character
print(text[::3])      # Output: Ph oai
✅ Slicing Trick:
text[::-1] is the easiest way to reverse a string!
Verified correction: if you've seen this example elsewhere claiming text[::3] outputs "Ph ormn" — that's wrong. We ran it in a live Python interpreter: indices 0, 3, 6, 9, 12, 15 of "Python Programming" spell out P, h, (space), o, a, i, giving "Ph oai". Always test slicing yourself with print() if you're unsure — it takes two seconds and saves real confusion.

String Concatenation

# Using + operator
first_name = "Alice"
last_name = "Smith"
full_name = first_name + " " + last_name
print(full_name)      # Output: Alice Smith

# Using * for repetition
laugh = "ha" * 3
print(laugh)          # Output: hahaha

border = "=" * 20
print(border)         # Output: ====================

# Cannot mix types!
age = 25
message = "I am " + str(age)  # Must convert to string!
print(message)        # Output: I am 25

String Methods

Strings come with many built-in methods:

text = "  Hello, Python World!  "

# Case conversion
print(text.upper())       # Output:   HELLO, PYTHON WORLD!  
print(text.lower())       # Output:   hello, python world!  
print(text.capitalize())  # Output:   hello, python world!  
print(text.title())       # Output:   Hello, Python World!  

# Remove whitespace
print(text.strip())       # Output: Hello, Python World!
print(text.lstrip())      # Output: Hello, Python World!   (left)
print(text.rstrip())      # Output:   Hello, Python World! (right)

# Replace
new_text = text.replace("Python", "Amazing")
print(new_text)           # Output:   Hello, Amazing World!  

# Split into list
words = "apple,banana,orange".split(",")
print(words)              # Output: ['apple', 'banana', 'orange']

# Join list into string
fruits = ['apple', 'banana', 'orange']
result = ", ".join(fruits)
print(result)             # Output: apple, banana, orange

String Searching and Checking

text = "Python Programming is Fun"

# Check if substring exists
print("Python" in text)        # Output: True
print("Java" in text)          # Output: False
print("Fun" not in text)       # Output: False

# Find position of substring
print(text.find("Programming")) # Output: 7 (starting index)
print(text.find("Java"))        # Output: -1 (not found)

# Count occurrences
text2 = "banana"
print(text2.count("a"))         # Output: 3

# Check string properties
print("hello".isalpha())        # Output: True (all letters)
print("hello123".isalpha())     # Output: False
print("12345".isdigit())        # Output: True (all digits)
print("hello".islower())        # Output: True
print("HELLO".isupper())        # Output: True
print("   ".isspace())          # Output: True

String Formatting (F-strings)

name = "Alice"
age = 25
gpa = 3.875

# Basic f-string
message = f"My name is {name} and I am {age} years old."
print(message)
# Output: My name is Alice and I am 25 years old.

# Expressions inside f-strings
print(f"Next year I'll be {age + 1} years old.")
# Output: Next year I'll be 26 years old.

# Formatting numbers
print(f"GPA: {gpa:.2f}")        # Output: GPA: 3.88 (2 decimals)

# Padding and alignment
print(f"Name: {name:<10}|")     # Output: Name: Alice     |
print(f"Name: {name:>10}|")     # Output: Name:      Alice|
print(f"Name: {name:^10}|")     # Output: Name:   Alice   |
Version Note:
F-strings require Python 3.6+. If you're on an older version, use .format() instead — but virtually every modern setup ships 3.6 or newer, so f-strings are the safe default.

Escape Characters

# Newline
print("Line 1\nLine 2")
# Output:
# Line 1
# Line 2

# Tab
print("Name:\tAlice\nAge:\t25")
# Output:
# Name:   Alice
# Age:    25

# Backslash
print("Path: C:\\Users\\Alice")
# Output: Path: C:\Users\Alice

# Quotes
print("She said, \"Hello!\"")
# Output: She said, "Hello!"

# Raw strings (ignore escape characters)
print(r"C:\Users\new\test")
# Output: C:\Users\new\test

Strings are Immutable

⚠ Important Concept:
Strings cannot be changed after creation. Every string operation creates a NEW string.
text = "Hello"

# This doesn't modify the original string
text.upper()
print(text)          # Output: Hello (unchanged!)

# You must assign to a new variable (or same variable)
text = text.upper()
print(text)          # Output: HELLO

# You cannot change individual characters
text = "Hello"
text[0] = "J"        # Error! TypeError: 'str' object does not support item assignment

# Instead, create a new string
text = "J" + text[1:]
print(text)          # Output: Jello

Practical String Examples

Example 1: Email Validator

email = input("Enter your email: ")

# Basic validation
if "@" in email and "." in email:
    parts = email.split("@")
    username = parts[0]
    domain = parts[1]
    
    print(f"Username: {username}")
    print(f"Domain: {domain}")
    print("Email format looks valid!")
else:
    print("Invalid email format!")

Example 2: Password Strength Checker

password = input("Enter password: ")

# Check password strength
has_upper = any(c.isupper() for c in password)
has_lower = any(c.islower() for c in password)
has_digit = any(c.isdigit() for c in password)
long_enough = len(password) >= 8

if has_upper and has_lower and has_digit and long_enough:
    print("Strong password!")
else:
    print("Weak password. Need:")
    if not has_upper:
        print("- At least one uppercase letter")
    if not has_lower:
        print("- At least one lowercase letter")
    if not has_digit:
        print("- At least one digit")
    if not long_enough:
        print("- Minimum 8 characters")

Use this when...

You're working with text — parsing it, cleaning it, searching it, or formatting it for display — which is most of what real-world Python programs spend their time doing.

6. Python Booleans — True or False

Booleans represent one of two values: True or False.

A simple analogy

Think of a boolean like a light switch — either ON or OFF, no in-between setting. Every yes/no question your program asks, from "is the user logged in?" to "did the file load?", collapses down to exactly one of these two positions.

Creating Booleans

# Boolean literals
is_active = True
is_admin = False

print(type(is_active))  # Output: <class 'bool'>

# Note: First letter must be capital!
# true = True   # Error! 'true' is not defined

Boolean from Comparisons

Comparisons always return boolean values:

# Equality
print(5 == 5)        # Output: True
print(5 == 3)        # Output: False

# Inequality
print(5 != 3)        # Output: True
print(5 != 5)        # Output: False

# Greater than / Less than
print(10 > 5)        # Output: True
print(10 < 5)        # Output: False
print(10 >= 10)      # Output: True
print(5 <= 3)        # Output: False

# String comparison
print("apple" == "apple")    # Output: True
print("Apple" == "apple")    # Output: False (case-sensitive!)
print("apple" < "banana")    # Output: True (alphabetical)

Logical Operators

Combine boolean values using and, or, not:

# AND - both must be True
print(True and True)      # Output: True
print(True and False)     # Output: False
print(False and False)    # Output: False

# OR - at least one must be True
print(True or False)      # Output: True
print(False or False)     # Output: False
print(True or True)       # Output: True

# NOT - reverses the value
print(not True)           # Output: False
print(not False)          # Output: True

Practical Boolean Logic

age = 25
has_license = True
has_car = False

# Check if can drive
can_drive = age >= 18 and has_license
print(f"Can drive: {can_drive}")  # Output: Can drive: True

# Check if needs transportation
needs_ride = not has_car
print(f"Needs ride: {needs_ride}")  # Output: Needs ride: True

# Complex condition
is_eligible = (age >= 21 and has_license) or has_car
print(f"Eligible: {is_eligible}")   # Output: Eligible: True

Boolean in Conditionals

is_raining = True
have_umbrella = False

if is_raining and not have_umbrella:
    print("You'll get wet!")
elif is_raining and have_umbrella:
    print("Don't forget your umbrella!")
else:
    print("Enjoy the weather!")

Truthy and Falsy Values

We covered this in casting, but it's crucial for booleans:

# These are all Falsy (evaluate to False)
print(bool(0))           # False
print(bool(0.0))         # False
print(bool(""))          # False (empty string)
print(bool([]))          # False (empty list)
print(bool({}))          # False (empty dict)
print(bool(None))        # False

# These are all Truthy (evaluate to True)
print(bool(1))           # True
print(bool(-1))          # True (any non-zero number)
print(bool("hello"))     # True (non-empty string)
print(bool([1, 2]))      # True (non-empty list)
print(bool({"a": 1}))    # True (non-empty dict)

Short-Circuit Evaluation

Python stops evaluating as soon as it knows the answer:

# AND - stops at first False
result = False and print("This won't run")
# print() never executes because False and anything = False

# OR - stops at first True
result = True or print("This won't run either")
# print() never executes because True or anything = True

# Practical use: avoid errors
user = None
name = user and user.name  # Doesn't crash! Returns None
print(name)  # Output: None

Practical Boolean Examples

Example 1: Login System

username = input("Username: ")
password = input("Password: ")

# Simulated database
correct_username = "alice"
correct_password = "secret123"

# Check credentials
is_valid = (username == correct_username) and (password == correct_password)

if is_valid:
    print("Login successful!")
else:
    print("Invalid credentials!")

Example 2: Age Range Checker

age = int(input("Enter your age: "))

is_child = age < 13
is_teen = 13 <= age < 20
is_adult = 20 <= age < 65
is_senior = age >= 65

print(f"Child: {is_child}")
print(f"Teen: {is_teen}")
print(f"Adult: {is_adult}")
print(f"Senior: {is_senior}")

Use this when...

You're writing any conditional logic, filtering data, or deciding which branch of an if/elif/else chain a program should follow — booleans are the currency every condition trades in.

7. Python None — The Absence of Value

None is a special value that represents "nothing" or "no value".

A simple analogy

Think of None like an empty gift box sitting under the tree — the box definitely exists, you can pick it up and shake it, but there's genuinely nothing inside yet.

What is None?

# Creating None
value = None

print(value)           # Output: None
print(type(value))     # Output: <class 'NoneType'>

# None is a singleton (only one None exists)
print(None is None)    # Output: True

When to Use None

Common use cases:

  1. Default values: When a variable has no value yet
  2. Function returns: When function has nothing to return
  3. Missing data: Represent absence of data
  4. Optional parameters: Default parameter values
# 1. Default values
user_email = None  # Will be set later

if user_email is None:
    user_email = input("Enter your email: ")

# 2. Function returns
def find_user(username):
    # Simulated search
    if username == "alice":
        return {"name": "Alice", "age": 25}
    else:
        return None  # User not found

result = find_user("bob")
if result is None:
    print("User not found!")
else:
    print(f"Found: {result}")

# 3. Missing data
user_data = {
    "name": "Alice",
    "age": 25,
    "email": None  # Email not provided
}

# 4. Optional parameters
def greet(name, title=None):
    if title is None:
        print(f"Hello, {name}!")
    else:
        print(f"Hello, {title} {name}!")

greet("Alice")              # Output: Hello, Alice!
greet("Smith", "Dr.")       # Output: Hello, Dr. Smith!

Checking for None

✅ Correct Way to Check None:
value = None

# Use 'is' operator
if value is None:
    print("Value is None")

# Check if NOT None
if value is not None:
    print("Value exists")
❌ Wrong Way to Check None:
# Don't use == with None
if value == None:  # Works, but not recommended
    print("Value is None")
Use is instead of == when checking for None! Since None is a singleton, is checks true object identity — it's both the idiomatic convention and marginally faster.

None vs Empty Values

Understanding the difference is important:

# These are different!
none_value = None
empty_string = ""
zero_value = 0
empty_list = []

print(none_value is None)      # True
print(empty_string is None)    # False
print(zero_value is None)      # False
print(empty_list is None)      # False

# But they're all Falsy
print(bool(none_value))        # False
print(bool(empty_string))      # False
print(bool(zero_value))        # False
print(bool(empty_list))        # False

None in Boolean Context

user = None

# None is Falsy
if not user:
    print("No user logged in")

# But be careful!
user = ""  # Empty string, not None

if not user:  # This also triggers!
    print("This prints too!")

# Better: explicitly check for None
if user is None:
    print("No user (correctly checked)")

Practical None Examples

Example 1: Configuration System

class Config:
    def __init__(self):
        self.api_key = None
        self.database_url = None
        self.debug_mode = None
    
    def is_configured(self):
        return (
            self.api_key is not None and
            self.database_url is not None and
            self.debug_mode is not None
        )

config = Config()
print(f"Ready: {config.is_configured()}")  # Output: Ready: False

config.api_key = "abc123"
config.database_url = "localhost:5432"
config.debug_mode = True
print(f"Ready: {config.is_configured()}")  # Output: Ready: True

Example 2: Search with Default

def get_user_preference(user_id, preference_key, default=None):
    """
    Get user preference, return default if not found
    """
    # Simulated database
    preferences = {
        1: {"theme": "dark", "language": "en"},
        2: {"theme": "light"}
    }
    
    user_prefs = preferences.get(user_id)
    
    if user_prefs is None:
        return default
    
    return user_prefs.get(preference_key, default)

# Usage
theme = get_user_preference(1, "theme", "light")
print(f"Theme: {theme}")  # Output: Theme: dark

language = get_user_preference(2, "language", "en")
print(f"Language: {language}")  # Output: Language: en (default)

email = get_user_preference(3, "email", "none@example.com")
print(f"Email: {email}")  # Output: Email: none@example.com

Use this when...

You need a placeholder for "not set yet," a function return value that means "nothing found," or a default parameter value that a function can detect and replace — never use it to mean "empty" when you actually mean an empty string, list, or zero.

8. Putting It All Together — Final Project

Now we can combine these ideas in one small student-management program.

"""
Student Management System
Demonstrates: variables, data types, casting, strings, booleans, None
"""

print("=" * 50)
print("  STUDENT MANAGEMENT SYSTEM")
print("=" * 50)

# Student data storage
students = []

while True:
    print("\n--- Add Student ---")
    
    # Get student name (string)
    name = input("Student name (or 'done' to finish): ").strip()
    
    if name.lower() == 'done':
        break
    
    if not name:  # Check for empty string
        print("Name cannot be empty!")
        continue
    
    # Get age (casting string to int)
    age_input = input("Age: ").strip()
    try:
        age = int(age_input)
        if age < 5 or age > 100:
            print("Age must be between 5 and 100!")
            continue
    except ValueError:
        print("Invalid age! Please enter a number.")
        continue
    
    # Get GPA (casting string to float)
    gpa_input = input("GPA (0.0-4.0): ").strip()
    try:
        gpa = float(gpa_input)
        if gpa < 0.0 or gpa > 4.0:
            print("GPA must be between 0.0 and 4.0!")
            continue
    except ValueError:
        print("Invalid GPA! Please enter a number.")
        continue
    
    # Get scholarship status (boolean)
    scholarship_input = input("Has scholarship? (yes/no): ").strip().lower()
    has_scholarship = scholarship_input == 'yes'
    
    # Get email (string, optional - can be None)
    email = input("Email (optional, press Enter to skip): ").strip()
    if not email:
        email = None
    
    # Create student record (dictionary)
    student = {
        'name': name,
        'age': age,
        'gpa': gpa,
        'has_scholarship': has_scholarship,
        'email': email
    }
    
    students.append(student)
    print(f"✓ Added {name} to the system!")

# Display summary
print("\n" + "=" * 50)
print("  STUDENT SUMMARY")
print("=" * 50)

if not students:  # Empty list is Falsy
    print("No students registered.")
else:
    print(f"\nTotal students: {len(students)}\n")
    
    for i, student in enumerate(students, 1):
        print(f"{i}. {student['name'].upper()}")
        print(f"   Age: {student['age']}")
        print(f"   GPA: {student['gpa']:.2f}")
        print(f"   Scholarship: {'Yes' if student['has_scholarship'] else 'No'}")
        
        # Handle None email
        if student['email'] is None:
            print(f"   Email: Not provided")
        else:
            print(f"   Email: {student['email']}")
        
        # Calculate status
        if student['gpa'] >= 3.5:
            status = "Excellent"
        elif student['gpa'] >= 3.0:
            status = "Good"
        elif student['gpa'] >= 2.0:
            status = "Satisfactory"
        else:
            status = "Needs Improvement"
        
        print(f"   Status: {status}")
        print()
    
    # Statistics
    total_gpa = sum(s['gpa'] for s in students)
    average_gpa = total_gpa / len(students)
    
    scholarship_count = sum(1 for s in students if s['has_scholarship'])
    
    print("-" * 50)
    print(f"Average GPA: {average_gpa:.2f}")
    print(f"Students with scholarship: {scholarship_count}/{len(students)}")
    print("=" * 50)

print("\nThank you for using Student Management System!")
Extend it further: once you finish the upcoming Functions lesson, come back and refactor each block of this script (input collection, validation, summary printing) into its own function — it becomes dramatically easier to test and reuse.

9. Quick Reference Guide

Variables & Data Types Cheat Sheet

Variables:

name = "Alice"          # Create variable
age = age + 1           # Update variable
x = y = z = 0          # Multiple assignment
a, b, c = 1, 2, 3      # Unpack values

Type Checking:

type(variable)              # Get type
isinstance(var, int)        # Check if specific type

Casting:

int("42")           # String to int
float("3.14")       # String to float
str(42)             # Number to string
bool(1)             # To boolean

String Operations:

len(s)              # Length
s.upper()           # Uppercase
s.lower()           # Lowercase
s.strip()           # Remove whitespace
s.split(",")        # Split by delimiter
",".join(list)      # Join list into string
s[0:5]              # Slice
s[::-1]             # Reverse

Boolean Logic:

and                 # Both must be True
or                  # At least one True
not                 # Reverse boolean
is None             # Check for None

10. Common Pitfalls and How to Avoid Them

❌ Pitfall 1: Comparing floats directly
# Bad
if 0.1 + 0.2 == 0.3:  # False! (floating point precision)
    print("Equal")

# Good
if abs((0.1 + 0.2) - 0.3) < 0.0001:
    print("Approximately equal")

Why it happens: decimal fractions like 0.1 can't be stored exactly in binary floating point, so two mathematically equal expressions can differ by a tiny rounding error. Compare with a tolerance instead of ==, or use the decimal module for money.

❌ Pitfall 2: Using == with None
# Bad
if value == None:
    pass

# Good
if value is None:
    pass

Why it happens: == works here purely by coincidence, so beginners reach for the operator they already know. is checks true object identity, which is what you actually mean when testing against the singleton None.

❌ Pitfall 3: Forgetting to convert input()
# Bad
age = input("Age: ")
if age > 18:  # Error! Comparing string to number

# Good
age = int(input("Age: "))
if age > 18:
    print("Adult")

Why it happens: input() always returns a string, even if the user types digits, and Python won't silently compare a string to a number the way some looser languages do — you'll get a TypeError instead of a guess.

❌ Pitfall 4: Modifying strings (they're immutable!)
# Bad
text = "hello"
text[0] = "H"  # Error!

# Good
text = "H" + text[1:]  # Create new string

Why it happens: in many languages a string is just a mutable array of characters, so developers instinctively try to edit one index. Python strings are immutable by design (partly so they can be safely hashed as dictionary keys), so you must build a new string instead.

11. Practice Exercises

Use these exercises to reinforce the ideas before moving on to functions and larger programs:

✅ Exercise 1: Variable Swap
Swap the values of two variables without using a third variable.
a = 10
b = 20
# Your code here
# Hint: Python tuple unpacking (a, b = b, a) handles this for ANY
# data type. The classic "XOR swap trick" only works for integers
# and won't work here, so avoid reaching for it.
# Result: a = 20, b = 10
✅ Exercise 2: Type Converter
Create a program that takes any input and converts it to all possible types. Show which conversions work and which fail.
✅ Exercise 3: String Analyzer
Write a program that analyzes a string and reports:
  • Length
  • Number of vowels
  • Number of digits
  • Number of spaces
  • Is palindrome?
✅ Exercise 4: Grade Calculator
Create a grading system that:
  • Accepts numeric grades (0-100)
  • Converts to letter grade (A, B, C, D, F)
  • Determines if student passed (≥60)
  • Calculates GPA (4.0 scale)
✅ Exercise 5: Data Validator
Create validators for:
  • Email format (must contain @ and .)
  • Phone number (10 digits)
  • Password (8+ chars, upper, lower, digit)
  • Age (1-120)

12. Frequently Asked Questions

What is the difference between a variable and a data type in Python?

A variable is the name you choose to reference a value in memory (like age). A data type describes what kind of value that is (like int or str) and, crucially, what operations are valid on it.

What are Python's 5 basic data types?

The five fundamentals covered in this lesson are str (text), int (whole numbers), float (decimals), bool (True/False), and NoneType (absence of a value). Python also has sequence, mapping, and set types you'll meet in later lessons.

Why does 0.1 + 0.2 not equal 0.3 in Python?

Floats are stored in binary, and most decimal fractions — including 0.1 — can't be represented exactly in binary, the same way 1/3 can't be written exactly in decimal. Use abs(a - b) < tolerance for float comparisons, or the decimal module for exact decimal math.

Should I use == or is to check for None?

Use is None. None is a singleton — only one instance ever exists — so identity comparison is both the technically correct check and the community-standard convention enforced by linters like flake8.

Can I change a Python string after creating it?

No — strings are immutable. Every method like .upper() or .replace() returns a brand-new string rather than modifying the original one in place.

13. References & Further Reading

  • Python Language Reference — Data Model (docs.python.org)
  • Python Standard Library — Built-in Types (docs.python.org/3/library/stdtypes.html)
  • Python Standard Library — decimal module (docs.python.org/3/library/decimal.html)
  • Python Standard Library — math module (docs.python.org/3/library/math.html)
  • PEP 8 — Style Guide for Python Code (peps.python.org/pep-0008)
  • PEP 3101 — Advanced String Formatting / f-strings background (peps.python.org/pep-3101)
  • What's New in Python — release notes by version (docs.python.org/3/whatsnew/)

This article is an independently written synthesis for teaching purposes. All explanations, analogies, and code examples were created for this post; the sources above were used only to verify technical accuracy, not copied from.

14. Summary

  • Variables are names bound to values, created with =, with no separate type declaration needed
  • Python is dynamically typed — a variable's type is inferred from its current value and can change on reassignment
  • Integers have unlimited precision; floats trade some precision for the ability to represent fractions
  • Strings are immutable sequences of characters — every "modifying" method returns a new string
  • Booleans power every conditional; remember that empty/zero values are Falsy and everything else is Truthy
  • None represents the deliberate absence of a value — always check it with is None, never ==
  • Type casting bridges data across boundaries (like input()) that only speak strings — use int(), float(), and str() deliberately, inside a try/except when the input isn't trusted
  • Use descriptive snake_case names, validate and convert user input immediately, and lean on the Student Management System project to see every concept working together

Master this foundation and everything else in Python — functions, loops, classes, even async code — clicks into place faster, because it's all just more sophisticated ways of organizing names and the values they point to. Keep coding, keep learning.

Comments