Variables & Data Types 📚¶
What You'll Learn
- ✅ What variables are and how to declare them
- ✅ All Python built-in data types with examples
- ✅ Memory allocation and how Python stores data
- ✅ Type conversion (implicit & explicit)
- ✅ Type checking with
type()andisinstance() - ✅ Common mistakes to avoid
📖 Introduction¶
In Python, a variable is a name that refers to a value stored in memory. Unlike C or Java, Python is dynamically typed — you don't need to declare the type of a variable. Python figures it out automatically.
New to Python?
Start with Basics → Complexity Analysis → Data Structures → Algorithms before jumping into practice problems.
Already know Python?
Jump straight to Data Structures or Algorithms depending on what you're revising.
Keep in mind
Every topic includes real code examples, memory diagrams, and practical use cases — read them carefully, don't just skim the code.
Think of it this way
A variable is like a label on a box 📦. The label (variable name) points to whatever is inside the box (value). You can change what's in the box at any time!
graph TD
A[Python Data Types] --> B[Numeric]
A --> C[Sequence]
A --> D[Set]
A --> E[Mapping]
A --> F[Boolean]
A --> G[None]
B --> B1[int - Whole Numbers]
B --> B2[float - Decimals]
B --> B3[complex - Complex Numbers]
C --> C1[str - Text]
C --> C2[list - Mutable Sequence]
C --> C3[tuple - Immutable Sequence]
D --> D1[set - Unique Elements]
D --> D2[frozenset - Immutable Set]
E --> E1[dict - Key-Value Pairs]
F --> F1[bool - True / False]
G --> G1[NoneType - No Value]
🏷️ Variables¶
Declaring Variables¶
Python uses dynamic typing — no need to specify the type.
name = "Alice" # str
age = 25 # int
height = 5.7 # float
is_student = True # bool
nothing = None # NoneType
Output:
Variable Naming Rules¶
Rules
- Must start with a letter or
_(not a digit) - Can contain letters, digits, and underscores
- Case-sensitive:
age≠Age≠AGE - Cannot use Python keywords (
if,for,class, etc.)
Multiple Assignment¶
# Assign same value to multiple variables
x = y = z = 0
print(x, y, z)
# Assign multiple values at once
a, b, c = 10, 20, 30
print(a, b, c)
# Swap values (Pythonic way)
a, b = b, a
print(a, b)
Output:
Python Convention
Use snake_case for variable names: my_variable, student_name, total_marks
🔢 Numeric Types¶
1️⃣ Integer (int)¶
Stores whole numbers — positive, negative, or zero. No size limit in Python!
Real-Life Example
- Age:
25 - Number of students:
50 - Bank balance:
-1500
age = 25
students = 50
negative = -100
big_num = 999_999_999 # Underscore for readability
print(age)
print(students)
print(negative)
print(big_num)
print(type(age))
Output:
Integer in Different Bases
Memory Visualization
Python int (arbitrary precision — grows as needed)
small int (e.g. 25):
┌─────────────────────────────┐
│ ob_refcnt │ ob_type │ ← CPython object header
├─────────────────────────────┤
│ ob_digit[0] = 25 │ ← actual value stored here
└─────────────────────────────┘
Unlike C, Python ints never overflow — they expand automatically!
Practical Example: Simple Calculator
num1 = int(input("Enter first number: "))
num2 = int(input("Enter second number: "))
print(f"\n📊 Results:")
print(f"Sum: {num1 + num2}")
print(f"Difference: {num1 - num2}")
print(f"Product: {num1 * num2}")
print(f"Quotient: {num1 / num2}")
print(f"Floor Div: {num1 // num2}")
print(f"Remainder: {num1 % num2}")
print(f"Power: {num1 ** num2}")
Common Mistake
result = 10 / 3
print(result) # 3.3333... (float, not int!)
result = 10 // 3
print(result) # 3 (floor division → gives int)
/ always returns a float. Use // for integer division.
2️⃣ Float (float)¶
Stores decimal numbers. Follows IEEE 754 double-precision standard (64-bit).
Real-Life Example
- Temperature:
98.6 - Price:
19.99 - Pi:
3.141592653589793
temperature = 98.6
price = 19.99
pi = 3.141592653589793
scientific = 1.5e10 # Scientific notation = 15000000000.0
print(temperature)
print(price)
print(pi)
print(scientific)
print(type(pi))
Output:
Memory Visualization
float (64-bit IEEE 754 double precision)
┌──────┬──────────────┬──────────────────────────────────────────┐
│ Sign │ Exponent │ Mantissa │
├──────┼──────────────┼──────────────────────────────────────────┤
│ 1bit │ 11 bits │ 52 bits │
└──────┴──────────────┴──────────────────────────────────────────┘
↑ ↑ ↑
+/- sign Power of 2 Fractional part
Floating Point Precision
Special Float Values
import math
print(float('inf')) # Infinity
print(float('-inf')) # Negative Infinity
print(float('nan')) # Not a Number
print(math.isinf(float('inf'))) # True
print(math.isnan(float('nan'))) # True
3️⃣ Complex (complex)¶
Stores numbers with a real and imaginary part.
c1 = 3 + 4j
c2 = complex(2, -5)
print(c1) # (3+4j)
print(c2) # (2-5j)
print(c1.real) # 3.0
print(c1.imag) # 4.0
print(abs(c1)) # 5.0 (magnitude: √(3²+4²))
print(c1 + c2) # (5-1j)
print(type(c1)) # <class 'complex'>
Output:
When to Use
Complex numbers are used in signal processing, electrical engineering, and scientific computing.
📝 Text Type¶
4️⃣ String (str)¶
Stores text — an immutable sequence of Unicode characters.
Real-Life Example
- Name:
"Alice" - Message:
"Hello, World!" - Email:
"alice@example.com"
name = "Alice"
greeting = 'Hello, World!'
multiline = """This is
a multiline
string"""
print(name)
print(greeting)
print(multiline)
print(type(name))
Output:
Memory Visualization
str = "Hello"
Index: 0 1 2 3 4
┌─────┬─────┬─────┬─────┬─────┐
Char: │ H │ e │ l │ l │ o │
└─────┴─────┴─────┴─────┴─────┘
Neg idx: -5 -4 -3 -2 -1
Strings are immutable — you cannot change individual characters!
String Operations
Strings are Immutable
📋 Sequence Types¶
5️⃣ List (list)¶
An ordered, mutable collection of items. Can hold mixed types.
fruits = ["apple", "banana", "cherry"]
mixed = [1, "hello", 3.14, True, None]
nested = [[1, 2], [3, 4], [5, 6]]
print(fruits)
print(mixed)
print(fruits[0]) # apple
print(fruits[-1]) # cherry
print(len(fruits)) # 3
print(type(fruits)) # <class 'list'>
Output:
Memory Visualization
fruits = ["apple", "banana", "cherry"]
List object:
┌──────────┬──────────┬──────────┐
│ ref[0] │ ref[1] │ ref[2] │
└────┬─────┴────┬─────┴────┬─────┘
│ │ │
▼ ▼ ▼
"apple" "banana" "cherry"
Lists store references (pointers) to objects, not the objects themselves!
Common List Operations
fruits = ["apple", "banana", "cherry"]
fruits.append("mango") # Add to end
fruits.insert(1, "kiwi") # Insert at index
fruits.remove("banana") # Remove by value
popped = fruits.pop() # Remove & return last
fruits.sort() # Sort in place
fruits.reverse() # Reverse in place
print(fruits)
print(popped)
Output:
6️⃣ Tuple (tuple)¶
An ordered, immutable sequence. Faster than lists.
point = (3, 4)
rgb = (255, 128, 0)
single = (42,) # Single element — note the comma!
empty = ()
print(point)
print(rgb[0]) # 255
print(type(point)) # <class 'tuple'>
# Tuple unpacking
x, y = point
print(f"x={x}, y={y}")
Output:
| Feature | Tuple | List |
|---|---|---|
| Mutable | ❌ No | ✅ Yes |
| Syntax | (1, 2) |
[1, 2] |
| Speed | Faster | Slower |
| Use case | Fixed data | Dynamic data |
| Hashable | ✅ Yes | ❌ No |
When to Use Tuples
Use tuples for data that should never change: coordinates, RGB values, database records, dictionary keys.
Common Mistake
🔣 Set Types¶
7️⃣ Set (set)¶
An unordered collection of unique elements.
Real-Life Example
A set is like a bag where duplicates are automatically removed. Perfect for membership testing and removing duplicates.
fruits = {"apple", "banana", "cherry", "apple"} # duplicate removed
numbers = {1, 2, 3, 4, 5}
empty_set = set() # NOT {} — that creates a dict!
print(fruits) # order not guaranteed
print(len(fruits)) # 3 (not 4)
print("apple" in fruits) # True
print(type(fruits)) # <class 'set'>
Output:
Set Operations
Practical: Remove Duplicates
Output:
🗂️ Mapping Type¶
8️⃣ Dictionary (dict)¶
An unordered collection of key-value pairs. Keys must be unique and hashable.
Real-Life Example
A dictionary is like a phone book 📖 — you look up a name (key) to get a phone number (value).
student = {
"name": "Alice",
"age": 20,
"gpa": 3.8,
"courses": ["Math", "CS", "Physics"]
}
print(student["name"]) # Alice
print(student.get("age")) # 20
print(student.get("grade", "N/A")) # N/A (default if missing)
print(type(student)) # <class 'dict'>
Output:
Memory Visualization
student = {"name": "Alice", "age": 20}
Hash Table:
┌──────────┬──────────────┐
│ Key │ Value │
├──────────┼──────────────┤
│ "name" │ "Alice" │
├──────────┼──────────────┤
│ "age" │ 20 │
└──────────┴──────────────┘
Keys are hashed for O(1) average lookup!
Common Dict Operations
student = {"name": "Alice", "age": 20}
# Add / Update
student["gpa"] = 3.8
student.update({"age": 21, "city": "NY"})
# Remove
del student["city"]
popped = student.pop("gpa")
# Iterate
for key, value in student.items():
print(f"{key}: {value}")
# Keys, Values, Items
print(list(student.keys())) # ['name', 'age']
print(list(student.values())) # ['Alice', 21]
Output:
KeyError
✔️ Boolean Type¶
9️⃣ Boolean (bool)¶
Stores True or False. A subclass of int in Python.
is_raining = True
is_sunny = False
print(is_raining)
print(type(is_raining)) # <class 'bool'>
# bool is a subclass of int
print(int(True)) # 1
print(int(False)) # 0
print(True + True) # 2
Output:
Truthy and Falsy Values
# Practical use
name = ""
if not name:
print("Name is empty!") # This prints
items = [1, 2, 3]
if items:
print("List has items!") # This prints
🚫 None Type¶
🔟 NoneType (None)¶
Represents the absence of a value. Similar to null in other languages.
result = None
name = None
print(result) # None
print(type(result)) # <class 'NoneType'>
# Always use 'is' to check for None
if result is None:
print("No result yet!")
if result is not None:
print("Got a result!")
Output:
Use is, not ==
x = None
print(x == None) # True (works but not recommended)
print(x is None) # True ✅ (correct way)
is checks identity (same object), == checks equality.
Common Use Case
🔄 Type Conversion¶
Implicit Conversion (Automatic)¶
Python automatically converts types when safe to do so.
x = 10 # int
y = 3.14 # float
result = x + y
print(result) # 13.14
print(type(result)) # <class 'float'> ← int promoted to float
Explicit Conversion (Casting)¶
# int()
print(int(3.9)) # 3 (truncates decimal)
print(int("42")) # 42
print(int(True)) # 1
# float()
print(float(10)) # 10.0
print(float("3.14")) # 3.14
# str()
print(str(42)) # "42"
print(str(3.14)) # "3.14"
print(str(True)) # "True"
# bool()
print(bool(0)) # False
print(bool("hello")) # True
# list(), tuple(), set()
print(list("hello")) # ['h', 'e', 'l', 'l', 'o']
print(tuple([1, 2, 3])) # (1, 2, 3)
print(set([1, 2, 2, 3])) # {1, 2, 3}
Output:
Data Loss in Casting
🔍 Type Checking¶
x = 42
name = "Alice"
items = [1, 2, 3]
# type() — returns exact type
print(type(x)) # <class 'int'>
print(type(x) == int) # True
# isinstance() — checks type including subclasses (preferred ✅)
print(isinstance(x, int)) # True
print(isinstance(x, (int, float))) # True (check multiple types)
print(isinstance(True, int)) # True (bool is subclass of int)
Use isinstance() over type()
isinstance() is preferred because it works correctly with inheritance. For example, isinstance(True, int) returns True since bool is a subclass of int.
✅ Quick Reference Summary¶
| Type | Category | Mutable | Example | type() |
|---|---|---|---|---|
int |
Numeric | ❌ | 42, -10, 0 |
<class 'int'> |
float |
Numeric | ❌ | 3.14, -0.5 |
<class 'float'> |
complex |
Numeric | ❌ | 3+4j |
<class 'complex'> |
str |
Sequence | ❌ | "hello" |
<class 'str'> |
list |
Sequence | ✅ | [1, 2, 3] |
<class 'list'> |
tuple |
Sequence | ❌ | (1, 2, 3) |
<class 'tuple'> |
set |
Set | ✅ | {1, 2, 3} |
<class 'set'> |
dict |
Mapping | ✅ | {"a": 1} |
<class 'dict'> |
bool |
Boolean | ❌ | True, False |
<class 'bool'> |
None |
NoneType | ❌ | None |
<class 'NoneType'> |