โšก DevAscent Academy โ€ข Technical Reference Series

Unit 2: Variables and Data Types

An authoritative deep dive into Python's dynamic type system, memory references, numerical representations, immutable sequences, hash-based collections, and type casting mechanics.

Curriculum Track Python for Systems & AI
Unit Code PY-102 / Module 1
Estimated Read 40 Minutes
Core Concepts Primitives, Sets, Dicts, Casting
๐Ÿ“–

Unit 2 Curriculum Roadmap & Competencies

Data structures and variable bindings are the structural bedrock of all modern software. In this unit, you will master how Python allocates and references objects in heap memory, evaluate primitive scalar types (int, float, complex, bool), leverage immutable vs. mutable sequences (str, list, tuple), harness constant-time lookup collections (set, dict), and inspect types using rigorous runtime validation patterns.

๐Ÿ”ข Numerical & Scalar Types

Master arbitrary precision integers, floating point IEEE 754 precision caveats, complex numbers, and boolean truthiness evaluation.

๐Ÿ—‚๏ธ Sequential Collections

Contrast mutable dynamic arrays (Lists) against fixed memory tuples and immutable text buffers (Strings) with step slicing.

โšก Hash-Based Structures

Demystify mathematical Sets and Key-Value Dictionaries operating with O(1) average lookup and hash-table collision resilience.

๐Ÿ” Inspection & Type Casting

Distinguish between type() and isinstance() inheritance checks, and perform safe explicit conversions across data boundaries.

1

Variables and Constants in Python

In compiled languages like C or Rust, declaring a variable reserves a statically-typed slot of memory on the stack. In Python, everything is an object allocated on the heap. A variable is merely a named pointer (or label) bound to that object.

Memory Reference Model: Tagging vs. Storing
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
user_age = 21
backup_age = user_age        # Both labels point to the integer object 21

user_age โ”€โ”€โ”€โ”€โ”
             โ”œโ”€โ”€> [ Heap Object: int 21 | ref_count: 2 | id: 0x7fa4b1 ]
backup_age โ”€โ”€โ”˜

user_age = 22                # 'user_age' re-binds to a NEW integer object 22
                              # 'backup_age' remains pointing to 21!

Constants in Python

Python does not possess a native const keyword. By universal convention, developers communicate that a value must never be altered using SCREAMING_SNAKE_CASE. In modern Python 3.8+, static type checkers (like Pylance or Mypy) enforce immutability via the Final qualifier:

constants_demo.py
from typing import Final

# Standard PEP 8 Convention
DATABASE_TIMEOUT_MS: Final[int] = 5000
MAX_CONCURRENT_SESSIONS: Final[int] = 100
API_BASE_URL: Final[str] = "https://www.devascentacademy.me/api/v1"

# Static type checkers will flag reassignment as an error!
# DATABASE_TIMEOUT_MS = 3000  <-- Pylance: "Cannot assign to Final name"
๐Ÿ’ก
Production Tip: Multi-Variable Assignment Python supports tuple unpacking for parallel assignment: x, y, z = 10, 20, 30. You can also swap two variables cleanly without an intermediate temporary variable: a, b = b, a!
2

Identifier Naming Rules & Standards (PEP 8)

An identifier is the unique label assigned to variables, functions, classes, and modules. Python enforces strict lexical syntax rules alongside style recommendations:

The 4 Hard Syntax Rules

PEP 8 Professional Style Matrix

Construct Casing Convention Production Example Anti-Pattern to Avoid
Variables & Functions snake_case student_count, fetch_certificate() studentCount, fetchCertificate()
Classes PascalCase (CapWords) PaymentGateway, EnrollmentTracker payment_gateway
Constants SCREAMING_SNAKE_CASE MAX_FILE_SIZE_BYTES max_file_size
Internal / Private Single leading underscore (_name) _jwt_secret (Module internal) Exposing raw secrets publicly
Name Mangling Double leading underscore (__name) __private_ledger (Class private) Accidental subclass collisions
โš ๏ธ
Self-Documenting Code vs. Cryptic Abbreviations Avoid single-letter variables except in localized counters: for i in range(10):. Never use l (lowercase L), O (uppercase O), or I (uppercase I) as isolated variable names, as they are indistinguishable from digits 1 and 0 in various monospaced fonts!
3

Numbers: int, float, and complex

Python provides three built-in numerical data types optimized for both business computing and scientific simulation:

1. Integers (int) โ€” Arbitrary Precision

