Skip to content

Python Data Types

This article provides an in-depth look at Python’s six built-in container data types and their operations, along with modern type tools introduced in Python 3.9+.

Strings

Strings are immutable sequences of characters that come with a rich set of built-in methods.

Definition and Basic Operations

# Three ways to define a string (all equivalent)
s1 = 'hello'
s2 = "world"
s3 = """multi-line
string"""

# Concatenation and repetition
greeting = "Hello" + ", " + "Python"
line = "-" * 40

# Multi-line concatenation (backslash continuation; adjacent string literals auto-merge)
long_str = ("This is part one"
            "This is part two")  # Preferred: no backslash needed inside parentheses

# Indexing and slicing
s = "abcdef"
print(s[0])       # a (forward index starts at 0)
print(s[-1])      # f (reverse index starts at -1)
print(s[2:5])     # cde
print(s[::2])     # ace (every other character)
print(s[::-1])    # fedcba (reversed)

Common Built-in Methods

s = "Hello World"

# Case conversion
print(s.upper())        # HELLO WORLD
print(s.lower())        # hello world
print(s.capitalize())   # Hello world (first letter upper, rest lower)
print(s.title())        # Hello World
print(s.swapcase())     # hELLO wORLD

# Search and inspection
print(s.find("World"))        # 6 (returns -1 if not found)
print(s.index("World"))       # 6 (raises ValueError if not found)
print(s.count("l"))           # 3
print(s.startswith("Hello"))  # True
print(s.endswith("World"))    # True
print("123".isdecimal())      # True
print("abc".isalpha())        # True

# Strip whitespace / specific characters
print("  hello  ".strip())        # hello
print("***hello***".strip("*"))   # hello
print("  hello".lstrip())         # hello (strip left)
print("hello  ".rstrip())         # hello (strip right)

# Split and join
words = "a,b,c,d".split(",")       # ['a', 'b', 'c', 'd']
words2 = "a b c".split()           # ['a', 'b', 'c'] (splits on any whitespace)
print(",".join(["a", "b", "c"]))   # a,b,c

# Replace
print("hello python".replace("python", "world"))  # hello world

# Alignment and padding
print("hi".center(10, "*"))   # ****hi****
print("hi".ljust(10, "-"))    # hi--------
print("hi".rjust(10, "-"))    # --------hi
print("42".zfill(5))          # 00042

Formatting (Three Methods Compared)

name, age = "Alice", 25

# 1. % formatting (old-style, not recommended)
print("Name: %s, Age: %d" % (name, age))

# 2. str.format()
print("Name: {}, Age: {}".format(name, age))
print("{name} is {age} years old".format(name=name, age=age))
print("{:.2f}".format(3.14159))    # 3.14
print("{:>10}".format("right"))    # right-aligned, width 10
print("{:,}".format(1234567))      # 1,234,567

# 3. f-strings (recommended, Python 3.6+)
print(f"Name: {name}, Age: {age}")
print(f"π ≈ {3.14159:.2f}")
print(f"{age + 1} years old")
print(f"{name!r}")                 # 'Alice' (repr form)
print(f"{name=}")                  # name='Alice' (Python 3.8+, great for debugging)

Lists

Lists are ordered, mutable sequences that can hold elements of any type.

Defining Lists and Slicing

lst = [1, "hello", 3.14, True, [2, 3]]

# Slicing (same syntax as strings)
nums = [0, 1, 2, 3, 4, 5]
print(nums[1:4])     # [1, 2, 3]
print(nums[::2])     # [0, 2, 4]
print(nums[::-1])    # [5, 4, 3, 2, 1]

# Slice assignment (in-place modification)
nums[1:3] = [10, 20]
print(nums)          # [0, 10, 20, 3, 4, 5]

Common List Methods

lst = ["a", "b", "c"]

# Add
lst.append("d")           # Append single element to end → ['a', 'b', 'c', 'd']
lst.insert(1, "x")        # Insert before index 1 → ['a', 'x', 'b', 'c', 'd']
lst.extend([1, 2])        # Append multiple elements → ['a', 'x', 'b', 'c', 'd', 1, 2]

# Remove
lst.pop()                 # Remove and return the last element
lst.pop(0)                # Remove and return the element at index 0
lst.remove("x")           # Remove the first occurrence of "x"
lst.clear()               # Clear the list

# Search
lst = [3, 1, 4, 1, 5, 9]
print(lst.index(1))       # 1 (index of first occurrence)
print(lst.count(1))       # 2 (number of occurrences)

# Sorting and reversing
lst.sort()                # Sort in ascending order in-place → [1, 1, 3, 4, 5, 9]
lst.sort(reverse=True)    # Sort in descending order in-place
lst.reverse()             # Reverse in-place

# Built-in functions
print(sorted([3, 1, 2]))  # [1, 2, 3] (returns a new list; original unchanged)
print(len(lst))
print(max(lst), min(lst), sum(lst))

List Comprehensions

# Basic form
squares = [x ** 2 for x in range(10)]

# With condition
evens = [x for x in range(20) if x % 2 == 0]

# Nested
matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]

