Ad – 728Γ—90
🌱 Beginner

Python Data Types – The Complete Guide

Every value in Python has a type. Understanding data types is fundamental to writing correct code β€” operations that work on integers fail on strings, and confusing a None value for a number is a classic source of bugs. This lesson covers all of Python's built-in primitive types: int, float, str, bool, NoneType, and complex, plus how to inspect and check types at runtime.

⏱️ 22 min read 🎯 Beginner πŸ“… Updated 2026

What Are Data Types?

A data type tells Python what kind of value a variable holds and what operations are legal on it. You can add two integers, but you can't divide a string by a number. Python's type system enforces these rules and raises clear errors when you mix incompatible types.

Python is dynamically typed, meaning you don't declare types when creating variables β€” Python infers the type from the value. However, types still exist and matter at runtime.

Python
# Python infers the type automatically
x = 42          # int
y = 3.14        # float
name = "Alice"  # str
active = True   # bool
nothing = None  # NoneType

# Check each type
print(type(x))       # <class 'int'>
print(type(y))       # <class 'float'>
print(type(name))    # <class 'str'>
print(type(active))  # <class 'bool'>
print(type(nothing)) # <class 'NoneType'>
β–Ά Output
<class 'int'> <class 'float'> <class 'str'> <class 'bool'> <class 'NoneType'>

Integers (int)

Integers are whole numbers β€” positive, negative, or zero β€” with no decimal point. Python's int type has unlimited precision: there is no maximum value (unlike C/Java where integers overflow). You can compute with numbers as large as your RAM allows.

Python
# Regular integers
age = 25
temperature = -10
score = 0

# Large integers β€” no overflow in Python!
big_number = 1_000_000_000_000  # underscores for readability
factorial_20 = 2432902008176640000
print(factorial_20)

# Different integer literals
decimal = 255          # base 10 (normal)
hexadecimal = 0xFF     # base 16 β†’ 255
octal = 0o377          # base 8  β†’ 255
binary = 0b11111111    # base 2  β†’ 255

print(decimal, hexadecimal, octal, binary)  # all print as 255