Unlike C++ or Java where integers overflow at 32 bits (2,147,483,647) or 64 bits, Python 3 integers have unlimited precision! An integer can expand to fill all available system RAM without overflow errors.

integers_demo.py
# Standard decimal integer
active_students = 10450

# Underscores as visual thousands separators (PEP 515)
budget_paise = 1_000_000_00  # Exactly 10,00,000

# Number systems: Binary (0b), Octal (0o), Hexadecimal (0x)
binary_mask = 0b1010    # Decimal 10
hex_color   = 0xFF      # Decimal 255

# Arbitrary precision without overflow: 2 to the 100th power!
massive_num = 2 ** 100
print(f"2^100 = {massive_num}")
Output
2^100 = 1267650600228229401496703205376

2. Floating-Point Numbers (float)

Floats are implemented as IEEE 754 64-bit double-precision numbers. They handle decimals and scientific notation (e.g. 1.5e-4).

๐Ÿšจ
The Floating-Point Binary Rounding Trap Computers store numbers in binary (base-2). Just as 1/3 cannot be represented finitely in decimal (0.3333...), fractions like 0.1 and 0.2 have infinite repeating binary expansions!
0.1 + 0.2 == 0.3 # Returns FALSE (It actually equals 0.30000000000000004)
Production Solution: For financial transactions, use the decimal.Decimal class or store currency as integer paise/cents. For scientific equality, use math.isclose(a, b)!
3.1

Complex Numbers & Numerical Operations

3. Complex Numbers (complex)

Python has native first-class support for complex numbers, widely used in electrical engineering, physics modeling, signal processing, and quantum computing. In Python, the imaginary unit is denoted by j (rather than mathematical i).

complex_demo.py
# Defined as real + imaginary*j
z1 = 3 + 4j
z2 = complex(2, -1)  # 2 - 1j

print(f"Real Part: {z1.real}")          # 3.0
print(f"Imaginary Part: {z1.imag}")     # 4.0
print(f"Conjugate: {z1.conjugate()}")   # (3-4j)
print(f"Magnitude: {abs(z1)}")          # 5.0 (Pythagorean: sqrt(3^2 + 4^2))

Complete Arithmetic Operator Matrix

Operator Name Example Result Notes
+ Addition 10 + 4 14 Promotes to float if any operand is float
- Subtraction 10 - 4 6 Standard negation
* Multiplication 10 * 4 40 Also repeats sequences (e.g. '-' * 10)
/ True Division 10 / 4 2.5 Always returns float, even for 4 / 2 -> 2.0
// Floor Division 10 // 4 2 Rounds down to nearest integer (truncates towards -infinity)
% Modulus (Remainder) 10 % 4 2 Useful for parity checks (num % 2 == 0)
** Exponentiation 2 ** 3 8 Power calculation (equivalent to math.pow())
4

Strings (str): Text Processing & Slicing

In Python 3, strings are immutable sequences of Unicode code points. Because strings are Unicode by default, Python seamlessly handles all global alphabets, accents, and emojis (e.g. ๐Ÿš€, เคนเคฟเค‚เคฆเฅ€, ๆ—ฅๆœฌ่ชž).

๐Ÿ“ Bi-Directional String Indexing Grid: text = "PYTHON"
P Idx: 0 | -6
Y Idx: 1 | -5
T Idx: 2 | -4
H Idx: 3 | -3
O Idx: 4 | -2
N Idx: 5 | -1

Step Slicing: [start:stop:step]

Slicing extracts a substring. The start index is inclusive, while stop is exclusive.

slicing_mastery.py
lang = "DevAscent Academy"

print(lang[0:9])     # 'DevAscent' (Indices 0 to 8)
print(lang[10:])     # 'Academy' (Index 10 through end)
print(lang[:3])      # 'Dev' (First 3 characters)
print(lang[-7:])     # 'Academy' (Negative indexing from right)
print(lang[::2])     # 'DvsetAaey' (Every 2nd character)
print(lang[::-1])    # 'ymedacA tnecsaveD' (Reverse string!)
โŒ
String Immutability Violation: TypeError Strings cannot be altered in-place! Attempting lang[0] = "M" will crash your program with:
TypeError: 'str' object does not support item assignment.
To alter a string, you must construct a new string object via concatenation or .replace().
4.1

Essential String Methods in Production

Python strings come equipped with rich built-in transformation and inspection methods:

Method Description Example Returned Output
.strip() Removes leading and trailing whitespace/newlines "  admin  ".strip() "admin"
.lower() / .upper() Converts casing for normalization "DevAscent".lower() "devascent"
.split(sep) Breaks string into a list of tokens "user@domain.com".split("@") ['user', 'domain.com']
.join(iterable) Concatenates elements with delimiter "-".join(["2026", "10", "14"]) "2026-10-14"
.replace(old, new) Substitutes all occurrences of substring "Python 2".replace("2", "3") "Python 3"
.startswith() / .endswith() Boolean prefix / suffix verification url.startswith("https://") True or False

Raw Strings (r"...") for Paths and RegEx

By default, Python treats backslashes as escape characters (e.g. \n = newline, \t = tab). Prefixing a string with r disables escape sequence parsing, making it essential for Windows file paths and Regular Expressions:

raw_strings.py
# Standard string: \t is parsed as a TAB, breaking the path!
broken_path = "C:\new_folder\test.txt"

# Raw string (r"..."): Backslashes are treated as literal characters
valid_path  = r"C:\new_folder\test.txt"
print(valid_path)  # Output: C:\new_folder\test.txt
5

Boolean Values & Truthy / Falsy Evaluation

The bool data type represents logical truth values: True and False. Under the hood, bool is a direct subclass of int, where True == 1 and False == 0.

Boolean Logical Operators

The Python Truthiness Hierarchy (Truthy vs. Falsy)

In Python, any object can be tested for truth value inside an if or while condition without explicit comparison to True or False:

Category Falsy Values (Evaluates to False) Truthy Values (Evaluates to True)
Constants None, False True
Numbers 0, 0.0, 0j Any non-zero number (e.g. 1, -42, 3.14)
Sequences Empty string "", empty list [], empty tuple () Any populated sequence (e.g. "hello", [0], (False,))
Mappings / Sets Empty dictionary {}, empty set set() Any dictionary or set with at least 1 item
truthy_evaluation.py
enrolled_students = []

# Pythonic idiomatic check: Empty list evaluates to Falsy
if not enrolled_students:
    print("Cohort is currently empty. Open admissions!")

# Short-circuit evaluation: Default fallback pattern
user_display_name = input("Enter alias: ").strip() or "Anonymous Engineer"
print(f"Logged in as: {user_display_name}")
6

Lists (list): Dynamic Mutable Arrays

A List is an ordered, mutable collection that allows duplicate elements and heterogeneous data types. In CPython, lists are implemented as dynamically-sized arrays of contiguous memory pointers.

list_operations.py
# Initializing a heterogeneous list
stack = ["FastAPI", "PostgreSQL", "Docker", 2026]

# 1. Appending to end: O(1) amortized
stack.append("Kubernetes")

# 2. Inserting at index: O(n) due to element shifting
stack.insert(0, "Python 3.12")

# 3. Removing by value
stack.remove(2026)

# 4. Popping by index (defaults to last element): O(1)
last_item = stack.pop()  # Removes 'Kubernetes'

print(f"Current Production Stack: {stack}")
Output
Current Production Stack: ['Python 3.12', 'FastAPI', 'PostgreSQL', 'Docker']

List Memory Allocation: Over-Allocation Growth Pattern

When a list reaches capacity, CPython does not allocate 1 slot at a time (which would make repeated append() calls prohibitively slow). Instead, it over-allocates extra buffer slots according to the growth formula:
new_allocated = (size_t)newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);
This guarantees that appending elements operates with O(1) amortized time complexity.

6.1

List Mutability, Copying & Comprehensions

The Shallow Copy Trap (list.copy() vs. copy.deepcopy())

โš ๏ธ
Assignment Does NOT Copy a List! If you assign b = a, modifying b alters a because both point to the same memory address.
shallow = a.copy() copies the top-level container, but nested lists still share pointers!
For nested multi-dimensional structures, always use import copy; deep = copy.deepcopy(a).

List Comprehensions (Clean, Idiomatic Transformations)

List comprehensions provide an expressive, high-performance syntax for constructing new lists from existing iterables:

list_comprehensions.py
raw_prices_inr = [999, 1499, 2499, 4999, 8999]

# Standard loop vs List Comprehension:
# Syntax: [expression for item in iterable if condition]
discounted = [p * 0.85 for p in raw_prices_inr if p >= 2000]