# Python 3.9+: list as a type annotation directly
def process(items: list[int]) -> list[str]:
    return [str(x) for x in items]

Tuples

Tuples are ordered, immutable sequences, commonly used for returning multiple values or as dictionary keys.

# Definition
t = (1, 2, 3)
single = (42,)          # Single-element tuple requires a trailing comma

# Unpacking
x, y, z = (1, 2, 3)
first, *rest = (1, 2, 3, 4, 5)   # first=1, rest=[2, 3, 4, 5]

# Only supports index and count
print(t.index(2))    # 1
print(t.count(1))    # 1

# Named tuple (dataclass is more modern in Python 3.6+, but namedtuple is still widely used)
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(1.0, 2.0)
print(p.x, p.y)      # 1.0  2.0

Dictionaries

Dictionaries are key-value pair containers (insertion order is guaranteed in Python 3.7+).

Definition and Basic Operations

# Definition
person = {"name": "Alice", "age": 25}

# Access (prefer get to avoid KeyError)
print(person["name"])                   # Alice
print(person.get("city", "Unknown"))    # Unknown (default value when key is missing)

# Add / update
person["email"] = "alice@example.com"
person.update({"age": 26, "city": "Beijing"})

# Delete
age = person.pop("age")             # Remove and return the value
person.popitem()                    # Remove and return the last inserted key-value pair (Python 3.7+)
del person["email"]

# Iterate
for k, v in person.items():
    print(f"{k}: {v}")

print(list(person.keys()))
print(list(person.values()))

Dict Comprehensions and Merge (Python 3.9+)

# Dict comprehension
squares = {x: x ** 2 for x in range(5)}

# setdefault: set a default value if the key is absent and return it
d = {"a": 1}
d.setdefault("b", 0)    # d = {"a": 1, "b": 0}

# fromkeys: create a dictionary from a list of keys
keys = ["x", "y", "z"]
d = dict.fromkeys(keys, 0)   # {"x": 0, "y": 0, "z": 0}

# Python 3.9+ dict merge operator
defaults = {"color": "red", "size": 10}
custom = {"color": "blue"}
merged = defaults | custom          # New dict; custom overrides defaults
defaults |= custom                  # In-place merge

# Python 3.9+: dict directly as a type annotation
def config() -> dict[str, int]:
    return {"timeout": 30}

Sets

Sets are unordered containers of unique elements, primarily used for deduplication and set operations.

# Definition
s = {1, 2, 3, 2, 1}   # Duplicates removed automatically → {1, 2, 3}
empty = set()           # Empty set; {} creates an empty dict, not a set

# Common methods
s.add(4)
s.update([5, 6])
s.discard(99)           # Remove element; no error if absent (preferred)
s.remove(1)             # Remove element; raises KeyError if absent

# Set operations
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a | b)            # Union: {1, 2, 3, 4, 5, 6}
print(a & b)            # Intersection: {3, 4}
print(a - b)            # Difference: {1, 2} (in a but not b)
print(a ^ b)            # Symmetric difference: {1, 2, 5, 6} (unique to each set)

print({1, 2} < {1, 2, 3})    # True (subset check)
print({1, 2, 3} > {1, 2})    # True (superset check)
print({1, 2}.isdisjoint({3, 4}))  # True (no common elements)

# frozenset: immutable set; can be used as a dictionary key
fs = frozenset([1, 2, 3])

Mutable vs Immutable Types

TypeMutableNotes
int, float, str, tuple, frozensetNoModification creates a new object; id changes
list, dict, setYesModified in-place; id stays the same
# Immutable example
s = "hello"
old_id = id(s)
s += "!"
print(id(s) == old_id)   # False; s points to a new string

# Mutable example
lst = [1, 2, 3]
old_id = id(lst)
lst.append(4)
print(id(lst) == old_id)  # True; modified in-place

Shallow Copy vs Deep Copy

import copy

original = [1, [2, 3], 4]

# Shallow copy: copies only the outer layer; inner objects are still shared
shallow = copy.copy(original)
shallow = original[:]          # Equivalent

# Modifying an inner object affects the original
shallow[1].append(99)
print(original)    # [1, [2, 3, 99], 4]  ← affected

# Deep copy: fully independent replica
deep = copy.deepcopy(original)
deep[1].append(100)
print(original)    # [1, [2, 3, 99], 4]  ← not affected

Modern Type Annotation Tools (Python 3.9+)

TypedDict

from typing import TypedDict

class Movie(TypedDict):
    title: str
    year: int
    rating: float

m: Movie = {"title": "Inception", "year": 2010, "rating": 8.8}

dataclass

from dataclasses import dataclass, field

@dataclass
class Point:
    x: float
    y: float
    label: str = "origin"
    tags: list[str] = field(default_factory=list)

    def distance(self) -> float:
        return (self.x ** 2 + self.y ** 2) ** 0.5

p = Point(3.0, 4.0, label="A")
print(p.distance())    # 5.0
print(p)               # Point(x=3.0, y=4.0, label='A', tags=[])
dataclass automatically generates __init__, __repr__, __eq__, and other methods, making it the preferred way to define data classes (Python 3.7+). For immutability guarantees, use @dataclass(frozen=True).
Last updated on