Python Data Types

Explore int, float, str, bool, and None - Python's core scalar types - plus type checking, casting, and the mutable vs immutable distinction.

Beginner 10 min read 9 examples

Numeric Types

Python has three built-in numeric types: int, float, and complex. int has unlimited precision.

Python
# int - whole numbers, unlimited size
x = 42
y = -100
big = 1_000_000_000   # underscores for readability (Python 3.6+)
binary  = 0b1010      # binary literal  -> 10
octal   = 0o17        # octal literal   -> 15
hexadec = 0xFF        # hex literal     -> 255

print(type(x))  # <class 'int'>

# float - 64-bit IEEE 754 double precision
pi    = 3.14159
sci   = 1.5e10    # scientific notation -> 15000000000.0
small = 2.5e-4    # -> 0.00025

print(type(pi))  # <class 'float'>

# Division always returns float
print(10 / 3)    # 3.3333333333333335
print(10 / 2)    # 5.0   (float, not 5)

# Floor division returns int (or float if either operand is float)
print(10 // 3)   # 3
print(10.0 // 3) # 3.0

# Float precision issue
print(0.1 + 0.2)   # 0.30000000000000004

import math
print(math.isclose(0.1 + 0.2, 0.3))  # True - proper float comparison

# complex - real + imaginary
c = 2 + 3j
print(c.real)  # 2.0
print(c.imag)  # 3.0

Strings (str)

Strings are sequences of Unicode characters. They are immutable - you cannot change a character in place. A full lesson covers strings in depth.

Python
# Single or double quotes - equivalent
a = 'hello'
b = "world"

# Triple quotes - multiline strings
multi = """Line one
Line two
Line three"""

# f-strings - format values inline (Python 3.6+)
name = "Alice"
age  = 30
print(f"Name: {name}, Age: {age}")     # Name: Alice, Age: 30
print(f"2 + 2 = {2 + 2}")             # 2 + 2 = 4
print(f"{name.upper()!r}")             # 'ALICE' (with repr)
print(f"{3.14159:.2f}")               # 3.14 (format spec)

# Raw strings - backslashes not treated as escape sequences
path = r"C:\Users\Alice\Documents"    # \ is literal
print(path)  # C:\Users\Alice\Documents

# Escape sequences (in regular strings)
print("Line 1\nLine 2")  # \n = newline
print("Tab\there")       # \t = tab
print("Quote: \"hi\"")   # \" = literal quote

Booleans (bool)

Python booleans are True and False (capitalized). Booleans are a subclass of int - True == 1 and False == 0.

Python
active = True
disabled = False

print(type(True))    # <class 'bool'>
print(True + True)   # 2 (bool is a subclass of int)
print(True * 5)      # 5

# Truthiness - values that evaluate to False in boolean context
# Falsy: False, None, 0, 0.0, "", [], {}, (), set()
# Everything else is truthy

print(bool(0))     # False
print(bool(""))    # False
print(bool([]))    # False
print(bool(None))  # False

print(bool(1))     # True
print(bool("hi"))  # True
print(bool([0]))   # True  (non-empty list, even if content is falsy)

# Using truthiness in if statements
items = []
if items:
    print("has items")
else:
    print("empty list")  # this runs

name = "Alice"
if name:
    print(f"Name is {name}")  # runs - non-empty string is truthy

None

None is Python's null value - it represents the absence of a value. It is the only instance of the NoneType class.

Python
result = None
print(result)         # None
print(type(result))   # <class 'NoneType'>

# Functions without a return statement return None
def do_nothing():
    pass

print(do_nothing())   # None

# Check for None with 'is' (not ==)
if result is None:
    print("No result yet")

if result is not None:
    print("We have a result")

# Common pattern: None as default + overwrite
def greet(name=None):
    if name is None:
        name = "World"
    return f"Hello, {name}!"

print(greet())        # Hello, World!
print(greet("Alice")) # Hello, Alice!

# None vs False vs 0 - all falsy but different
print(None == False)  # False
print(None == 0)      # False
print(None is None)   # True

type() and isinstance()

Python
# type() - returns the exact type
print(type(42))      # <class 'int'>
print(type(3.14))    # <class 'float'>
print(type("hello")) # <class 'str'>
print(type(True))    # <class 'bool'>
print(type(None))    # <class 'NoneType'>
print(type([]))      # <class 'list'>

# Compare type
if type(x) == int:   # works but not recommended
    pass

# isinstance() - preferred; handles inheritance
print(isinstance(42, int))           # True
print(isinstance(42, float))         # False
print(isinstance(True, int))         # True! (bool is subclass of int)
print(isinstance(True, bool))        # True
print(isinstance(3.14, (int, float)))# True - check against tuple of types

class Animal: pass
class Dog(Animal): pass

d = Dog()
print(isinstance(d, Dog))     # True
print(isinstance(d, Animal))  # True  (inheritance!)
print(type(d) == Animal)      # False (type() doesn't check inheritance)

Type Casting

Python
# int() - convert to integer
print(int("42"))      # 42
print(int(3.9))       # 3  (truncates, does NOT round)
print(int(True))      # 1
print(int(False))     # 0
# int("3.14")         # ValueError - can't convert "3.14" directly
print(int(float("3.14")))  # 3  (two-step conversion)

# float() - convert to float
print(float("3.14"))  # 3.14
print(float(42))      # 42.0
print(float("inf"))   # inf  (positive infinity)

# str() - convert to string
print(str(42))        # '42'
print(str(3.14))      # '3.14'
print(str(True))      # 'True'
print(str(None))      # 'None'

# bool() - convert to boolean
print(bool(1))        # True
print(bool(0))        # False
print(bool("text"))   # True
print(bool(""))       # False

# Handling ValueError from bad input
user_input = "not a number"
try:
    value = int(user_input)
except ValueError:
    print(f"Cannot convert '{user_input}' to int")
    value = 0

Mutable vs Immutable

Immutable (cannot change in place)Mutable (can change in place)
int, float, complexlist
booldict
strset
tuplebytearray
frozensetuser-defined classes (usually)
Python
# Immutable - "changing" creates a new object
s = "hello"
s += " world"   # creates new string, rebinds s
# s[0] = "H"   # TypeError: 'str' object does not support item assignment

# Mutable - changes happen in place
my_list = [1, 2, 3]
my_list.append(4)   # modifies the same list object
my_list[0] = 99     # modifies in place
print(my_list)      # [99, 2, 3, 4]

# This matters when passing to functions
def add_item(lst, item):
    lst.append(item)  # modifies the original list!

numbers = [1, 2, 3]
add_item(numbers, 4)
print(numbers)  # [1, 2, 3, 4] - function modified the original

# To avoid modifying the original, pass a copy
add_item(numbers.copy(), 5)
print(numbers)  # [1, 2, 3, 4] - unchanged

Built-in Types Reference

TypeKeywordExampleMutable?Notes
Integerint42NoUnlimited precision
Floatfloat3.14No64-bit IEEE 754
Complexcomplex2+3jNoReal + imaginary
Stringstr"hello"NoUnicode sequence
BooleanboolTrueNoSubclass of int
NoneNoneTypeNoneNoNull value singleton
Listlist[1, 2, 3]YesOrdered, indexed
Tupletuple(1, 2, 3)NoOrdered, fixed
Dictionarydict{"a": 1}YesKey-value pairs
Setset{1, 2, 3}YesUnique unordered

Frequently Asked Questions

int represents whole numbers with arbitrary precision (Python integers can be as large as memory allows). float represents floating-point numbers (decimals) using 64-bit IEEE 754 double precision. Float arithmetic has rounding errors: 0.1 + 0.2 != 0.3. Use the decimal module for exact decimal arithmetic (financial calculations). Division / always returns float; use // (floor division) for integer results.

This is a floating-point representation issue, not a Python bug - it affects all languages using IEEE 754 doubles. 0.1 cannot be represented exactly in binary floating point, so there is a tiny rounding error. Solutions: use round(0.1 + 0.2, 10) for display, use math.isclose(a, b) for comparisons, or use from decimal import Decimal; Decimal("0.1") + Decimal("0.2") for exact arithmetic.

None, False, and 0 are all falsy (they evaluate to False in a boolean context), but they are distinct objects of different types. None is of type NoneType, False is a bool, and 0 is an int. Use is None to check for None specifically (not == None). They are equal in a loose sense but not identical.

Use the type name as a function: int("42"), float("3.14"), str(100), bool(0), list((1,2,3)), tuple([1,2,3]). If conversion is impossible, Python raises a ValueError: int("hello") fails. Always handle this with try/except when converting user input.