print(f"Original:   {raw_prices_inr}")
print(f"Discounted: {discounted}")
Output
Original: [999, 1499, 2499, 4999, 8999]
Discounted: [2124.15, 4249.15, 7649.15]
7

Tuples (tuple): Immutable Protected Records

A Tuple is an ordered, immutable sequence. Once created, elements cannot be appended, removed, or replaced in-place.

Why Use Tuples Instead of Lists?

tuples_mastery.py
# 1. Defining a tuple
geo_coordinates = (28.6139, 77.2090)  # New Delhi (Lat, Long)

# 2. Tuple Unpacking
latitude, longitude = geo_coordinates
print(f"Lat: {latitude}, Long: {longitude}")

# 3. CRITICAL TRAP: The Single-Element Tuple
fake_tuple = (42)    # Evaluates to integer 42, NOT a tuple!
real_tuple = (42,)   # Trailing comma is MANDATORY for 1-element tuple!

print(type(fake_tuple))  # <class 'int'>
print(type(real_tuple))  # <class 'tuple'>
๐Ÿ†
Domain Modeling with Named Tuples For structured data records with named fields, use from collections import namedtuple. It produces tuple instances accessible via dot notation (e.g. student.name) while retaining immutable zero-overhead performance!
8

Sets (set): Unique Unordered Hash Collections

A Set is an unordered collection of unique, hashable elements. Sets automatically deduplicate input data and provide lightning-fast O(1) average time complexity membership tests (item in my_set).

sets_demo.py
# Automatic Deduplication
raw_cohort_emails = [
    "shivan@devascent.me", 
    "alex@mit.edu", 
    "shivan@devascent.me",  # Duplicate
    "priya@iitb.ac.in"
]

unique_students = set(raw_cohort_emails)
print(f"Total Unique Students: {len(unique_students)}")

# Fast membership testing
print("alex@mit.edu" in unique_students)  # O(1) Instant Lookup
Output
Total Unique Students: 3
True
๐Ÿšจ
The Empty Set Initialization Trap Writing my_set = {} DOES NOT create an empty set! It creates an empty Dictionary!
To initialize an empty set, you must explicitly call the constructor: my_set = set().
8.1

Mathematical Set Algebra in Python

Python sets provide dedicated algebraic operators modeled directly after mathematical Venn diagrams:

Operation Operator Method Equivalent Venn Diagram Logic
Union A | B A.union(B) All elements present in either A or B
Intersection A & B A.intersection(B) Only elements present in both A and B
Difference A - B A.difference(B) Elements in A that are not present in B
Symmetric Difference A ^ B A.symmetric_difference(B) Elements in either A or B, but NOT in both
set_algebra.py
frontend_skills = {"HTML", "CSS", "JavaScript", "React"}
backend_skills  = {"Python", "FastAPI", "PostgreSQL", "Docker", "JavaScript"}

# Full-stack intersection: Skills shared across both disciplines
shared = frontend_skills & backend_skills
print(f"Shared Skills: {shared}")  # {'JavaScript'}

# Backend-exclusive skills
pure_backend = backend_skills - frontend_skills
print(f"Pure Backend: {pure_backend}")

# Complete tech stack union
full_stack = frontend_skills | backend_skills
print(f"Total Unique Skills: {len(full_stack)}")
9

Dictionaries (dict): Key-Value Hash Maps

A Dictionary is an associative mapping of unique keys to arbitrary value objects. Since Python 3.7, standard dictionaries are guaranteed to preserve their insertion order.

Key Eligibility Rule: The Hashability Requirement

Dictionary keys must be immutable and hashable (implementing the __hash__() protocol). You can use str, int, float, or tuple as keys. You cannot use mutable types like list, set, or another dict as keys!

dict_architecture.py
student_profile = {
    "id": "STU-1049",
    "name": "Aarav Sharma",
    "cohort": 14,
    "skills": ["Python", "SQL", "FastAPI"],
    "is_certified": True,
    "gpa": 9.4
}

# 1. Unsafe Access: Throws KeyError if key does not exist!
name = student_profile["name"]

# 2. Safe Access with .get(): Returns default fallback instead of crashing
scholarship = student_profile.get("scholarship_tier", "Standard Tier")
print(f"Scholarship Status: {scholarship}")

# 3. Adding or updating keys
student_profile["grade"] = "A+"
9.1

Dictionary Iteration & Advanced Patterns

Mastering dictionary iteration patterns is essential for API handling, JSON serialization, and database mappings:

