Python Variables and Data Types Explained (2026)
Python variables and data types look simple right up until they aren't. A beginner writes a running-total calculator: total = 0, then total += input("Enter amount: ") in a loop. Enter 10, then 15 — instead of 25, the program prints 1015. No error. No crash. Just the wrong answer, because input() always returns a string, and + between two strings concatenates instead of adding. This guide covers exactly what's happening there, plus every core type, mutability, and safe type conversion.
Quick Answer: Python Variables and Data Types
A Python variable is a name bound to a value — no type declaration needed, since Python figures out the type automatically from the value itself (dynamic typing). The core built-in data types are int, float, str, bool, and None. Some types are mutable (can change in place, like a list) and some are immutable (cannot, like a string or integer). Most beginner bugs in this area come from one thing: assuming Python will convert between types automatically when it won't.
The 1015 Bug
A beginner builds a simple running-total calculator. The logic looks completely reasonable: start at zero, ask the user for an amount, add it to the total, repeat.
total = 0 for _ in range(2): amount = input("Enter amount: ") total += amount print(total) # enter 10, then 15 — expects 25, prints 1015
No crash, no error message — just a silently wrong answer. The cause: input() always returns a string, no matter what the user types. "10" + "15" doesn't add two numbers — it concatenates two pieces of text, producing "1015". Python never assumed you meant addition, because as far as the type system is concerned, you asked it to combine text.
The fix is one line — amount = int(input("Enter amount: ")) — but understanding why the bug happened at all requires actually understanding how Python's types work, which is exactly what the rest of this article covers.
What a Variable Actually Is
A Python variable is a name that points to a value in memory — there's no separate "declare the type, then assign a value" step like in some other languages.
age = 28 name = "Maria" is_active = True age = "twenty-eight" # completely legal — age now points to a string instead
That last line is legal because Python uses dynamic typing: a variable name doesn't carry a fixed type — the value it currently points to does. Reassigning age to a string doesn't error; the name just points somewhere else now. This flexibility is convenient, but it's also exactly why type-related bugs like the one above don't get caught until the program actually runs.
Variable names must start with a letter or underscore, can contain letters, numbers, and underscores, and are case-sensitive — total and Total are different variables. Convention (PEP 8) favors lowercase with underscores: order_total, not orderTotal.
The Core Data Types
Five built-in types cover the overwhelming majority of everyday Python code.
whole_number = 42 # int decimal_number = 19.99 # float text = "data science" # str flag = True # bool nothing = None # NoneType print(type(whole_number)) # <class 'int'>
- int — whole numbers, positive or negative, no size limit beyond available memory.
- float — decimal numbers, stored as floating-point approximations (the same rounding caveats covered for SQL's DECIMAL vs FLOAT apply here too).
- str — text, always wrapped in quotes, immutable once created.
- bool — exactly two values,
TrueorFalse, technically a subtype of int (True == 1). - None — represents the deliberate absence of a value, not zero and not an empty string.
Mutable vs Immutable: Why It Matters Later
Every Python value is either mutable (changeable in place) or immutable (never changed, only replaced) — a distinction that becomes critical the moment lists and dictionaries enter the picture in the next article.
| Immutable | Mutable |
|---|---|
| int, float | list |
| str | dict |
| tuple | set |
| bool | — |
name = "maria" upper_name = name.upper() print(name) # still "maria" — the original string never changed print(upper_name) # "MARIA" — a brand-new string was created instead
name.upper() looks like it modifies the string in place — it doesn't. Strings are immutable, so every "modifying" string method actually returns a new string, leaving the original untouched. This is why forgetting to capture the return value (name.upper() alone, with no assignment) silently does nothing useful.
Type Conversion: The Actual Fix
Python never silently converts between fundamentally different types in an operation — you have to do it explicitly, using a small set of built-in conversion functions.
amount_text = input("Enter amount: ") amount = int(amount_text) # str -> int, the actual fix for the 1015 bug price = float("19.99") # str -> float label = str(42) # int -> str, for combining with text
int("abc") raises a ValueError — not every string is a valid number. Any time a conversion runs on real user input rather than a value you control, wrap it in a try/except block instead of assuming it will always succeed.
type() vs isinstance()
Both answer "what type is this," but they're not interchangeable inside real conditional logic.
value = 42 # quick debugging check print(type(value)) # <class 'int'> # the safer choice inside actual logic if isinstance(value, int): print("it's an int")
isinstance() correctly handles subclasses — since bool is technically a subclass of int, isinstance(True, int) returns True, which is usually what you actually want. A direct type(value) == int comparison misses that relationship entirely. Use type() for quick, throwaway debugging; use isinstance() anywhere a real decision depends on the check.
f-strings: The Modern Way to Combine Types
Rather than manually converting every value to a string before combining it with text, an f-string handles the conversion automatically, inline.
total = 25 name = "Maria" # old way: manual str() conversion required message = name + " spent $" + str(total) # f-string: handles the conversion for you message = f"{name} spent ${total}" print(message) # Maria spent $25
Inside an f-string's {}, any value — int, float, bool, even the result of a function call — gets converted to its string representation automatically. This is the standard, current way to build strings from mixed types in Python, and it sidesteps the entire class of "can't concatenate str and int" errors when the goal is display, not math.
Mistakes That Give Away a Beginner
- Assuming input() returns a number. The exact trap from this article's opening — it always returns a string, every time, with no exceptions.
- Calling a string method and expecting it to modify the original. Strings are immutable — capture the return value, or nothing changes.
- Converting user input without handling failure.
int()on invalid text raises a ValueError — wrap it in try/except for anything not fully controlled. - Using type() for a real conditional check instead of isinstance(), and missing subclass relationships as a result.
- Confusing None with 0, False, or an empty string. They're all "falsy" in a boolean context, but None specifically means "no value was set," not "the value is zero."
Practice: Fix These Three Yourself
Try each of these before moving to the next article:
Fix the running total
Rewrite the 1015-bug calculator so it correctly adds numbers instead of concatenating strings.
Check a type safely
Write a function that accepts any value and uses isinstance() to print whether it's a number (int or float).
Build a message with an f-string
Given a name (str), age (int), and is_member (bool), build one sentence combining all three using an f-string.
Frequently Asked Questions
What are the basic data types in Python?
The core built-in types are int (whole numbers), float (decimal numbers), str (text), bool (True or False), and NoneType (the absence of a value, written as None). More complex types like list, tuple, dict, and set are built from these basic ones.
Do I need to declare a variable's type in Python?
No. Python uses dynamic typing, meaning a variable's type is determined automatically from the value assigned to it, and the same variable name can be reassigned to a different type later in the program without declaring anything upfront.
What is the difference between mutable and immutable data types in Python?
A mutable type can be changed in place after creation, like a list or dictionary. An immutable type cannot be changed after creation; any operation that looks like it modifies a string, integer, or tuple actually creates a new object instead. This affects how variables behave when copied or passed to functions.
Why does adding a string and a number cause an error in Python?
Python's + operator is type-specific: between two numbers it adds, but between two strings it concatenates, and it refuses to mix a string with a number directly, raising a TypeError. Values from input() are always strings, which is why this error commonly appears when combining user input with a number without converting it first.
What is the difference between type() and isinstance() in Python?
type() returns a value's exact type and is common for quick debugging. isinstance() checks whether a value is an instance of a type or any of its subclasses, and is the recommended choice inside actual conditional logic because it correctly handles inheritance, which a direct type() comparison does not.
How do you convert a string to an integer in Python?
Use int() to convert a string containing whole digits to an integer, for example int('42') returns 42. Converting a string that isn't a valid number, such as int('abc'), raises a ValueError, so user input should generally be validated or wrapped in a try/except block before converting.
Conclusion: Know the Type Before You Trust the Operation
Python's dynamic typing removes the ceremony of declaring types upfront, but it doesn't remove the type rules themselves — + still means something different for strings than for numbers, and no operation silently guesses which one you meant. Know your five core types, know which ones are mutable, convert explicitly with int()/float()/str() rather than assuming, and reach for isinstance() the moment a type check is doing real work in your logic.
Practice the three exercises above, then move to the next article in this cluster, which covers Python's core data structures — lists, tuples, and dictionaries — built directly on the types covered here.
Next Up: Python Lists, Tuples, and Dictionaries
The mutable vs immutable distinction from this article becomes the whole story in the next one.
▶ Read the Lists, Tuples & Dictionaries GuideKhalid Hussain
Founder of Review Publically. MSc holder and Google Advanced Data Analytics certified. Teaches Python and SQL data analysis with a focus on current, correct, production-ready code rather than outdated conventions.
Related Articles