Exploring Basic Data Types

Every value in Python is an object, and every object has a type. Five built-in types cover the overwhelming majority of data you will handle at the start: integers (int), floating-point numbers (float), Booleans (bool), text (str) and the absence of a value (NoneType, whose single instance is None). Knowing which one you are holding — and how to convert between them safely — eliminates a huge class of runtime errors.

Python integers are arbitrary precision: 2 ** 100 is a perfectly normal value with no overflow. Floats are standard 64-bit IEEE-754 doubles, so they have about 15–17 significant digits of precision and all the usual rounding surprises (0.1 + 0.2 == 0.3 is False). When exact decimals matter — money, measurements — use decimal.Decimal instead. When fractions are needed exactly, use fractions.Fraction.

bool is technically a subclass of int, with True equal to 1 and False equal to 0. That is why sum([True, True, False]) returns 2, which is occasionally useful for counting matches. More importantly, every object has a truth value: empty containers, zero, None and empty strings are all falsy; everything else is truthy. This is what makes if items: idiomatic in place of if len(items) > 0:.

str is an immutable sequence of Unicode characters. That one word, immutable, has two important consequences: string methods never change the original (they return a new string), and strings can be used as dictionary keys. Every letter, digit, emoji, Chinese character or mathematical symbol is valid in a Python string because the default encoding for source files and string literals is UTF-8.

Finally, None is Python's way of saying "no value". It is the default return of a function with no explicit return, a common default argument to signal "use the built-in default", and the unambiguous "nothing here" for missing fields. Compare with is None and is not None, never with == None, because is checks object identity and avoids surprises with objects that define their own __eq__.

Checking and converting types

type(value) returns the exact class; isinstance(value, cls) accepts subclasses (important for booleans and custom classes). Conversion functions are the classes themselves: int("42"), float("3.14"), str(42), bool(0). All conversions are explicit; Python never silently mixes numeric and text types.

Beware that bool("False") returns True because the string is non-empty. To parse the text "True" / "False" into a boolean, compare against a whitelist or use ast.literal_eval.

Type hints, for humans and tools

Modern Python allows annotations such as def area(radius: float) -> float:. These annotations are not enforced at runtime; they are documentation that tools (mypy, pyright, your editor) use to catch mistakes before you run the code. Start simple: annotate the parameters and return types of every function that is not trivial, and let the tooling do the rest.

These are the built-in types and their conversion helpers. Click through to the docs for the full list of methods on each.

ToolPurpose
int()
built-in
Integer with arbitrary precision; converts from str or float.
float()
built-in
64-bit IEEE-754 floating-point number.
bool()
built-in
Truth value; True and False are the only instances.
str
built-in type
Immutable Unicode text; supports rich formatting and search methods.
None
constant
The single instance of NoneType; means "no value".
type()
built-in
Returns the exact class of its argument.
isinstance()
built-in
Tests membership in a class or tuple of classes.
decimal.Decimal
class
Exact decimal arithmetic for money and measurements.

Exploring Basic Data Types code example

The example creates one value of each basic type, checks its class, and demonstrates safe conversions.

# Lesson: Exploring Basic Data Types
# Goal: observe how each built-in type behaves and convert between them safely.
from decimal import Decimal


def describe(value: object) -> str:
    '''Return one line: type, repr, truthiness.'''
    return f"{type(value).__name__:<5} {value!r:<25} truthy={bool(value)}"


samples: list[object] = [
    42,              # int
    3.14,            # float
    True,            # bool (note: also counts as int)
    "Ada",           # str
    None,            # NoneType
    "",              # empty str is falsy
    0,               # zero int is falsy
    Decimal("0.10"), # exact decimal
]

for item in samples:
    print(describe(item))

# Safe conversions: always guard str -> number with try/except
for text in ["10", "3.2", "nope"]:
    try:
        print(f"int({text!r}) = {int(text)}")
    except ValueError as err:
        print(f"int({text!r}) -> {err}")

# Correct comparison with None
result: int | None = None
if result is None:
    print("no result yet")

Points to notice while reading:

1) describe() prints the type, repr and truthiness in one row.
2) Decimal keeps trailing zeros; float would not.
3) int("3.2") raises because int() does not parse decimals.
4) `result is None` is the idiomatic way to check for the sentinel.

Two practice snippets that isolate truthiness and the int/float boundary.

# Example A: truthiness as a filter
values = [0, 1, "", "hi", None, [], [1]]
real = [v for v in values if v]
print(real)  # -> [1, 'hi', [1]]

# Example B: int vs float division
a = 7
b = 2
print(a / b)   # true division -> 3.5  (always float)
print(a // b)  # floor division -> 3   (int result for int inputs)
print(a % b)   # modulus -> 1
print(type(a / b).__name__, type(a // b).__name__)

These assertions verify the behaviours that first trip most learners up.

assert isinstance(True, int)           # bool is a subclass of int
assert bool("False") is True           # any non-empty string is truthy
assert 0.1 + 0.2 != 0.3                # classic float surprise
assert Decimal("0.1") + Decimal("0.2") == Decimal("0.3")

Running the script prints one descriptive line per value:

int   42                        truthy=True
float 3.14                      truthy=True
bool  True                      truthy=True
str   'Ada'                     truthy=True
NoneType None                    truthy=False
str   ''                        truthy=False
int   0                         truthy=False
Decimal Decimal('0.10')         truthy=True
int('10') = 10
int('3.2') -> invalid literal for int() with base 10: '3.2'
int('nope') -> invalid literal for int() with base 10: 'nope'
no result yet