dict_iteration.py
course_enrollments = {
    "Python Production": 120,
    "AI Engineering": 85,
    "Full-Stack Web": 95,
    "Cloud Systems": 60
}

# 1. Iterating Keys and Values simultaneously via .items()
for course, count in course_enrollments.items():
    print(f"Course: {course:<20} | Enrolled: {count:>3}")

# 2. Dictionary Comprehension: Filter and transform
popular_courses = {
    k: v for k, v in course_enrollments.items() if v >= 90
}
print(f"High-Demand Cohorts: {popular_courses}")
Terminal Output
Course: Python Production | Enrolled: 120
Course: AI Engineering | Enrolled: 85
Course: Full-Stack Web | Enrolled: 95
Course: Cloud Systems | Enrolled: 60
High-Demand Cohorts: {'Python Production': 120, 'Full-Stack Web': 95}
โšก
Dictionary Merging Operator (Python 3.9+) You can cleanly merge two dictionaries using the pipe operator: combined = default_config | user_overrides. Any key in user_overrides overwrites the duplicate in default_config cleanly!
10

Type Checking: type() vs. isinstance()

Python provides two primary mechanisms for inspecting object types at runtime. Choosing the right one distinguishes beginner scripts from enterprise-grade code:

Feature type(obj) isinstance(obj, classinfo)
Exact Type Match Yes (Strict equality only: type(x) is int) Yes, but also supports inheritance hierarchies
Subclass / OOP Support NO (Fails to recognize subclasses) YES (Returns True for derived classes)
Multi-Type Check Requires verbose boolean chaining Native tuple support: isinstance(x, (int, float))
Industry Recommendation Avoid for polymorphism Mandatory Production Standard
type_checking_demo.py
# Demonstrating the Subclass Blindness of type()
flag = True

# Remember: bool is a subclass of int!
print(type(flag) == int)       # False (type() is strictly looking for int)
print(isinstance(flag, int))   # True! (Recognizes bool inherits from int)

# Defensive API Input Validation pattern
def calculate_shipping(weight_kg):
    if not isinstance(weight_kg, (int, float)):
        raise TypeError(f"Weight must be numeric, got {type(weight_kg).__name__}")
    if weight_kg <= 0:
        raise ValueError("Weight must be strictly greater than 0 kg")
    return weight_kg * 150.0
11

Type Conversion & Casting (Implicit vs. Explicit)

Type conversion refers to changing an entity of one data type into another. Python categorizes conversions into two distinct paradigms:

1. Implicit Type Conversion (Type Coercion)

Python automatically converts one operand into the wider, more expressive type during mathematical evaluations to avoid data truncation:

implicit_coercion.py
int_val = 10      # <class 'int'>
float_val = 5.5   # <class 'float'>

result = int_val + float_val
print(f"Result: {result} | Type: {type(result)}")
# Result: 15.5 | Type: <class 'float'> (Automatic promotion to float)

2. Explicit Type Conversion (Typecasting)

Performed manually by the software engineer using built-in constructor functions:

Constructor Target Type Input Example Converted Result Exception Condition
int(x) Integer int("1400") 1400 ValueError if string contains non-digits
float(x) Float float("98.5") 98.5 ValueError for malformed text
str(x) String str(2026) "2026" Always succeeds for all valid objects
list(x) List list("ABC") ['A', 'B', 'C'] Fails if input is non-iterable
set(x) Set set([1, 2, 2, 3]) {1, 2, 3} Fails if elements are unhashable
โญ

Master Collection Architecture & Complexity Matrix

Choosing the optimal data structure directly dictates the performance, scalability, and memory footprint of production backend services:

Collection Syntax Ordered? Mutable? Duplicates? Lookup Time Ideal Production Use Case
List [a, b, c] Yes Yes Yes O(n) linear scan Ordered queue, sequential data streams, mutable stacks
Tuple (a, b, c) Yes No (Immutable) Yes O(n) linear scan Fixed configuration records, coordinates, DB rows, dict keys
Set {a, b, c} No Yes No (Unique) O(1) Constant Deduplication, fast membership checks, Venn algebra
Dictionary {k: v} Yes (3.7+) Yes Keys: No
Values: Yes
O(1) Constant JSON payloads, database entity caching, symbol lookups
๐ŸŽ“
Unit 2 Mastery Complete! You have mastered Python's memory reference model, numerical primitives, mutable/immutable sequences, constant-time hash tables, and defensive type casting. Proceed directly to Unit 3: Operators & Control Flow!