Values and Types
Topic — In Python, data is not stored in rigid, statically typed boxes. Instead, every value is an object in memory that carries its own type, and variables are merely named tags pointing to those objects. This guide explores the four foundational primitive types (
int,float,str,bool), type inspection viatype()andisinstance(), the boolean integer inheritance surprise, floating-point precision traps, and casting rules.
1. The Core Concept
In programming, we distinguish between two fundamental concepts:
- A Value is the concrete piece of information (e.g.,
100,15.75,"Python",True). - A Type is the blueprint defining what operations are legal on that value (e.g., you can divide an
int, slice astr, but cannot add anintto astr).
Python is dynamically typed: you never declare a variable's type. Python inspects the value at runtime and assigns the appropriate class blueprint automatically:
| Expression | Python Interpretation | Assigned Data Type | Full Type Object |
|---|---|---|---|
100 | Whole number without decimal | int | <class 'int'> |
15.75 | Real number with decimal point | float | <class 'float'> |
"Python" | Characters enclosed in quotes | str | <class 'str'> |
True | Logical boolean keyword | bool | <class 'bool'> |
Floating-Point Numbers (float)
If you only take one thing from this page
In Python, variables do not have types; values have types. A variable is simply a name tag attached to an object in memory. If you reassign x = 100 and then x = "Python", the variable x has simply moved its pointer from an integer object to a string object.
2. Interactive Type Inspector Sandbox
Click on any Python literal or expression below to inspect its evaluated type, truthiness, mutability, and runtime memory behavior:
Python Value and Type Inspector
Select a Python literal to inspect how the runtime evaluates its object metadata:
num_value = 1003. Three Ways to Query Types in Python
- 1. isinstance(x, T) — Standard Best Practice
- 2. type(x) — Raw Type Object
- 3. type(x).__name__ — Clean String Output
- Syntax:
isinstance(value, target_type) - Returns:
TrueorFalse. - Why it's preferred: Correctly accounts for class inheritance. Also accepts a tuple of types:
# Checks if x is either an integer or floating-point numberif isinstance(x, (int, float)):print("x is numeric")
- Syntax:
type(value) - Returns: The raw type object itself (
<class 'int'>). - Trap with == comparison:
type(100) == int # Truetype(True) == int # False! (Checks exact class, ignoring inheritance)
- Syntax:
type(value).__name__ - Returns: The class name as a clean string:
'int','float','str','bool'. - Best For: Human-readable display output and logging without string slicing.
4. The Boolean Inheritance Surprise
In Python, bool is a direct subclass of int. This historical architecture design catches many developers off guard:
issubclass(bool, int) # True
isinstance(True, int) # True! True IS an integer!
Consequences of Boolean Inheritance
True == 1 # True
False == 0 # True
True + True # 2 (Arithmetic works!)
True * 50 # 50
The If-Elif Subclass Pitfall
Because True is an instance of int, checking isinstance(val, int) before isinstance(val, bool) will falsely intercept booleans:
# BUG: True matches the int check!
if isinstance(val, int):
print("Number")
elif isinstance(val, bool): # Never reached!
print("Flag")
# FIX: Always check bool first
if isinstance(val, bool):
print("Flag")
elif isinstance(val, int):
print("Number")
5. Type Conversion and Casting Pitfalls
Python provides built-in constructors (int(), float(), str(), bool()) to cast between types:
- 1. Truncation vs. Rounding
- 2. The Decimal String Trap
- 3. Falsy Values in Python
int(15.75)evaluates to15.- Rule:
int()truncates toward zero; it does not round to the nearest whole integer. - To round properly according to standard arithmetic rules, use
round(15.75).
int("100")succeeds ().int("15.75")crashes with aValueError!- Why:
int()can only parse base-10 digit strings. It cannot parse decimal points. - Fix: Route through
floatfirst:int(float("15.75")).
Truthy and Falsy Values in Python
In Python, only exactly seven values convert to False:
False0(Integer zero)0.0(Float zero)""(Empty string)[](Empty list){}(Empty dict / set)None
Every other object is Truthy, including strings containing "False" or "0":
bool("False") # True! (Non-empty string)
bool("0") # True!
bool(-1) # True! (Any non-zero number)
6. Implementation Lab
Lab Exercise: Values, Types & Casting Mechanics
An interactive, fully functional Google Colab / Jupyter Notebook is available to inspect types, verify the boolean integer inheritance chain, test floating-point epsilon comparisons, and practice type casting live in your browser.
How to run the lab:
- Click the "Open In Colab" badge above to launch the interactive notebook.
- Run cells sequentially to experiment with type inspection and truthiness rules.
Key Experiments to Run:
- Experiment 1 (Type vs. Isinstance): Compare
type(True) == int(False) withisinstance(True, int)(True) to see inheritance in action. - Experiment 2 (Floating-Point Epsilon): Evaluate
0.1 + 0.2 == 0.3(False) and write a safe tolerance check usingabs(a - b) < 1e-9. - Experiment 3 (Type Casting Traps): Catch
ValueErroronint("15.75")and demonstrate the nested casting fixint(float("15.75")).
7. Common Mistakes
- 1. Lowercase Booleans
- 2. Accidentally Quoting Numbers
- 3. Forgetting input() Returns String
- 4. Believing int() Rounds Numbers
- 5. Assuming bool('False') is False
- The Misconception: "In Python, booleans can be typed as
trueorfalselike in JavaScript." - Wrong Thinking: Typing
flag = true. - The Right Principle: Python keywords are case-sensitive.
trueraises aNameError: name 'true' is not defined. Always capitalize:TrueandFalse.
- The Misconception: "A number is a number regardless of whether it has quotes."
- Wrong Thinking:
val = "100"followed by arithmeticval * 2. - The Right Principle: Quotes create a
str."100" * 2performs sequence repetition resulting in"100100". Remove quotes for mathematical numbers (val = 100).
- The Misconception: "If a user types 25 into
input(), Python stores it as an integer." - Wrong Thinking:
age = input(); age + 5raisesTypeError: can only concatenate str to str. - The Right Principle:
input()always returns astr. You must explicitly convert it:age = int(input()).
- The Misconception: "Calling
int(15.75)gives 16 because .75 is closer to 16." - Wrong Thinking: Treating
int()as a rounding function. - The Right Principle:
int()completely discards the fractional part (truncates toward zero). To round, useround(15.75).
- The Misconception: "Converting the word 'False' to bool gives False."
- Wrong Thinking: Expecting string semantic parsing from
bool(). - The Right Principle: In Python,
bool(s)evaluates whether stringsis non-empty. Because"False"contains 5 characters,bool("False")evaluates toTrue! Only""isFalse.
8. Summary
Primitive Types
- int: Arbitrary-precision whole numbers. Division (
/) always produces afloat. - float: IEEE 754 64-bit numbers. Exact for binary fractions (), approximate for decimals ().
- str: Immutable text sequences. Indexed from or .
- bool: Subclass of
int.True == 1,False == 0.
Runtime Inspection
- type(x): Returns raw class object (
<class 'int'>). - isinstance(x, T): Preferred check; respects inheritance and accepts tuples
(int, float). - Dynamic Typing: Variables are labels; objects carry types.
- int() vs. round():
int()truncates;round()rounds.
Key Takeaways
- Values carry types: Variables are pointers to objects in memory; dynamic re-assignment changes which object the variable points to.
- Prefer isinstance(): Use
isinstance(x, (int, float))for robust numerical validation. - Falsy check: Only and are falsy; all other values evaluate to
True.
Next Section: Variables and Naming - exploring namespace scopes, reference assignment, and PEP 8 naming conventions.
9. Active Recall
Test your understanding by answering first, then clicking to reveal the underlying principles.
Interactive Checkpoint Quiz
Interactive Checkpoint: The Dynamic Typing Trap
Consider this Python snippet: x = "20"; print(x * 3). What is printed, and why?
Review Flashcards
1. [THEORY] Why does Python evaluate 0.1 + 0.2 == 0.3 as False?
- Base-2 Binary Fractions: Computers represent floating-point numbers in binary.
- Just as has an infinite repeating decimal in base-10, and are infinite repeating fractions in base-2:
- When truncated to 53 bits of precision, yields:
- Safe Comparison: Never use
==on floats. Usemath.isclose(a, b)orabs(a - b) < 1e-9.
2. [THEORY] Why does isinstance(True, int) evaluate to True, but type(True) == int evaluates to False?
- Inheritance: In Python,
boolis a subclass ofint(issubclass(bool, int) == True). isinstance(obj, Class)checks ifobjis an instance ofClassor any class derived from it. BecauseTrueis aboolandboolinherits fromint,isinstancereturnsTrue.type(obj) == Classchecks for exact class identity, ignoring inheritance. Becausetype(True)is<class 'bool'>and not<class 'int'>, it evaluates toFalse.
3. [PRACTICE] Why does int("15.75") raise a ValueError, and how do you fix it?
- Base-10 Parsing Limit: The
int(s)constructor expects a string consisting purely of integer digits. The character.is not a valid base-10 digit, so Python raisesValueError: invalid literal for int() with base 10: '15.75'. - The Fix: Parse the decimal string through
float()first, then truncate to integer:int(float("15.75")) # Evaluates to 15
4. [ANALYZE] What is printed by print(bool("False")) and print(bool(""))?
print(bool("False"))printsTrue.print(bool(""))printsFalse.- The Principle: In Python, string truthiness is determined strictly by sequence length (
len(s) > 0). It does not parse the semantic English meaning of the letters inside the string. Only an empty string""has length 0 and evaluates toFalse.
5. [THEORY] What does it mean that Python is dynamically typed?
- Types Belong to Objects, Not Variables: In statically typed languages (like C or Java), a variable is declared with a fixed type (
int x = 10;) and can never hold any other type. - In Python, variables are simply pointers (labels) in the namespace. An object on the heap carries its type header.
- Reassigning
x = 10tox = "hello"merely rebinds the labelxto a different object in memory; Python handles this without compiler errors.