What data types are, why Python cares about them, and how each one shows up in real code you'll write on the job.
You write "5" + 3 expecting the answer 8, but Python throws an error instead. Why? Because "5" is TEXT and 3 is a NUMBER — Python refuses to guess which one you actually meant.
A Data Type tells Python exactly WHAT KIND of value you're working with — a number, text, a true/false answer, or a whole collection of values. Python uses this to decide what operations (+, -, comparisons, loops) are even allowed on that value.
Every single bug you'll debug in your first months as a developer will very often trace back to a data type mismatch — treating text as a number, or expecting a list where you actually got a single value. Understanding data types isn't optional theory; it's the #1 skill that prevents confusing, hard-to-read error messages from ruining your day.
age = 25 name = "Sai" print(type(age)) # <class 'int'> print(type(name)) # <class 'str'>
type(value) tells you exactly what type something is — use it whenever you're unsureYou're calculating someone's age (a whole number) and their average test score (which can have decimals, like 87.5). Python needs to distinguish between these, since dividing whole numbers can behave differently than dividing decimals.
Simple Answer: int is a whole number (no decimal point). float is a number WITH a decimal point, used for anything that needs precision (money, measurements, averages). complex handles numbers with a real and imaginary part — rare in everyday coding, mostly used in scientific/engineering calculations.
age = 25 # int - whole number average_score = 87.5 # float - has a decimal point signal = 3 + 4j # complex - rarely used in everyday code print(type(age)) # <class 'int'> print(type(average_score)) # <class 'float'>
In real data engineering work, choosing int vs float correctly matters — storing money as float can cause tiny rounding errors that add up over millions of transactions (a real, famous class of bugs in finance systems). You'll often deliberately choose specific numeric precision when designing database columns and PySpark schemas for exactly this reason.
You need to display "Welcome, Sai!" on a webpage, combining a fixed greeting with the user's actual name — text needs its own type because you can't "add" letters the same way you add numbers.
Simple Answer: A string is any text, wrapped in quotes (single or double). Strings support their own set of operations — combining (concatenation), repeating, slicing out parts of the text, and searching within it.
name = "Sai" greeting = "Welcome, " + name + "!" # concatenation print(greeting) # Welcome, Sai! print(name.upper()) # SAI print(name[0]) # S (first character) print(len(name)) # 3 (number of characters)
String handling is everywhere — cleaning messy text data from CSVs (extra spaces, wrong casing), building SQL queries dynamically, parsing log files, and formatting reports. Nearly every ETL pipeline you'll build involves cleaning and reshaping strings at some point.
name[0], not name[1]Your program needs to decide: "is this user old enough to register?" The answer can only ever be Yes or No — there's no in-between value that makes sense here.
Simple Answer: A Boolean holds exactly one of two values: True or False. It's what every comparison (>, ==, in) produces, and what every if statement checks.
age = 20 is_adult = age >= 18 # comparison produces a boolean print(is_adult) # True print(type(is_adult)) # <class 'bool'> if is_adult: print("You can register")
Booleans drive EVERY decision your code makes — validation checks, filtering data ("is this row valid?"), controlling loops, and feature flags in production systems. In PySpark, filter conditions like df.filter(col("salary") > 50000) are built entirely on boolean logic underneath.
True, not trueYou need to store the names of 5 students in a class, and later you might need to add a new student, remove one, or check the order they joined in.
Simple Answer: A list is an ordered collection of values, written with square brackets [ ]. Order is remembered, duplicate values are allowed, and you CAN change it after creating it (add, remove, update items) — this is what "mutable" means.
students = ["Sai", "Ravi", "Anu"] students.append("Priya") # add a new student students.remove("Ravi") # remove a student print(students) # ['Sai', 'Anu', 'Priya'] print(students[0]) # Sai (first item, index 0)
Lists are how you'll hold rows of data before loading them into a database, store results from an API call, or collect items during a loop. In data engineering, when you read a CSV with core Python (before even touching Pandas/PySpark), you're often working with a list of dictionaries.
[ ], ordered, allows duplicates, MUTABLE (changeable)forYou're storing a fixed GPS coordinate (latitude, longitude) for a store location. This pair should NEVER accidentally get modified somewhere else in a large codebase — that would corrupt your data.
Simple Answer: A tuple looks like a list, but uses round brackets ( ) and CANNOT be changed after creation — it's "immutable." Use a tuple whenever the data should stay fixed and protected from accidental changes.
store_location = (17.385, 78.4867) # latitude, longitude print(store_location[0]) # 17.385 # store_location[0] = 20.0 -> this would raise an ERROR, tuples can't be changed
Tuples are used for fixed, protected data — function return values that shouldn't be altered, dictionary keys (which must be immutable), and configuration values you want to guarantee never change accidentally in a large codebase.
( ), ordered, allows duplicates, IMMUTABLE (cannot be changed)You need to store a student's details — name, age, department — but looking them up by POSITION ("the 3rd item") is confusing and error-prone. You want to look them up by NAME instead, like "give me the age."
Simple Answer: A dictionary stores data as key-value pairs, written with curly brackets { }. Instead of a numeric position, you look up values using a meaningful KEY — much closer to how real-world data (like a JSON API response) is naturally structured.
student = {
"name": "Sai",
"age": 21,
"department": "Data Engineering"
}
print(student["name"]) # Sai
student["age"] = 22 # update a value using its key
Dictionaries are EXTREMELY common in real work — every JSON API response, every row read from MongoDB, every config file (like your database connection settings) naturally maps to a Python dictionary. If you understand dicts well, working with APIs and NoSQL databases feels immediately familiar.
{ }, key-value pairs, look up by KEY not positionYou have a list of 10,000 customer emails, but many are accidentally repeated. You just want the list of UNIQUE emails, with no duplicates at all.
Simple Answer: A set automatically removes duplicates and stores only unique values, written with curly brackets { } (like a dict, but without key-value pairs). Order is NOT guaranteed — sets care about uniqueness, not sequence.
emails = ["a@x.com", "b@x.com", "a@x.com", "c@x.com"] unique_emails = set(emails) print(unique_emails) # {'a@x.com', 'b@x.com', 'c@x.com'} (order may vary)
Sets are a quick, efficient way to de-duplicate data during cleaning steps, and to quickly check "does this value exist?" — checking membership in a set is much faster than checking membership in a list on large data. You'll use this exact pattern often during data cleaning before loading data into a database.
{ }, unique values only, no guaranteed orderset(my_list){} with a set — that actually creates an empty dictionaryA user hasn't entered their middle name yet. Should that field be an empty string "", the number 0, or something else entirely? None of those really mean "this doesn't exist yet."
Simple Answer: None is Python's way of saying "there is intentionally no value here" — different from an empty string or zero, which ARE actual values. It's Python's version of NULL, which you already know from SQL.
middle_name = None if middle_name is None: print("No middle name provided")
This connects directly to what you already learned about NULL values in SQL — None is Python's equivalent. You'll constantly check for None when handling missing data, optional function arguments, and API responses where a field might genuinely be absent.
is None, not == NoneA user types their age into a web form. Every value from a web form arrives as TEXT (a string) — even though "25" looks like a number, Python still sees it as text until you explicitly convert it.
Simple Answer: Type conversion (also called "casting") means deliberately switching a value from one type to another using functions like int(), float(), or str().
age_text = "25" # this is a STRING, not a number age_number = int(age_text) # now it's an actual int print(age_number + 5) # 30 (works now, would fail on the string version) print(str(100)) # "100" - number converted back to text
This is one of the most common real bugs in data engineering: a CSV column that LOOKS numeric actually gets read as text, and every calculation silently fails or behaves unexpectedly until you explicitly convert it. Recognizing "this data is the wrong type" is often the very first debugging step in a broken pipeline.
int(), float(), str(), bool() convert between typestype() to confirm before you assumeUse this table to quickly recall every type covered today, side by side — great for a last-minute review before a quiz or interview.
| Data Type | Syntax | Mutable? | Example | Common Real-World Use |
|---|---|---|---|---|
| int | 25 |
— | age = 25 |
Counts, IDs, ages, quantities |
| float | 87.5 |
— | score = 87.5 |
Prices, averages, measurements |
| complex | 3+4j |
— | z = 3 + 4j |
Scientific/engineering calculations |
| str | "text" |
No | name = "Sai" |
Names, messages, cleaning text data |
| bool | True / False |
— | is_adult = True |
Conditions, validation, filters |
| list | [ ] |
Yes | names = ["Sai","Anu"] |
Collections you'll add/remove from |
| tuple | ( ) |
No | loc = (17.3, 78.4) |
Fixed values that must stay protected |
| dict | { key: value } |
Yes | {"name":"Sai"} |
JSON/API data, config, records |
| set | { } (no keys) |
Yes | {"a","b","c"} |
Removing duplicates, fast lookups |
| NoneType | None |
— | middle_name = None |
Representing intentionally missing data |
type(value) to checkA fresher in an interview is asked: "You need to store student names — would you use a list, tuple, set, or dictionary?" Without understanding the FEATURE differences between these four, it's just a guess. With them, the right choice becomes obvious based on what the data actually needs.
All four are Python's main ways to hold MULTIPLE values together — the difference is entirely in HOW they behave: do they remember order, can they change, do they allow duplicates, and how do you look values up?
| Feature | List | Tuple | Set | Dictionary |
|---|---|---|---|---|
| Syntax | [ ] |
( ) |
{ } |
{key: value} |
| Ordered? | Yes | Yes | No | Yes (insertion order) |
| Mutable? (changeable) | Yes | No | Yes | Yes |
| Allows Duplicate Values? | Yes | Yes | No | Keys: No · Values: Yes |
| How You Access Items | By position: list[0] |
By position: tup[0] |
No indexing — check membership only | By key: dict["name"] |
| Typical Use Case | A changing collection of items | Fixed, protected values | Removing duplicates, fast lookups | Labeled data (like a JSON record) |
This exact comparison ("list vs tuple vs set vs dict") is one of the most frequently asked Python fresher interview questions — because it tests whether you understand WHY each type exists, not just their syntax. Answering with the right feature (mutability, order, uniqueness) instead of a memorized definition instantly signals real understanding.
Every value in Python has a type, and that type decides what you're allowed to do with it. Numbers (int/float) for math, strings for text, booleans for decisions, lists/tuples for ordered collections (changeable vs fixed), dictionaries for labeled data, sets for uniqueness, and None for intentionally missing values. Getting comfortable recognizing and converting between these types is the single most useful debugging skill you'll build in your first months of writing real code.