# Integer arithmetic
print(10 + 3)    # 13
print(10 - 3)    # 7
print(10 * 3)    # 30
print(10 ** 3)   # 1000 (exponentiation)
print(10 // 3)   # 3  (floor division β€” integer result)
print(10 % 3)    # 1  (modulo β€” remainder)
β–Ά Output
2432902008176640000 255 255 255 255 13 7 30 1000 3 1
πŸ’‘
Use Underscores in Large Numbers

Python allows underscores as visual separators in numeric literals: 1_000_000 is the same as 1000000 but much easier to read. This works for integers, floats, and hex values.

Floats (float)

Floats represent real numbers with a decimal point. Python floats are 64-bit double-precision IEEE 754 values, giving about 15–17 significant digits of precision. This high precision is sufficient for most real-world calculations.

Python
pi = 3.14159265358979
height = 1.75
temperature = -273.15

# Scientific notation
speed_of_light = 3e8       # 3 Γ— 10^8 = 300000000.0
tiny = 1.5e-10             # 1.5 Γ— 10^-10

print(speed_of_light)   # 300000000.0
print(tiny)             # 1.5e-10

# Float arithmetic
print(0.1 + 0.2)        # 0.30000000000000004 (floating point precision!)
print(round(0.1 + 0.2, 2))  # 0.3 β€” use round() for display

# Division always returns float in Python 3
print(7 / 2)    # 3.5
print(7 // 2)   # 3  (floor division β†’ int)

# Special float values
import math
print(math.inf)    # inf
print(-math.inf)   # -inf
print(math.nan)    # nan (Not a Number)
β–Ά Output
300000000.0 1.5e-10 0.30000000000000004 0.3 3.5 3 inf -inf nan
⚠️
Floating-Point Precision

0.1 + 0.2 does not equal exactly 0.3 in most programming languages. This is a fundamental property of binary floating-point representation, not a Python bug. For financial calculations requiring exact decimal arithmetic, use Python's decimal module: from decimal import Decimal.

Strings (str)

Strings are sequences of characters used to represent text. In Python, strings are immutable β€” you can't change a string in place; any "modification" creates a new string.

Python
# Creating strings
greeting = "Hello, World!"
single = 'Also a valid string'
multiline = """This spans
multiple lines"""

# String operations
name = "Python"
print(len(name))           # 6 β€” length
print(name[0])             # P β€” indexing
print(name[-1])            # n β€” negative indexing (from end)
print(name[0:3])           # Pyt β€” slicing
print(name.upper())        # PYTHON
print(name.lower())        # python
print(name * 3)            # PythonPythonPython β€” repetition

# String is immutable
word = "hello"
# word[0] = "H"  # TypeError! Can't change in place
word = "H" + word[1:]      # Must create a new string
print(word)                 # Hello
β–Ά Output
6 P n Pyt PYTHON python PythonPythonPython Hello
Ad – 336Γ—280

Booleans (bool)

Booleans represent truth values: True or False. They are used extensively in conditional statements and comparisons. In Python, bool is actually a subclass of int β€” True equals 1 and False equals 0, which leads to some interesting behavior.

Python
is_active = True
is_deleted = False

print(type(is_active))   # <class 'bool'>

# bool is a subclass of int
print(True + True)       # 2
print(True + 1)          # 2
print(False + 10)        # 10
print(True * 5)          # 5

# Comparison operators return booleans
print(10 > 5)            # True
print(10 == 5)           # False
print(10 != 5)           # True

# "Truthy" and "Falsy" values
# These are considered False:
print(bool(0))           # False
print(bool(0.0))         # False
print(bool(""))          # False (empty string)
print(bool([]))          # False (empty list)
print(bool(None))        # False

# These are considered True:
print(bool(1))           # True
print(bool(-42))         # True
print(bool("hello"))     # True
print(bool([1, 2]))      # True
β–Ά Output
<class 'bool'> 2 2 10 5 True False True False False False False False True True True True
πŸ’‘
Capitalize Boolean Literals

In Python, booleans are True and False with capital first letters. Writing true or false (lowercase) causes a NameError. This trips up developers coming from JavaScript or other languages.

NoneType (None)

None is Python's way of representing "no value" or "absence of a value". It is its own type (NoneType) and there is only one None object in Python β€” it's a singleton. This is conceptually similar to null in Java/JavaScript or nil in other languages.

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

# Functions that don't return a value return None implicitly
def do_nothing():
    pass

value = do_nothing()
print(value)          # None

# The correct way to check for None is using 'is'
if result is None:
    print("No result yet")

# Avoid using == for None comparison
# result == None  ← works but not Pythonic
# result is None  ← correct, recommended

# None is falsy
if not result:
    print("result is falsy (None counts)")

# None as a default/placeholder
user_name = None
user_email = None
# (later in program, user fills these in)
β–Ά Output
None <class 'NoneType'> None No result yet result is falsy (None counts)
⚠️
Always Use "is None", Not "== None"

While x == None often works, the correct, Pythonic way is x is None. The is operator checks identity (same object in memory), while == checks equality (which can be overloaded by custom classes in surprising ways).

Complex Numbers (complex)

Python has built-in support for complex numbers using the form a + bj, where a is the real part and b is the imaginary part. This is particularly useful in scientific computing, signal processing, and engineering applications.

Python
# Creating complex numbers
c1 = 3 + 4j
c2 = complex(2, -1)   # 2 - 1j

print(c1)             # (3+4j)
print(c2)             # (2-1j)
print(type(c1))       # <class 'complex'>

# Accessing parts
print(c1.real)        # 3.0
print(c1.imag)        # 4.0
print(c1.conjugate()) # (3-4j)

# Complex arithmetic
print(c1 + c2)        # (5+3j)
print(c1 * c2)        # (10+5j)

# Magnitude (absolute value)
import math
magnitude = math.sqrt(c1.real**2 + c1.imag**2)
print(magnitude)      # 5.0
print(abs(c1))        # 5.0 β€” abs() works on complex numbers
β–Ά Output
(3+4j) (2-1j) <class 'complex'> 3.0 4.0 (3-4j) (5+3j) (10+5j) 5.0 5.0

Type Checking: type() and isinstance()

Python provides two built-in tools to inspect types at runtime. Knowing when to use each is important.

Python
# type() β€” returns the exact type object
x = 42
print(type(x))           # <class 'int'>
print(type(x) == int)    # True β€” exact type match

# isinstance() β€” checks if object is an instance of a type or subclass
print(isinstance(x, int))    # True
print(isinstance(x, float))  # False
print(isinstance(x, (int, float)))  # True β€” check multiple types

# Why isinstance() is often better: it handles inheritance
# bool is a subclass of int, so:
flag = True
print(type(flag) == int)        # False β€” exact match fails
print(isinstance(flag, int))    # True  β€” recognizes inheritance!
print(isinstance(flag, bool))   # True

# Practical usage: validating input type
def process_number(n):
    if not isinstance(n, (int, float)):
        raise TypeError(f"Expected int or float, got {type(n).__name__}")
    return n * 2

print(process_number(5))     # 10
print(process_number(3.14))  # 6.28
# process_number("5")        # TypeError!
β–Ά Output
<class 'int'> True True False True False True True 10 6.28

Mutable vs Immutable Types

This is one of the most important concepts in Python. Immutable objects cannot be changed after creation. Mutable objects can be modified in place. All primitive types (int, float, str, bool, complex, NoneType) are immutable.

Category Type Mutable? Example
PrimitiveintNo (immutable)42
PrimitivefloatNo (immutable)3.14
PrimitivestrNo (immutable)"hello"
PrimitiveboolNo (immutable)True
PrimitiveNoneTypeNo (immutable)None
CollectionlistYes (mutable)[1, 2, 3]
CollectiondictYes (mutable){"a": 1}
CollectionsetYes (mutable){1, 2, 3}
CollectiontupleNo (immutable)(1, 2, 3)
Python
# Immutability of strings β€” "changes" create new objects
original = "hello"
print(id(original))     # memory address, e.g. 140234567890

modified = original.upper()
print(id(modified))     # DIFFERENT address β€” new object
print(original)         # "hello" β€” unchanged

# Integer caching (Python caches small integers)
a = 42
b = 42
print(a is b)           # True β€” same object (cached)

a = 1000
b = 1000
print(a is b)           # May be False β€” large ints not cached

# Mutable types: changes affect the original
my_list = [1, 2, 3]
alias = my_list          # both point to same list
alias.append(4)
print(my_list)           # [1, 2, 3, 4] β€” changed via alias!

# To avoid this, make a copy:
original_list = [1, 2, 3]
copy_list = original_list.copy()
copy_list.append(4)
print(original_list)     # [1, 2, 3] β€” unaffected
β–Ά Output
hello [1, 2, 3, 4] [1, 2, 3]

Quick Reference: All Primitive Types

Type Keyword Example Literal Truthy when Falsy when
Integerint42, -7, 0Non-zero0
Floatfloat3.14, -0.5Non-zero0.0
Stringstr"hello", ''Non-empty""
BooleanboolTrue, FalseTrueFalse
NoneNoneTypeNoneNeverAlways
Complexcomplex3+4jNon-zero0j

πŸ‹οΈ Practical Exercise

Create a Python script that demonstrates all six primitive types:

  1. Create one variable of each type: int, float, str, bool, NoneType, complex.
  2. Print each variable's value and its type using type().
  3. Use isinstance() to check if your integer variable is also an instance of bool (it's not). Then check if your True variable is an instance of int (it is!).
  4. Demonstrate that strings are immutable by trying .upper() and showing the original is unchanged.

πŸ”₯ Challenge Exercise

Write a function called describe_value(x) that accepts any value and prints a full report: the value itself, its type name (just the name, not the full class string), whether it is truthy or falsy, and whether it is mutable or immutable. Test it with at least one value of each primitive type plus a list and a tuple. Use isinstance() for type checking rather than type().

Interview Questions on Data Types

  • What is the difference between type() and isinstance()? When should you use each?
  • Why is 0.1 + 0.2 != 0.3 in Python? How do you work around this?
  • What is the difference between mutable and immutable types? Give examples of each.
  • Why is bool a subclass of int in Python? What are the implications?
  • What is NoneType and how should you check if a variable is None?
  • Python integers have unlimited precision. Why doesn't this make them infinitely fast?
  • What are "truthy" and "falsy" values? List all the falsy built-in values in Python.
  • What is integer caching in Python and why does a is b return True for small integers?

πŸ“‹ Summary

  • Python has six primitive types: int, float, str, bool, NoneType, and complex.
  • int holds whole numbers with unlimited precision; use // for integer division, % for remainder.
  • float holds decimal numbers (64-bit); be aware of floating-point precision issues with 0.1 + 0.2.
  • All primitive types are immutable β€” they cannot be changed in place; operations return new objects.
  • bool is a subclass of int: True == 1 and False == 0.
  • Use x is None (not x == None) to check for None.
  • Use type() for exact type checks; use isinstance() for inheritance-aware checks.
  • Zero, empty strings, empty containers, and None are all falsy; everything else is truthy.

Frequently Asked Questions

Is Python weakly typed or strongly typed? +

Python is strongly typed but dynamically typed. Strongly typed means you can't implicitly mix incompatible types (e.g., "5" + 5 raises a TypeError). Dynamically typed means types are checked at runtime, not compile time, and variables don't need explicit type declarations.

What is the difference between int division / and // in Python 3? +

In Python 3, / always performs true division and returns a float: 7 / 2 = 3.5. The // operator performs floor division and returns an int (when both operands are integers): 7 // 2 = 3. This was a major change from Python 2, where / between two integers performed integer division.

Can a Python variable change its type? +

Yes. Python variables are just names that point to objects. You can reassign a variable to a value of any type at any time: x = 5 then x = "five". This is called dynamic typing. The variable itself doesn't have a type β€” the object it points to has a type.

Why should I prefer isinstance() over type() for type checking? +

isinstance() respects inheritance, while type() requires an exact match. For example, isinstance(True, int) returns True (correct β€” bool is a subclass of int), but type(True) == int returns False. In general code, you should use isinstance() unless you specifically need to exclude subclasses.

What is the difference between None, 0, False, and empty string ""? +

They are all falsy but represent different concepts. None means "no value / absence". 0 means the number zero. False means a negative truth value. "" means an empty text string. They are not equal to each other: None == 0 is False, None == False is False. Use the right one for its semantic meaning.