Python Complete Cheat Sheet

    A comprehensive, well-organized reference for Python programming


    📋 Table of Contents

    1. 🔤 String Methods
    2. 📝 List Methods
    3. 🗂️ Dictionary Methods
    4. 📦 Tuple & Named Tuples
    5. 🔸 Set & Frozenset
    6. 💾 Bytes & Bytearray
    7. 🔄 List Comprehensions
    8. ⏰ Date & Time
    9. ⚙️ User-Defined Functions
    10. 🔧 Built-in Functions
    11. 📁 File I/O Operations
    12. 🚨 Exception Handling
    13. 🏗️ Classes & OOP
    14. 📦 Modules & Packages
    15. 🔍 Regular Expressions
    16. 📊 Data Structures (Collections)
    17. 🧵 Iterators & Generators
    18. 🎨 Context Managers
    19. ⚡ Performance & Optimization
    20. 🧪 Testing Basics
    21. 🔢 Data Structures & Algorithms

    🔤 String Methods

    🧹 Cleaning & Trimming

    MethodDescriptionExample
    s.strip()Remove whitespace from both ends" hello ".strip()"hello"
    s.strip(chars)Remove specific characters"***hello***".strip("*")"hello"
    s.lstrip()Remove from left side only" hello ".lstrip()"hello "
    s.rstrip()Remove from right side only" hello ".rstrip()" hello"

    ✂️ Splitting & Joining

    MethodDescriptionExample
    s.split()Split on whitespace"a b c".split()['a', 'b', 'c']
    s.split(sep, maxsplit)Split by separator"a,b,c".split(",")['a', 'b', 'c']
    s.splitlines()Split by line breaks"a\nb\nc".splitlines()['a', 'b', 'c']
    sep.join(iterable)Join with separator",".join(['a', 'b', 'c'])"a,b,c"

    🔍 Searching & Testing

    MethodDescriptionExample
    sub in sCheck if substring exists"ell" in "hello"True
    s.startswith(prefix)Check start"hello".startswith("hel")True
    s.endswith(suffix)Check end"hello".endswith("lo")True
    s.find(sub)Find index (returns -1 if not found)"hello".find("e")1
    s.index(sub)Find index (raises error if not found)"hello".index("e")1
    s.count(sub)Count occurrences"hello".count("l")2

    🔁 Modifying & Case

    MethodDescriptionExample
    s.replace(old, new)Replace text"hello".replace("l", "x")"hexxo"
    s.upper()Convert to uppercase"hello".upper()"HELLO"
    s.lower()Convert to lowercase"HELLO".lower()"hello"
    s.capitalize()Capitalize first letter"hello".capitalize()"Hello"
    s.title()Title case"hello world".title()"Hello World"
    s.swapcase()Swap case"Hello".swapcase()"hELLO"

    Validation Methods

    MethodDescriptionExample
    s.isdigit()All digits"123".isdigit()True
    s.isalpha()All letters"abc".isalpha()True
    s.isalnum()Letters and digits"abc123".isalnum()True
    s.islower()All lowercase"hello".islower()True
    s.isupper()All uppercase"HELLO".isupper()True
    s.isspace()All whitespace" ".isspace()True

    🎨 Formatting

    MethodDescriptionExample
    s.center(width)Center string"hi".center(5)" hi "
    s.ljust(width)Left justify"hi".ljust(5)"hi "
    s.rjust(width)Right justify"hi".rjust(5)" hi"
    s.zfill(width)Pad with zeros"42".zfill(5)"00042"

    📝 List Methods

    Adding Elements

    MethodDescriptionExample
    lst.append(item)Add single item to end[1,2].append(3)[1,2,3]
    lst.extend(iterable)Add multiple items[1,2].extend([3,4])[1,2,3,4]
    lst.insert(index, item)Insert at position[1,3].insert(1, 2)[1,2,3]
    lst += [item]Alternative to appendlst += [4]
    lst += iterableAlternative to extendlst += [4,5,6]

    🗑️ Removing Elements

    MethodDescriptionExample
    lst.remove(item)Remove first occurrence[1,2,2,3].remove(2)[1,2,3]
    lst.pop()Remove and return last item[1,2,3].pop() → returns 3, list becomes [1,2]
    lst.pop(index)Remove at index[1,2,3].pop(1) → returns 2, list becomes [1,3]
    lst.clear()Remove all items[1,2,3].clear()[]
    del lst[index]Delete by indexdel lst[1]

    🔍 Searching & Information

    MethodDescriptionExample
    lst.index(item)Find index of item[1,2,3].index(2)1
    lst.count(item)Count occurrences[1,2,2,3].count(2)2
    len(lst)Number of itemslen([1,2,3])3
    item in lstCheck if item exists2 in [1,2,3]True

    🔄 Sorting & Reversing

    MethodDescriptionExample
    lst.sort()Sort in place[3,1,2].sort()[1,2,3]
    lst.sort(reverse=True)Sort descending[1,2,3].sort(reverse=True)[3,2,1]
    lst.reverse()Reverse in place[1,2,3].reverse()[3,2,1]
    sorted(lst)Return new sorted listsorted([3,1,2])[1,2,3]
    list(reversed(lst))Return new reversed listlist(reversed([1,2,3]))[3,2,1]

    ✂️ Slicing

    OperationDescriptionExample
    lst[start:end]Slice from start to end-1[1,2,3,4][1:3][2,3]
    lst[start:]From start to end[1,2,3,4][1:][2,3,4]
    lst[:end]From beginning to end-1[1,2,3,4][:2][1,2]
    lst[::step]Every step-th element[1,2,3,4,5][::2][1,3,5]
    lst[::-1]Reverse copy[1,2,3][::-1][3,2,1]

    🧮 Advanced Operations

    OperationDescriptionExample
    sum(lst)Sum numeric elementssum([1,2,3])6
    max(lst)Maximum valuemax([1,3,2])3
    min(lst)Minimum valuemin([1,3,2])1
    lst * nRepeat list n times[1,2] * 3[1,2,1,2,1,2]
    lst1 + lst2Concatenate lists[1,2] + [3,4][1,2,3,4]

    🗂️ Dictionary Methods

    🔑 Accessing Keys, Values & Items

    MethodDescriptionExample
    d.keys()Get all keys{'a':1, 'b':2}.keys()dict_keys(['a', 'b'])
    d.values()Get all values{'a':1, 'b':2}.values()dict_values([1, 2])
    d.items()Get key-value pairs{'a':1, 'b':2}.items()dict_items([('a', 1), ('b', 2)])

    🔍 Getting & Setting Values

    MethodDescriptionExample
    d[key]Get value (raises KeyError if missing){'a':1}['a']1
    d.get(key, default)Get value safely{'a':1}.get('b', 0)0
    d.setdefault(key, default)Get or set defaultd.setdefault('new', [])
    d[key] = valueSet valued['a'] = 1
    d.update(other)Update with another dictd.update({'b': 2, 'c': 3})

    🗑️ Removing Items

    MethodDescriptionExample
    del d[key]Delete key (raises KeyError if missing)del d['a']
    d.pop(key)Remove and return valued.pop('a') → returns value
    d.pop(key, default)Remove safely with defaultd.pop('missing', None)
    d.popitem()Remove and return arbitrary itemd.popitem()('key', 'value')
    d.clear()Remove all itemsd.clear(){}

    🏗️ Creating Dictionaries

    MethodDescriptionExample
    dict(iterable)From key-value pairsdict([('a',1), ('b',2)]){'a':1, 'b':2}
    dict(zip(keys, values))From separate sequencesdict(zip(['a','b'], [1,2])){'a':1, 'b':2}
    dict.fromkeys(keys, value)From keys with same valuedict.fromkeys(['a','b'], 0){'a':0, 'b':0}
    {k: v for ...}Dictionary comprehension{x: x**2 for x in range(3)}{0:0, 1:1, 2:4}

    🔄 Dictionary Operations

    OperationDescriptionExample
    key in dCheck if key exists'a' in {'a':1, 'b':2}True
    len(d)Number of itemslen({'a':1, 'b':2})2
    d.copy()Shallow copyd2 = d.copy()

    📊 Collections.Counter (Counting)

    from collections import Counter
    
    # Create counter
    counter = Counter(['a', 'b', 'a', 'c', 'b', 'a'])
    # Counter({'a': 3, 'b': 2, 'c': 1})
    
    # Common methods
    counter.most_common(2)      # [('a', 3), ('b', 2)]
    counter['a']                # 3
    counter.update(['a', 'd'])  # Add more elements
    Python

    📦 Tuple & Named Tuples

    📦 Regular Tuples

    🏗️ Creating Tuples

    MethodDescriptionExample
    ()Empty tuplet = ()
    (item,)Single item (comma required)t = (1,)
    (item1, item2, ...)Multiple itemst = (1, 2, 3)
    tuple(iterable)From iterabletuple([1, 2, 3])(1, 2, 3)

    🔍 Tuple Operations

    OperationDescriptionExample
    t[index]Access by index(1, 2, 3)[1]2
    t[start:end]Slicing(1, 2, 3, 4)[1:3](2, 3)
    len(t)Lengthlen((1, 2, 3))3
    item in tMembership test2 in (1, 2, 3)True
    t.count(item)Count occurrences(1, 2, 2, 3).count(2)2
    t.index(item)Find index(1, 2, 3).index(2)1

    🔄 Tuple Operations

    OperationDescriptionExample
    t1 + t2Concatenation(1, 2) + (3, 4)(1, 2, 3, 4)
    t * nRepetition(1, 2) * 3(1, 2, 1, 2, 1, 2)
    a, b, c = tUnpackinga, b, c = (1, 2, 3)

    🏷️ Named Tuples

    from collections import namedtuple
    
    # Define named tuple type
    Point = namedtuple('Point', ['x', 'y'])
    Person = namedtuple('Person', 'name age city')  # Space-separated also works
    
    # Create instances
    p = Point(10, 20)
    person = Person('Alice', 30, 'NYC')
    
    # Access data
    print(p.x, p.y)           # 10 20 (by name)
    print(p[0], p[1])         # 10 20 (by index)
    x, y = p                  # Unpacking
    
    # Methods
    print(p._asdict())        # {'x': 10, 'y': 20}
    print(Point._fields)      # ('x', 'y')
    p2 = p._replace(x=15)     # Point(x=15, y=20)
    p3 = Point._make([5, 25]) # Point(x=5, y=25)
    Python

    🔸 Set & Frozenset

    🔸 Set Operations

    🏗️ Creating Sets

    MethodDescriptionExample
    set()Empty sets = set()
    {item1, item2, ...}Set literals = {1, 2, 3}
    set(iterable)From iterableset([1, 2, 2, 3]){1, 2, 3}

    Adding & Removing

    MethodDescriptionExample
    s.add(item)Add single items.add(4)
    s.update(iterable)Add multiple itemss.update([4, 5, 6])
    s.remove(item)Remove (raises KeyError if missing)s.remove(3)
    s.discard(item)Remove safelys.discard(10) # No error if missing
    s.pop()Remove arbitrary itemitem = s.pop()
    s.clear()Remove all itemss.clear()

    🧮 Set Mathematics

    OperationOperatorMethodDescription
    Union`s1 \s2`s1.union(s2)
    Intersections1 & s2s1.intersection(s2)Common elements
    Differences1 - s2s1.difference(s2)Elements in s1 but not s2
    Symmetric Diffs1 ^ s2s1.symmetric_difference(s2)Elements in either, but not both

    Set Comparisons

    OperationOperatorMethodDescription
    Subsets1 <= s2s1.issubset(s2)All elements of s1 in s2
    Proper subsets1 < s2N/ASubset but not equal
    Supersets1 >= s2s1.issuperset(s2)s1 contains all elements of s2
    DisjointN/As1.isdisjoint(s2)No common elements
    # Examples
    s1 = {1, 2, 3}
    s2 = {3, 4, 5}
    
    print(s1 | s2)    # {1, 2, 3, 4, 5} - Union
    print(s1 & s2)    # {3} - Intersection  
    print(s1 - s2)    # {1, 2} - Difference
    print(s1 ^ s2)    # {1, 2, 4, 5} - Symmetric difference
    Python

    ❄️ Frozenset (Immutable Set)

    fs = frozenset([1, 2, 3])
    # Supports all read operations and set math
    # Cannot use: add, remove, discard, pop, clear, update
    Python

    💾 Bytes & Bytearray

    💾 Bytes (Immutable)

    🏗️ Creating Bytes

    MethodDescriptionExample
    b'string'Bytes literalb'Hello'
    bytes(iterable)From integers 0-255bytes([72, 101, 108, 108, 111])b'Hello'
    str.encode(encoding)From string'Hello'.encode('utf-8')b'Hello'
    bytes.fromhex(hex_string)From hexbytes.fromhex('48656c6c6f')b'Hello'

    🔄 Bytes Operations

    OperationDescriptionExample
    b[index]Access byte (returns int)b'Hello'[0]72
    b[start:end]Slicingb'Hello'[1:4]b'ell'
    len(b)Lengthlen(b'Hello')5
    b1 + b2Concatenationb'Hello' + b' World'b'Hello World'
    b * nRepetitionb'Hi' * 3b'HiHiHi'

    🔄 Converting from Bytes

    MethodDescriptionExample
    b.decode(encoding)To stringb'Hello'.decode('utf-8')'Hello'
    b.hex()To hex stringb'Hello'.hex()'48656c6c6f'
    list(b)To list of integerslist(b'Hi')[72, 105]

    🔄 Bytearray (Mutable)

    🏗️ Creating Bytearrays

    MethodDescriptionExample
    bytearray()Empty bytearrayba = bytearray()
    bytearray(size)Filled with zerosbytearray(5) → 5 zero bytes
    bytearray(iterable)From integersbytearray([72, 101, 108, 108, 111])
    bytearray(string, encoding)From stringbytearray('Hello', 'utf-8')

    ✏️ Modifying Bytearrays

    MethodDescriptionExample
    ba[index] = valueModify byteba[0] = 74
    ba.append(byte)Add byte to endba.append(33) # Add ‘!’
    ba.extend(iterable)Add multiple bytesba.extend(b' World')
    ba.insert(index, byte)Insert at positionba.insert(0, 72)
    ba.remove(byte)Remove first occurrenceba.remove(72)
    ba.pop(index)Remove and returnitem = ba.pop()
    ba.clear()Remove allba.clear()
    # Example usage
    ba = bytearray(b'Hello')
    ba[0] = 74              # Change 'H' to 'J'
    ba.append(33)           # Add '!'
    ba.extend(b' World')    # Add more text
    print(ba.decode())      # 'Jello! World'
    Python

    🔄 List Comprehensions

    🧱 Basic Syntax

    # Basic pattern
    [expression for item in iterable]
    
    # With condition
    [expression for item in iterable if condition]
    
    # With conditional expression (ternary)
    [expr1 if condition else expr2 for item in iterable]
    Python

    🎯 Simple Examples

    PatternExampleResult
    Transform[x * 2 for x in range(5)][0, 2, 4, 6, 8]
    Filter[x for x in range(10) if x % 2 == 0][0, 2, 4, 6, 8]
    Transform + Filter[x**2 for x in range(10) if x % 2 == 0][0, 4, 16, 36, 64]
    Conditional[x if x > 0 else -x for x in [-2, -1, 0, 1, 2]][2, 1, 0, 1, 2]

    🔗 Nested Loops

    # Cartesian product
    [(x, y) for x in [1, 2] for y in [3, 4]]
    # Result: [(1, 3), (1, 4), (2, 3), (2, 4)]
    
    # Flatten 2D list
    matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    flattened = [num for row in matrix for num in row]
    # Result: [1, 2, 3, 4, 5, 6, 7, 8, 9]
    Python

    🎭 Working with Strings

    # Remove vowels
    [char for char in "hello world" if char not in "aeiou"]
    # Result: ['h', 'l', 'l', ' ', 'w', 'r', 'l', 'd']
    
    # Word lengths
    [len(word) for word in "the quick brown fox".split()]
    # Result: [3, 5, 5, 3]
    
    # Uppercase words
    [word.upper() for word in ["apple", "banana", "cherry"]]
    # Result: ['APPLE', 'BANANA', 'CHERRY']
    Python

    🧮 Mathematical Operations

    # Squares
    [x**2 for x in range(1, 6)]
    # Result: [1, 4, 9, 16, 25]
    
    # Even squares only
    [x**2 for x in range(1, 11) if x % 2 == 0]
    # Result: [4, 16, 36, 64, 100]
    
    # Pythagorean triples
    [(a, b, c) for a in range(1, 11) for b in range(a, 11) for c in range(b, 11) if a**2 + b**2 == c**2]
    # Result: [(3, 4, 5), (6, 8, 10)]
    Python

    🗂️ Other Comprehensions

    Set Comprehension

    {x**2 for x in range(5)}
    # Result: {0, 1, 4, 9, 16}
    Python

    Dictionary Comprehension

    {x: x**2 for x in range(5)}
    # Result: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
    
    # From two lists
    keys = ['a', 'b', 'c']
    values = [1, 2, 3]
    {k: v for k, v in zip(keys, values)}
    # Result: {'a': 1, 'b': 2, 'c': 3}
    Python

    Generator Expression (Memory Efficient)

    # Generator (lazy evaluation)
    squares_gen = (x**2 for x in range(1000000))
    
    # Only computes values when needed
    for square in squares_gen:
        if square > 100:
            break
    Python

    Date & Time

    📅 datetime Module

    🏗️ Creating Date/Time Objects

    from datetime import date, time, datetime, timedelta
    
    # Current date/time
    today = date.today()                    # Current date
    now = datetime.now()                    # Current local datetime
    utc_now = datetime.utcnow()            # Current UTC datetime
    
    # Specific date/time
    specific_date = date(2025, 10, 25)
    specific_time = time(14, 30, 45)        # 2:30:45 PM
    specific_datetime = datetime(2025, 10, 25, 14, 30, 45)
    Python

    🎨 Formatting & Parsing

    dt = datetime(2025, 10, 25, 14, 30, 45)
    
    # Format to string
    dt.strftime('%Y-%m-%d %H:%M:%S')        # '2025-10-25 14:30:45'
    dt.strftime('%B %d, %Y')               # 'October 25, 2025'
    dt.isoformat()                         # '2025-10-25T14:30:45'
    
    # Parse from string
    datetime.strptime('2025-10-25', '%Y-%m-%d')
    datetime.fromisoformat('2025-10-25T14:30:45')
    Python

    📝 Common Format Codes

    CodeMeaningExample
    %Y4-digit year2025
    %mMonth (01-12)10
    %dDay (01-31)25
    %HHour (00-23)14
    %MMinute (00-59)30
    %SSecond (00-59)45
    %AFull weekdaySaturday
    %BFull monthOctober
    %aShort weekdaySat
    %bShort monthOct

    🧮 Date Arithmetic

    from datetime import timedelta
    
    # Add/subtract time
    future = datetime.now() + timedelta(days=7, hours=3, minutes=30)
    past = datetime.now() - timedelta(weeks=2)
    
    # Difference between dates
    dt1 = datetime(2025, 10, 25)
    dt2 = datetime(2025, 11, 1)
    diff = dt2 - dt1
    print(diff.days)              # 7
    print(diff.total_seconds())   # 604800.0
    
    # Replace components
    modified = dt1.replace(year=2026, month=12)
    Python

    🔍 Extracting Components

    dt = datetime.now()
    print(dt.year, dt.month, dt.day)        # Year, month, day
    print(dt.hour, dt.minute, dt.second)    # Hour, minute, second
    print(dt.weekday())                     # Monday=0, Sunday=6
    print(dt.isoweekday())                  # Monday=1, Sunday=7
    Python

    🏹 Arrow Library (Third-party)

    Install with: pip install arrow

    import arrow
    
    # Create arrow objects
    now = arrow.now()                       # Current local time
    utc = arrow.utcnow()                   # Current UTC time
    past = arrow.get('2025-10-25')         # From string
    timestamp = arrow.get(1698230400)      # From timestamp
    
    # Formatting
    now.format('YYYY-MM-DD HH:mm:ss')      # Custom format
    now.isoformat()                        # ISO format
    now.humanize()                         # "just now", "2 hours ago"
    
    # Timezone handling
    utc_time = now.to('UTC')
    eastern = now.to('US/Eastern')
    
    # Arithmetic
    future = now.shift(days=7, hours=3)
    past = now.shift(months=-2)
    
    # Ranges
    for dt in arrow.Arrow.range('hour', start, end):
        print(dt)
    Python

    📋 Quick Comparison

    Featuredatetimearrow
    Parsingstrptime()get()
    Formattingstrftime()format()
    TimezonesManual (pytz)Built-in
    Arithmetictimedeltashift()
    Human readableManualhumanize()
    Ease of useComplexSimple

    ⚙️ User-Defined Functions

    🏗️ Function Basics

    # Basic function
    def greet(name):
        """Greet a person by name."""
        return f"Hello, {name}!"
    
    # Function with default parameters
    def power(base, exponent=2):
        return base ** exponent
    
    # Multiple return values
    def divmod_custom(a, b):
        quotient = a // b
        remainder = a % b
        return quotient, remainder  # Returns tuple
    
    # Call functions
    message = greet("Alice")
    result = power(3)           # Uses default exponent=2
    result = power(3, 4)        # Uses exponent=4
    q, r = divmod_custom(10, 3) # Unpacking return values
    Python

    📦 Parameter Types

    def flexible_function(a, b=10, *args, **kwargs):
        """
        a: Required positional argument
        b: Optional argument with default value
        *args: Variable number of positional arguments (tuple)
        **kwargs: Variable number of keyword arguments (dict)
        """
        print(f"a={a}, b={b}")
        print(f"args={args}")
        print(f"kwargs={kwargs}")
    
    # Different ways to call:
    flexible_function(1)                           # a=1, b=10, args=(), kwargs={}
    flexible_function(1, 20)                       # a=1, b=20, args=(), kwargs={}
    flexible_function(1, 20, 30, 40)              # a=1, b=20, args=(30, 40), kwargs={}
    flexible_function(1, 20, 30, x=100, y=200)    # a=1, b=20, args=(30,), kwargs={'x': 100, 'y': 200}
    Python

    🔄 Advanced Function Features

    Lambda Functions (Anonymous)

    # Simple lambda
    square = lambda x: x ** 2
    add = lambda a, b: a + b
    
    # Using with built-in functions
    numbers = [1, 2, 3, 4, 5]
    squared = list(map(lambda x: x**2, numbers))        # [1, 4, 9, 16, 25]
    evens = list(filter(lambda x: x % 2 == 0, numbers)) # [2, 4]
    
    # Sorting with lambda
    students = [('Alice', 85), ('Bob', 90), ('Charlie', 78)]
    students.sort(key=lambda student: student[1])       # Sort by grade
    Python

    Closures

    def make_multiplier(factor):
        """Returns a function that multiplies by factor."""
        def multiplier(number):
            return number * factor
        return multiplier
    
    # Create specialized functions
    double = make_multiplier(2)
    triple = make_multiplier(3)
    
    print(double(5))    # 10
    print(triple(5))    # 15
    Python

    Decorators

    def timer(func):
        """Decorator to measure function execution time."""
        import time
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print(f"{func.__name__} took {end - start:.4f} seconds")
            return result
        return wrapper
    
    @timer
    def slow_function():
        import time
        time.sleep(1)
        return "Done!"
    
    # When called, prints execution time
    result = slow_function()
    Python

    🎯 Type Hints (Python 3.5+)

    from typing import List, Dict, Tuple, Optional, Union
    
    def process_data(
        numbers: List[int], 
        multiplier: float = 1.0
        ) -> List[float]:
        """Process a list of numbers."""
        return [n * multiplier for n in numbers]
    
    def get_user_info(user_id: int) -> Optional[Dict[str, str]]:
        """Get user info, returns None if user not found."""
        # Implementation here
        pass
    
    def flexible_input(value: Union[int, str]) -> str:
        """Accept either int or string."""
        return str(value)
    Python

    🔄 Higher-Order Functions

    from functools import reduce
    import operator
    
    numbers = [1, 2, 3, 4, 5]
    
    # map: Apply function to each element
    doubled = list(map(lambda x: x * 2, numbers))
    # [2, 4, 6, 8, 10]
    
    # filter: Keep elements that match condition  
    evens = list(filter(lambda x: x % 2 == 0, numbers))
    # [2, 4]
    
    # reduce: Combine all elements into single value
    total = reduce(lambda a, b: a + b, numbers)
    # 15 (equivalent to sum(numbers))
    
    product = reduce(operator.mul, numbers)
    # 120 (1 * 2 * 3 * 4 * 5)
    Python

    🔧 Built-in Functions

    🔄 Type Conversion

    FunctionPurposeExample
    int(x)Convert to integerint('42')42
    float(x)Convert to floatfloat('3.14')3.14
    str(x)Convert to stringstr(42)'42'
    bool(x)Convert to booleanbool(0)False
    list(x)Convert to listlist('abc')['a', 'b', 'c']
    tuple(x)Convert to tupletuple([1, 2, 3])(1, 2, 3)
    set(x)Convert to setset([1, 1, 2]){1, 2}
    dict(x)Convert to dictionarydict([('a', 1), ('b', 2)]){'a': 1, 'b': 2}

    🧮 Mathematical Functions

    FunctionPurposeExample
    abs(x)Absolute valueabs(-5)5
    round(x, n)Round to n decimalsround(3.14159, 2)3.14
    pow(x, y)Power (x^y)pow(2, 3)8
    min(iterable)Minimum valuemin([3, 1, 4])1
    max(iterable)Maximum valuemax([3, 1, 4])4
    sum(iterable)Sum of valuessum([1, 2, 3])6
    divmod(a, b)Quotient and remainderdivmod(10, 3)(3, 1)

    📊 Sequence Operations

    FunctionPurposeExample
    len(x)Length of sequencelen([1, 2, 3])3
    sorted(iterable)Return sorted listsorted([3, 1, 2])[1, 2, 3]
    reversed(seq)Reverse iteratorlist(reversed([1, 2, 3]))[3, 2, 1]
    enumerate(iterable)Add index numberslist(enumerate(['a', 'b']))[(0, 'a'), (1, 'b')]
    zip(*iterables)Combine iterableslist(zip([1, 2], ['a', 'b']))[(1, 'a'), (2, 'b')]
    all(iterable)True if all are truthyall([1, 2, 3])True
    any(iterable)True if any is truthyany([0, 1, 0])True

    🔍 Inspection Functions

    FunctionPurposeExample
    type(x)Get object typetype(42)<class 'int'>
    isinstance(obj, class)Check typeisinstance(42, int)True
    id(x)Object memory addressid(42)
    dir(x)List object attributesdir(str)
    vars(x)Object’s dictvars(obj)
    callable(x)Check if callablecallable(len)True
    hasattr(obj, name)Check if attribute existshasattr([], 'append')True
    getattr(obj, name)Get attribute valuegetattr([], 'append')

    🔄 Functional Programming

    FunctionPurposeExample
    map(func, iterable)Apply function to each itemlist(map(str.upper, ['a', 'b']))['A', 'B']
    filter(func, iterable)Filter itemslist(filter(lambda x: x > 0, [-1, 0, 1]))[1]
    iter(obj)Create iteratorit = iter([1, 2, 3])
    next(iterator)Get next itemnext(it)1
    range(start, stop, step)Generate numberslist(range(0, 10, 2))[0, 2, 4, 6, 8]

    💻 Input/Output

    FunctionPurposeExample
    print(*objects)Print to consoleprint("Hello", "World")
    input(prompt)Get user inputname = input("Name: ")
    open(file, mode)Open filef = open('file.txt', 'r')
    format(value, spec)Format valueformat(3.14159, '.2f')'3.14'

    🔢 Number Base Conversions

    FunctionPurposeExample
    bin(x)Binary representationbin(5)'0b101'
    oct(x)Octal representationoct(8)'0o10'
    hex(x)Hexadecimal representationhex(255)'0xff'
    chr(x)Character from Unicode codechr(65)'A'
    ord(c)Unicode code from characterord('A')65

    🔧 Advanced

    FunctionPurposeExample
    eval(expression)Evaluate string as codeeval('2 + 3')5
    exec(code)Execute code stringexec('x = 5; print(x)')
    compile(source, filename, mode)Compile codecompile('x=1', '', 'exec')
    globals()Global variables dictglobals()['x']
    locals()Local variables dictlocals()
    help(obj)Interactive helphelp(str)

    💡 Practical Examples

    Working with Files

    # Reading a file
    with open('data.txt', 'r') as f:
        content = f.read()
        lines = f.readlines()
    
    # Writing to a file  
    with open('output.txt', 'w') as f:
        f.write('Hello, World!')
    Python

    Data Processing Pipeline

    numbers = range(1, 11)
    
    # Chain operations
    result = list(
        map(lambda x: x ** 2,           # Square each number
            filter(lambda x: x % 2 == 0,  # Keep only even numbers
                   numbers)))             # [4, 16, 36, 64, 100]
    
    # Or using comprehension (more Pythonic)
    result = [x**2 for x in numbers if x % 2 == 0]
    Python

    Using enumerate and zip

    # enumerate: Add index to items
    names = ['Alice', 'Bob', 'Charlie']
    for i, name in enumerate(names, start=1):
        print(f"{i}. {name}")
    # Output: 1. Alice, 2. Bob, 3. Charlie
    
    # zip: Combine multiple iterables
    first_names = ['John', 'Jane', 'Bob']
    last_names = ['Doe', 'Smith', 'Johnson']  
    ages = [30, 25, 35]
    
    for first, last, age in zip(first_names, last_names, ages):
        print(f"{first} {last} is {age} years old")
    Python

    🎯 Quick Reference Summary

    🔤 String Essentials

    • Clean: strip(), lstrip(), rstrip()
    • Split/Join: split(), join()
    • Search: find(), startswith(), endswith(), in
    • Modify: replace(), upper(), lower(), title()
    • Validate: isdigit(), isalpha(), isalnum()

    📝 List Essentials

    • Add: append(), extend(), insert(), +=
    • Remove: remove(), pop(), clear(), del
    • Info: len(), count(), index(), in
    • Order: sort(), reverse(), sorted(), reversed()

    🗂️ Dict Essentials

    • Access: [], get(), keys(), values(), items()
    • Modify: update(), setdefault(), pop(), clear()
    • Create: dict(), dict.fromkeys(), {k:v for ...}

    🔸 Set Essentials

    • Math: | (union), & (intersection), - (difference), ^ (symmetric diff)
    • Test: <= (subset), >= (superset), isdisjoint()
    • Modify: add(), update(), remove(), discard()

    🔧 Built-in Essentials

    • Convert: int(), str(), list(), dict(), set()
    • Math: sum(), min(), max(), abs(), round()
    • Iterate: range(), enumerate(), zip(), map(), filter()
    • Inspect: len(), type(), isinstance(), dir()

    📁 File I/O Operations

    📖 Reading Files

    # Read entire file
    with open('file.txt', 'r') as f:
        content = f.read()          # Entire file as string
    
    with open('file.txt', 'r') as f:
        lines = f.readlines()       # List of lines (with \n)
    
    with open('file.txt', 'r') as f:
        lines = f.read().splitlines()  # List of lines (without \n)
    
    # Read line by line (memory efficient)
    with open('file.txt', 'r') as f:
        for line in f:
            print(line.strip())     # Process each line
    
    # Read specific number of characters
    with open('file.txt', 'r') as f:
        chunk = f.read(100)         # Read first 100 characters
    Python

    ✏️ Writing Files

    # Write (overwrites existing content)
    with open('file.txt', 'w') as f:
        f.write('Hello, World!')
        f.write('\nSecond line')
    
    # Append to existing file
    with open('file.txt', 'a') as f:
        f.write('\nAppended line')
    
    # Write multiple lines
    lines = ['Line 1\n', 'Line 2\n', 'Line 3\n']
    with open('file.txt', 'w') as f:
        f.writelines(lines)
    
    # Write with print function
    with open('file.txt', 'w') as f:
        print('Hello', 'World', file=f)
    Python

    🗂️ File Modes & Types

    ModeDescriptionExample Use
    'r'Read (default)Reading text files
    'w'Write (truncates)Creating new files
    'a'AppendAdding to log files
    'r+'Read & WriteUpdating files
    'rb'Read binaryImages, videos
    'wb'Write binarySaving binary data

    📂 Working with Paths

    import os
    from pathlib import Path
    
    # os.path (traditional)
    file_path = os.path.join('folder', 'subfolder', 'file.txt')
    directory = os.path.dirname(file_path)
    filename = os.path.basename(file_path)
    name, ext = os.path.splitext(filename)
    
    # pathlib (modern, recommended)
    path = Path('folder') / 'subfolder' / 'file.txt'
    print(path.parent)          # folder/subfolder
    print(path.name)            # file.txt
    print(path.stem)            # file
    print(path.suffix)          # .txt
    print(path.exists())        # True/False
    print(path.is_file())       # True/False
    print(path.is_dir())        # True/False
    Python

    📁 Directory Operations

    import os
    import shutil
    from pathlib import Path
    
    # Create directories
    os.makedirs('path/to/directory', exist_ok=True)
    Path('path/to/directory').mkdir(parents=True, exist_ok=True)
    
    # List directory contents
    files = os.listdir('.')
    files = list(Path('.').iterdir())
    
    # Walk through directory tree
    for root, dirs, files in os.walk('.'):
        for file in files:
            file_path = os.path.join(root, file)
            print(file_path)
    
    # Copy, move, delete
    shutil.copy2('source.txt', 'destination.txt')      # Copy file
    shutil.copytree('source_dir', 'dest_dir')          # Copy directory
    shutil.move('old_location', 'new_location')        # Move/rename
    os.remove('file.txt')                              # Delete file
    shutil.rmtree('directory')                         # Delete directory
    Python

    🔍 File Information

    import os
    from pathlib import Path
    
    # File stats
    stat_info = os.stat('file.txt')
    path = Path('file.txt')
    
    print(path.stat().st_size)          # File size in bytes
    print(path.stat().st_mtime)         # Last modified timestamp
    print(os.path.getsize('file.txt'))  # File size
    print(os.path.getmtime('file.txt')) # Last modified time
    Python

    🚨 Exception Handling

    🎯 Basic Try-Except

    # Basic exception handling
    try:
        result = 10 / 0
    except ZeroDivisionError:
        print("Cannot divide by zero!")
    
    # Multiple exceptions
    try:
        value = int(input("Enter a number: "))
        result = 10 / value
    except ValueError:
        print("Invalid number format!")
    except ZeroDivisionError:
        print("Cannot divide by zero!")
    
    # Catch multiple exceptions at once
    try:
        # risky code
        pass
    except (ValueError, TypeError, KeyError) as e:
        print(f"Error occurred: {e}")
    Python

    🔧 Advanced Exception Handling

    # Complete try-except-else-finally block
    try:
        file = open('data.txt', 'r')
        data = file.read()
        number = int(data)
    except FileNotFoundError:
        print("File not found!")
    except ValueError:
        print("Invalid number in file!")
    else:
        # Runs only if no exception occurred
        print("File processed successfully!")
        result = number * 2
    finally:
        # Always runs (cleanup code)
        if 'file' in locals():
            file.close()
        print("Cleanup completed")
    Python

    🚀 Raising Exceptions

    # Raise built-in exceptions
    def validate_age(age):
        if age < 0:
            raise ValueError("Age cannot be negative")
        if age > 150:
            raise ValueError("Age seems unrealistic")
        return age
    
    # Custom exceptions
    class CustomError(Exception):
        """Custom exception for specific use cases."""
        pass
    
    class ValidationError(Exception):
        """Raised when validation fails."""
        def __init__(self, message, error_code=None):
            super().__init__(message)
            self.error_code = error_code
    
    def process_data(data):
        if not data:
            raise ValidationError("Data cannot be empty", error_code=100)
    Python

    📝 Common Built-in Exceptions

    ExceptionWhen it occursExample
    ValueErrorInvalid value for typeint('abc')
    TypeErrorWrong type'hello' + 5
    KeyErrorMissing dictionary keydict['missing_key']
    IndexErrorList index out of range[1,2,3][5]
    FileNotFoundErrorFile doesn’t existopen('missing.txt')
    AttributeErrorMissing attribute/method'hello'.missing_method()
    ZeroDivisionErrorDivision by zero10 / 0
    ImportErrorCannot import moduleimport non_existent_module

    🛡️ Exception Best Practices

    # Good: Be specific about exceptions
    try:
        with open('config.json', 'r') as f:
            config = json.load(f)
    except FileNotFoundError:
        config = {}  # Use default config
    except json.JSONDecodeError:
        raise ValueError("Invalid JSON in config file")
    
    # Good: Use context managers for resource management
    try:
        with open('file.txt', 'r') as f:
            content = f.read()
    except FileNotFoundError:
        print("File not found")
    # File automatically closed even if exception occurs
    
    # Good: Log exceptions for debugging
    import logging
    
    try:
        risky_operation()
    except Exception as e:
        logging.error(f"Operation failed: {e}", exc_info=True)
        raise  # Re-raise the exception
    Python

    🏗️ Classes & OOP

    📦 Basic Class Definition

    class Person:
        # Class variable (shared by all instances)
        species = "Homo sapiens"
    
        def __init__(self, name, age):
            # Instance variables
            self.name = name
            self.age = age
            self._email = None  # Protected (convention)
            self.__ssn = None   # Private (name mangling)
    
        # Instance method
        def introduce(self):
            return f"Hi, I'm {self.name} and I'm {self.age} years old"
    
        # Instance method with parameters
        def have_birthday(self):
            self.age += 1
            return f"Happy birthday! Now I'm {self.age}"
    
        # Property (getter)
        @property
        def email(self):
            return self._email
    
        # Property setter
        @email.setter
        def email(self, value):
            if '@' in value:
                self._email = value
            else:
                raise ValueError("Invalid email format")
    
        # String representation
        def __str__(self):
            return f"Person(name='{self.name}', age={self.age})"
    
        def __repr__(self):
            return f"Person('{self.name}', {self.age})"
    
    # Usage
    person = Person("Alice", 30)
    print(person.introduce())       # Hi, I'm Alice and I'm 30 years old
    person.email = "alice@email.com"
    print(person.email)             # alice@email.com
    Python

    🧬 Inheritance

    class Animal:
        def __init__(self, name, species):
            self.name = name
            self.species = species
    
        def make_sound(self):
            return "Some generic animal sound"
    
        def info(self):
            return f"{self.name} is a {self.species}"
    
    class Dog(Animal):
        def __init__(self, name, breed):
            super().__init__(name, "Canis lupus")  # Call parent constructor
            self.breed = breed
    
        # Override parent method
        def make_sound(self):
            return "Woof!"
    
        # Add new method
        def fetch(self):
            return f"{self.name} is fetching the ball!"
    
    class Cat(Animal):
        def __init__(self, name, indoor=True):
            super().__init__(name, "Felis catus")
            self.indoor = indoor
    
        def make_sound(self):
            return "Meow!"
    
    # Usage
    dog = Dog("Buddy", "Golden Retriever")
    cat = Cat("Whiskers", indoor=True)
    
    print(dog.make_sound())     # Woof!
    print(cat.info())           # Whiskers is a Felis catus
    print(dog.fetch())          # Buddy is fetching the ball!
    Python

    🔧 Special Methods (Magic Methods)

    class Vector:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __str__(self):
            return f"Vector({self.x}, {self.y})"
    
        def __repr__(self):
            return f"Vector({self.x}, {self.y})"
    
        def __add__(self, other):
            return Vector(self.x + other.x, self.y + other.y)
    
        def __sub__(self, other):
            return Vector(self.x - other.x, self.y - other.y)
    
        def __mul__(self, scalar):
            return Vector(self.x * scalar, self.y * scalar)
    
        def __eq__(self, other):
            return self.x == other.x and self.y == other.y
    
        def __len__(self):
            return int((self.x**2 + self.y**2)**0.5)
    
        def __getitem__(self, index):
            if index == 0:
                return self.x
            elif index == 1:
                return self.y
            else:
                raise IndexError("Vector index out of range")
    
    # Usage
    v1 = Vector(2, 3)
    v2 = Vector(1, 4)
    v3 = v1 + v2            # Vector(3, 7)
    v4 = v1 * 2             # Vector(4, 6)
    print(v1 == v2)         # False
    print(v1[0])            # 2 (accessing like a list)
    Python

    🏭 Class Methods and Static Methods

    class MathUtils:
        pi = 3.14159
    
        def __init__(self, precision=2):
            self.precision = precision
    
        @classmethod
        def circle_area(cls, radius):
            """Class method - works with class, not instance"""
            return cls.pi * radius * radius
    
        @staticmethod
        def add(a, b):
            """Static method - independent function grouped in class"""
            return a + b
    
        @classmethod
        def from_string(cls, math_string):
            """Alternative constructor"""
            precision = len(math_string.split('.')[-1])
            return cls(precision)
    
    # Usage
    area = MathUtils.circle_area(5)         # Can call without creating instance
    result = MathUtils.add(10, 20)          # Static method
    math_obj = MathUtils.from_string("3.14159")  # Alternative constructor
    Python

    🎭 Abstract Base Classes

    from abc import ABC, abstractmethod
    
    class Shape(ABC):
        @abstractmethod
        def area(self):
            pass
    
        @abstractmethod
        def perimeter(self):
            pass
    
        # Concrete method (can be used by subclasses)
        def description(self):
            return f"This is a shape with area {self.area()}"
    
    class Rectangle(Shape):
        def __init__(self, width, height):
            self.width = width
            self.height = height
    
        def area(self):
            return self.width * self.height
    
        def perimeter(self):
            return 2 * (self.width + self.height)
    
    # Cannot instantiate ABC directly
    # shape = Shape()  # This would raise TypeError
    
    rect = Rectangle(5, 3)
    print(rect.area())          # 15
    print(rect.description())   # This is a shape with area 15
    Python

    📦 Modules & Packages

    📥 Importing Modules

    # Different ways to import
    import math                     # Import entire module
    import math as m               # Import with alias
    from math import sqrt, pi      # Import specific functions
    from math import *             # Import all (not recommended)
    
    # Usage
    print(math.sqrt(16))           # 4.0
    print(m.pi)                    # 3.141592653589793
    print(sqrt(25))                # 5.0
    Python

    📦 Creating Your Own Module

    # File: my_utils.py
    """
    A utility module with helpful functions.
    """
    
    def greet(name):
        """Greet a person by name."""
        return f"Hello, {name}!"
    
    def factorial(n):
        """Calculate factorial of n."""
        if n <= 1:
            return 1
        return n * factorial(n - 1)
    
    # Module-level variable
    VERSION = "1.0.0"
    
    # Code that runs when module is executed directly
    if __name__ == "__main__":
        print("This module is being run directly")
        print(f"Version: {VERSION}")
    Python
    # File: main.py - Using the module
    import my_utils
    from my_utils import greet
    
    print(my_utils.greet("Alice"))      # Hello, Alice!
    print(greet("Bob"))                 # Hello, Bob!
    print(my_utils.factorial(5))        # 120
    print(my_utils.VERSION)             # 1.0.0
    Python

    📁 Creating Packages

    my_package/
        __init__.py
        math_utils.py
        string_utils.py
        subpackage/
            __init__.py
            advanced.py
    Python
    # File: my_package/__init__.py
    """
    My custom package for utilities.
    """
    from .math_utils import add, multiply
    from .string_utils import capitalize_words
    
    __version__ = "1.0.0"
    __all__ = ['add', 'multiply', 'capitalize_words']
    Python
    # File: my_package/math_utils.py
    def add(a, b):
        return a + b
    
    def multiply(a, b):
        return a * b
    Python
    # Usage
    from my_package import add, multiply
    import my_package.string_utils as su
    
    result = add(5, 3)              # 8
    text = su.capitalize_words("hello world")
    Python

    🔄 Module Search Path & Reloading

    import sys
    import importlib
    
    # View module search paths
    print(sys.path)
    
    # Add custom path
    sys.path.append('/path/to/my/modules')
    
    # Reload a module (useful in development)
    import my_module
    importlib.reload(my_module)
    
    # Check if module is available
    try:
        import optional_module
        HAS_OPTIONAL = True
    except ImportError:
        HAS_OPTIONAL = False
    Python
    import os           # Operating system interface
    import sys          # System-specific parameters
    import json         # JSON encoder/decoder
    import datetime     # Date and time handling
    import random       # Generate random numbers
    import re           # Regular expressions
    import urllib.request  # URL handling
    import sqlite3      # SQLite database
    import csv          # CSV file reading/writing
    import collections  # Specialized container datatypes
    import itertools    # Iterator functions
    import functools    # Higher-order functions
    import pathlib      # Object-oriented filesystem paths
    import logging      # Logging facility
    import argparse     # Command-line argument parsing
    import configparser # Configuration file parser
    Python

    🔍 Regular Expressions

    🎯 Basic Pattern Matching

    import re
    
    text = "The quick brown fox jumps over the lazy dog"
    
    # Basic search
    match = re.search(r'fox', text)
    if match:
        print(f"Found 'fox' at position {match.start()}")
    
    # Find all matches
    matches = re.findall(r'\b\w{5}\b', text)  # All 5-letter words
    print(matches)  # ['quick', 'brown', 'jumps']
    
    # Split by pattern
    words = re.split(r'\s+', text)  # Split by whitespace
    print(words)
    Python

    🔧 Common Regex Patterns

    PatternMeaningExample
    .Any character except newlinea.c matches abc, a5c
    *0 or more repetitionsab* matches a, ab, abbb
    +1 or more repetitionsab+ matches ab, abbb
    ?0 or 1 repetitionab? matches a, ab
    {n}Exactly n repetitionsa{3} matches aaa
    {n,m}n to m repetitionsa{2,4} matches aa, aaa, aaaa
    ^Start of string^hello matches start
    $End of stringworld$ matches end
    \dAny digit\d+ matches 123
    \wWord character\w+ matches hello_123
    \sWhitespace\s+ matches spaces/tabs
    [abc]Character class[aeiou] matches vowels
    [^abc]Negated class[^0-9] matches non-digits

    📧 Practical Examples

    import re
    
    # Email validation
    email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    def is_valid_email(email):
        return bool(re.match(email_pattern, email))
    
    # Phone number extraction
    phone_pattern = r'\b\d{3}-\d{3}-\d{4}\b'
    text = "Call me at 555-123-4567 or 555-987-6543"
    phone_numbers = re.findall(phone_pattern, text)
    
    # URL extraction
    url_pattern = r'https?://[^\s]+'
    text = "Visit https://example.com or http://test.org"
    urls = re.findall(url_pattern, text)
    
    # Replace patterns
    text = "The price is $25.99 and $15.50"
    # Replace prices with "PRICE"
    cleaned = re.sub(r'\$\d+\.\d{2}', 'PRICE', text)
    print(cleaned)  # "The price is PRICE and PRICE"
    Python

    🔄 Advanced Regex Features

    import re
    
    # Groups and capturing
    pattern = r'(\d{4})-(\d{2})-(\d{2})'  # YYYY-MM-DD
    text = "Today is 2025-10-25"
    match = re.search(pattern, text)
    if match:
        year, month, day = match.groups()
        print(f"Year: {year}, Month: {month}, Day: {day}")
    
    # Named groups
    pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
    match = re.search(pattern, text)
    if match:
        print(match.groupdict())  # {'year': '2025', 'month': '10', 'day': '25'}
    
    # Lookahead and lookbehind
    # Positive lookahead: match X if followed by Y
    pattern = r'\d+(?= dollars)'  # Numbers followed by " dollars"
    text = "I have 100 dollars and 50 cents"
    matches = re.findall(pattern, text)  # ['100']
    
    # Case-insensitive matching
    pattern = r'python'
    text = "I love Python programming"
    match = re.search(pattern, text, re.IGNORECASE)
    Python

    🛠️ Regex Compilation and Performance

    import re
    
    # Compile regex for better performance when used multiple times
    email_regex = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
    
    def validate_emails(email_list):
        valid_emails = []
        for email in email_list:
            if email_regex.match(email):
                valid_emails.append(email)
        return valid_emails
    
    # Multi-line and verbose regex
    complex_pattern = re.compile(r'''
        ^                       # Start of string
        [a-zA-Z0-9._%+-]+       # Username part
        @                       # @ symbol
        [a-zA-Z0-9.-]+          # Domain name
        \.                      # Dot
        [a-zA-Z]{2,}            # Top-level domain
        $                       # End of string
    ''', re.VERBOSE)
    Python

    📊 Data Structures (Collections)

    🔄 collections.deque (Double-ended Queue)

    from collections import deque
    
    # Create deque
    dq = deque([1, 2, 3])
    dq = deque(maxlen=5)  # Limited size deque
    
    # Add elements
    dq.append(4)        # Add to right: [1, 2, 3, 4]
    dq.appendleft(0)    # Add to left: [0, 1, 2, 3, 4]
    
    # Remove elements
    right_item = dq.pop()        # Remove from right
    left_item = dq.popleft()     # Remove from left
    
    # Extend
    dq.extend([5, 6, 7])         # Extend right
    dq.extendleft([1, 2])        # Extend left (order reversed)
    
    # Rotate
    dq.rotate(1)    # Rotate right by 1
    dq.rotate(-2)   # Rotate left by 2
    
    # Use cases: sliding window, undo functionality, breadth-first search
    Python

    🏷️ collections.OrderedDict

    from collections import OrderedDict
    
    # Maintains insertion order (note: regular dict does this in Python 3.7+)
    od = OrderedDict()
    od['first'] = 1
    od['second'] = 2
    od['third'] = 3
    
    # Move to end
    od.move_to_end('first')     # Move 'first' to end
    od.move_to_end('second', last=False)  # Move 'second' to beginning
    
    # Pop items
    last_item = od.popitem()         # Remove last item
    first_item = od.popitem(last=False)  # Remove first item
    Python

    🔢 collections.Counter

    from collections import Counter
    
    # Count elements
    words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
    counter = Counter(words)
    print(counter)  # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
    
    # Most common elements
    print(counter.most_common(2))  # [('apple', 3), ('banana', 2)]
    
    # Arithmetic operations
    counter1 = Counter(['a', 'b', 'c', 'a'])
    counter2 = Counter(['a', 'b', 'b', 'd'])
    
    print(counter1 + counter2)  # Addition
    print(counter1 - counter2)  # Subtraction
    print(counter1 & counter2)  # Intersection
    print(counter1 | counter2)  # Union
    
    # Update counter
    counter.update(['apple', 'date'])
    counter.subtract(['banana'])
    Python

    🔗 collections.ChainMap

    from collections import ChainMap
    
    # Combine multiple dictionaries
    dict1 = {'a': 1, 'b': 2}
    dict2 = {'b': 3, 'c': 4}
    dict3 = {'c': 5, 'd': 6}
    
    # ChainMap searches in order
    combined = ChainMap(dict1, dict2, dict3)
    print(combined['b'])    # 2 (from dict1, first occurrence)
    print(combined['c'])    # 4 (from dict2, first occurrence)
    
    # Add new context
    combined = combined.new_child({'e': 7})
    print(combined['e'])    # 7
    Python

    📝 collections.defaultdict

    from collections import defaultdict
    
    # Dictionary with default values
    dd = defaultdict(list)  # Default value is empty list
    dd['fruits'].append('apple')
    dd['fruits'].append('banana')
    print(dd['fruits'])     # ['apple', 'banana']
    print(dd['vegetables']) # [] (empty list, no KeyError)
    
    # With different default types
    int_dd = defaultdict(int)       # Default: 0
    set_dd = defaultdict(set)       # Default: empty set
    str_dd = defaultdict(str)       # Default: empty string
    
    # Custom default function
    def default_factory():
        return "N/A"
    
    custom_dd = defaultdict(default_factory)
    print(custom_dd['missing'])     # "N/A"
    
    # Practical example: grouping
    from collections import defaultdict
    
    students = [
        ('Alice', 'Math'),
        ('Bob', 'Science'),
        ('Alice', 'English'),
        ('Charlie', 'Math'),
        ('Bob', 'Math')
    ]
    
    # Group by student
    grouped = defaultdict(list)
    for student, subject in students:
        grouped[student].append(subject)
    
    print(dict(grouped))
    # {'Alice': ['Math', 'English'], 'Bob': ['Science', 'Math'], 'Charlie': ['Math']}
    Python

    🗂️ heapq (Priority Queue)

    import heapq
    
    # Create heap (min-heap by default)
    heap = [3, 1, 4, 1, 5, 9, 2, 6]
    heapq.heapify(heap)  # Convert list to heap in-place
    
    # Add elements
    heapq.heappush(heap, 0)
    
    # Remove smallest element
    smallest = heapq.heappop(heap)
    
    # Get n smallest/largest elements
    numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
    smallest_3 = heapq.nsmallest(3, numbers)    # [1, 1, 2]
    largest_3 = heapq.nlargest(3, numbers)      # [9, 6, 5]
    
    # Priority queue with custom objects
    class Task:
        def __init__(self, priority, description):
            self.priority = priority
            self.description = description
    
        def __lt__(self, other):
            return self.priority < other.priority
    
        def __repr__(self):
            return f"Task(priority={self.priority}, desc='{self.description}')"
    
    # Usage
    tasks = []
    heapq.heappush(tasks, Task(3, "Low priority"))
    heapq.heappush(tasks, Task(1, "High priority"))
    heapq.heappush(tasks, Task(2, "Medium priority"))
    
    next_task = heapq.heappop(tasks)  # Gets highest priority task
    Python

    🧵 Iterators & Generators

    🔄 Understanding Iterators

    # Any object with __iter__() and __next__() methods
    class CountUp:
        def __init__(self, start, end):
            self.start = start
            self.end = end
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.start >= self.end:
                raise StopIteration
            self.start += 1
            return self.start - 1
    
    # Usage
    counter = CountUp(1, 5)
    for num in counter:
        print(num)  # 1, 2, 3, 4
    
    # Built-in iter() function
    my_list = [1, 2, 3]
    iterator = iter(my_list)
    print(next(iterator))  # 1
    print(next(iterator))  # 2
    Python

    Generators (Simple and Powerful)

    # Generator function (uses yield)
    def count_up(start, end):
        while start < end:
            yield start
            start += 1
    
    # Usage
    for num in count_up(1, 5):
        print(num)  # 1, 2, 3, 4
    
    # Generator expressions
    squares = (x**2 for x in range(10))  # Generator, not list
    print(next(squares))  # 0
    print(next(squares))  # 1
    
    # Memory efficient file processing
    def read_large_file(file_path):
        with open(file_path, 'r') as file:
            for line in file:
                yield line.strip()
    
    # Process file line by line without loading entire file
    for line in read_large_file('large_file.txt'):
        process_line(line)
    Python

    🧮 Advanced Generator Features

    # Generator with send() and throw()
    def accumulator():
        total = 0
        while True:
            value = yield total
            if value is not None:
                total += value
    
    acc = accumulator()
    next(acc)           # Prime the generator
    print(acc.send(10)) # 10
    print(acc.send(5))  # 15
    print(acc.send(3))  # 18
    
    # Generator pipeline
    def read_numbers(filename):
        with open(filename) as f:
            for line in f:
                yield int(line.strip())
    
    def square_numbers(numbers):
        for num in numbers:
            yield num ** 2
    
    def filter_even(numbers):
        for num in numbers:
            if num % 2 == 0:
                yield num
    
    # Chain generators together
    def process_numbers(filename):
        numbers = read_numbers(filename)
        squared = square_numbers(numbers)
        even_squares = filter_even(squared)
        return even_squares
    
    # Memory efficient - processes one number at a time
    for result in process_numbers('numbers.txt'):
        print(result)
    Python

    🔧 itertools Module

    import itertools
    
    # Infinite iterators
    counter = itertools.count(10, 2)    # 10, 12, 14, 16, ...
    cycler = itertools.cycle(['A', 'B', 'C'])  # A, B, C, A, B, C, ...
    repeater = itertools.repeat('hello', 3)    # hello, hello, hello
    
    # Combinatorial iterators
    list1 = [1, 2]
    list2 = ['a', 'b']
    
    # Cartesian product
    product = list(itertools.product(list1, list2))
    # [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]
    
    # Permutations
    perms = list(itertools.permutations([1, 2, 3], 2))
    # [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
    
    # Combinations
    combs = list(itertools.combinations([1, 2, 3, 4], 2))
    # [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
    
    # Grouping
    data = [('A', 1), ('A', 2), ('B', 3), ('B', 4), ('A', 5)]
    grouped = itertools.groupby(data, key=lambda x: x[0])
    for key, group in grouped:
        print(f"{key}: {list(group)}")
    
    # Chain multiple iterables
    chained = itertools.chain([1, 2], [3, 4], [5, 6])
    # 1, 2, 3, 4, 5, 6
    
    # Take while condition is true
    numbers = [1, 3, 5, 8, 9, 11]
    odds = list(itertools.takewhile(lambda x: x % 2 == 1, numbers))
    # [1, 3, 5]
    Python

    🎨 Context Managers

    🔧 Built-in Context Managers

    # File handling (most common)
    with open('file.txt', 'r') as f:
        content = f.read()
    # File automatically closed
    
    # Multiple files
    with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:
        data = infile.read()
        outfile.write(data.upper())
    
    # Suppress exceptions
    from contextlib import suppress
    
    with suppress(FileNotFoundError):
        with open('might_not_exist.txt', 'r') as f:
            content = f.read()
    # No exception raised if file doesn't exist
    Python

    🏗️ Creating Custom Context Managers

    # Method 1: Class-based
    class DatabaseConnection:
        def __init__(self, database_url):
            self.database_url = database_url
            self.connection = None
    
        def __enter__(self):
            print(f"Connecting to {self.database_url}")
            # self.connection = create_connection(self.database_url)
            self.connection = f"Connected to {self.database_url}"
            return self.connection
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("Closing database connection")
            if self.connection:
                # self.connection.close()
                self.connection = None
            # Return False to propagate exceptions
            return False
    
    # Usage
    with DatabaseConnection("postgresql://localhost") as conn:
        print(f"Using connection: {conn}")
        # Do database operations
    # Connection automatically closed
    
    # Method 2: Function-based with contextlib
    from contextlib import contextmanager
    
    @contextmanager
    def timer():
        import time
        start = time.time()
        print("Timer started")
        try:
            yield start
        finally:
            end = time.time()
            print(f"Timer finished. Elapsed: {end - start:.2f}s")
    
    # Usage
    with timer() as start_time:
        # Do some work
        import time
        time.sleep(1)
        print("Working...")
    Python

    🔄 Advanced Context Manager Examples

    from contextlib import contextmanager, ExitStack
    import tempfile
    import os
    
    # Temporary directory
    @contextmanager
    def temporary_directory():
        temp_dir = tempfile.mkdtemp()
        try:
            yield temp_dir
        finally:
            import shutil
            shutil.rmtree(temp_dir)
    
    # Usage
    with temporary_directory() as temp_dir:
        file_path = os.path.join(temp_dir, 'temp_file.txt')
        with open(file_path, 'w') as f:
            f.write("Temporary content")
    # Directory and all contents automatically deleted
    
    # Managing multiple context managers
    def process_files(filenames):
        with ExitStack() as stack:
            files = [stack.enter_context(open(fname)) for fname in filenames]
            # All files will be automatically closed
            for f in files:
                print(f.read())
    
    # Custom exception handling in context manager
    @contextmanager
    def ignore_errors(*exceptions):
        try:
            yield
        except exceptions as e:
            print(f"Ignored exception: {e}")
    
    # Usage
    with ignore_errors(ValueError, TypeError):
        result = int("not_a_number")  # ValueError ignored
        print("This won't be reached")
    
    print("This will be reached")
    Python

    🛡️ Context Manager Best Practices

    # Always handle cleanup in __exit__ or finally
    @contextmanager
    def resource_manager():
        resource = acquire_resource()
        try:
            yield resource
        finally:
            # Cleanup always happens
            release_resource(resource)
    
    # Proper exception handling
    class SafeContextManager:
        def __enter__(self):
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            if exc_type is not None:
                print(f"Exception occurred: {exc_val}")
                # Log exception, clean up, etc.
    
            # Return True to suppress exception, False to propagate
            return False  # Usually want to propagate exceptions
    
    # Nested context managers
    with open('file1.txt') as f1:
        with open('file2.txt') as f2:
            # Both files properly managed
            pass
    
    # Or equivalently:
    with open('file1.txt') as f1, open('file2.txt') as f2:
        pass
    Python

    Performance & Optimization

    📊 Measuring Performance

    import time
    import timeit
    from functools import wraps
    
    # Simple timing decorator
    def timer(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print(f"{func.__name__} took {end - start:.4f} seconds")
            return result
        return wrapper
    
    @timer
    def slow_function():
        time.sleep(1)
        return "Done"
    
    # Using timeit for small code snippets
    execution_time = timeit.timeit(
        'sum([1, 2, 3, 4, 5])',
        number=1000000
    )
    print(f"Time: {execution_time:.4f} seconds")
    
    # Compare different approaches
    time1 = timeit.timeit(
        lambda: [i**2 for i in range(1000)],
        number=1000
    )
    
    time2 = timeit.timeit(
        lambda: list(map(lambda x: x**2, range(1000))),
        number=1000
    )
    
    print(f"List comprehension: {time1:.4f}s")
    print(f"Map function: {time2:.4f}s")
    Python

    🚀 Optimization Techniques

    List vs Generator Performance

    # Memory efficient - use generators for large datasets
    def fibonacci_list(n):
        """Returns list of first n Fibonacci numbers (memory intensive)"""
        fib = []
        a, b = 0, 1
        for _ in range(n):
            fib.append(a)
            a, b = b, a + b
        return fib
    
    def fibonacci_generator(n):
        """Yields first n Fibonacci numbers (memory efficient)"""
        a, b = 0, 1
        for _ in range(n):
            yield a
            a, b = b, a + b
    
    # For large n, generator uses constant memory
    for fib_num in fibonacci_generator(1000000):
        if fib_num > 1000:
            break
    Python

    String Concatenation Optimization

    # Inefficient - creates new string each time
    def slow_concat(strings):
        result = ""
        for s in strings:
            result += s  # Creates new string object each time
        return result
    
    # Efficient - join operation
    def fast_concat(strings):
        return "".join(strings)
    
    # For formatting
    def format_data(items):
        # Slow
        result = ""
        for item in items:
            result += f"Item: {item}\n"
    
        # Fast
        result = "\n".join(f"Item: {item}" for item in items)
        return result
    Python

    Dictionary vs List for Lookups

    # Efficient lookups with sets/dicts (O(1) average)
    valid_ids = {1, 2, 3, 4, 5, 100, 200, 300}  # Set for membership testing
    user_data = {1: "Alice", 2: "Bob", 3: "Charlie"}  # Dict for key-value lookup
    
    def is_valid_user(user_id):
        return user_id in valid_ids  # O(1) average
    
    # Inefficient with lists (O(n))
    valid_ids_list = [1, 2, 3, 4, 5, 100, 200, 300]
    def is_valid_user_slow(user_id):
        return user_id in valid_ids_list  # O(n) - scans entire list
    Python

    🔧 Built-in Performance Tools

    # collections.Counter for counting
    from collections import Counter
    import string
    
    # Efficient counting
    def count_letters_fast(text):
        return Counter(text.lower())
    
    # Less efficient
    def count_letters_slow(text):
        counts = {}
        for char in text.lower():
            if char in counts:
                counts[char] += 1
            else:
                counts[char] = 1
        return counts
    
    # Use appropriate data structures
    from collections import deque
    
    # Efficient queue operations
    queue = deque()
    queue.append(1)           # O(1)
    queue.appendleft(0)       # O(1)
    queue.pop()               # O(1)
    queue.popleft()           # O(1)
    
    # Inefficient with lists
    queue_list = []
    queue_list.append(1)      # O(1)
    queue_list.insert(0, 0)   # O(n) - shifts all elements
    queue_list.pop()          # O(1)
    queue_list.pop(0)         # O(n) - shifts all elements
    Python

    🧮 Algorithm Optimization

    # Memoization for expensive recursive functions
    from functools import lru_cache
    
    @lru_cache(maxsize=None)  # Cache all results
    def fibonacci_memo(n):
        if n < 2:
            return n
        return fibonacci_memo(n-1) + fibonacci_memo(n-2)
    
    # Manual memoization
    def memoize(func):
        cache = {}
        @wraps(func)
        def wrapper(*args):
            if args in cache:
                return cache[args]
            result = func(*args)
            cache[args] = result
            return result
        return wrapper
    
    @memoize
    def expensive_function(n):
        # Simulate expensive computation
        time.sleep(0.1)
        return n ** 2
    
    # Use list comprehensions instead of loops when possible
    # Fast
    squares = [x**2 for x in range(1000)]
    
    # Slower
    squares = []
    for x in range(1000):
        squares.append(x**2)
    
    # Use built-in functions (implemented in C)
    numbers = list(range(1000000))
    
    # Fast - built-in sum
    total = sum(numbers)
    
    # Slower - manual loop
    total = 0
    for num in numbers:
        total += num
    Python

    🔍 Profiling Code

    import cProfile
    import pstats
    
    def profile_function():
        # Code to profile
        numbers = [i**2 for i in range(100000)]
        return sum(numbers)
    
    # Profile with cProfile
    cProfile.run('profile_function()', 'profile_stats')
    
    # Analyze results
    stats = pstats.Stats('profile_stats')
    stats.sort_stats('cumulative')
    stats.print_stats(10)  # Top 10 functions by cumulative time
    
    # Line-by-line profiling (requires line_profiler package)
    # pip install line_profiler
    # @profile  # Uncomment when using line_profiler
    def detailed_function():
        x = [i for i in range(1000)]
        y = [i**2 for i in x]
        z = sum(y)
        return z
    
    # Run with: kernprof -l -v script.py
    Python

    🧪 Testing Basics

    unittest (Built-in Testing Framework)

    import unittest
    
    class MathOperations:
        @staticmethod
        def add(a, b):
            return a + b
    
        @staticmethod
        def divide(a, b):
            if b == 0:
                raise ValueError("Cannot divide by zero")
            return a / b
    
    class TestMathOperations(unittest.TestCase):
    
        def setUp(self):
            """Run before each test method"""
            self.math_ops = MathOperations()
    
        def tearDown(self):
            """Run after each test method"""
            pass
    
        def test_add_positive_numbers(self):
            result = self.math_ops.add(2, 3)
            self.assertEqual(result, 5)
    
        def test_add_negative_numbers(self):
            result = self.math_ops.add(-1, -1)
            self.assertEqual(result, -2)
    
        def test_divide_normal(self):
            result = self.math_ops.divide(10, 2)
            self.assertEqual(result, 5.0)
    
        def test_divide_by_zero(self):
            with self.assertRaises(ValueError):
                self.math_ops.divide(10, 0)
    
        def test_divide_with_message(self):
            with self.assertRaisesRegex(ValueError, "Cannot divide by zero"):
                self.math_ops.divide(5, 0)
    
    # Run tests
    if __name__ == '__main__':
        unittest.main()
    Python

    🔧 Common unittest Assertions

    import unittest
    
    class TestAssertions(unittest.TestCase):
    
        def test_equality(self):
            self.assertEqual(1 + 1, 2)
            self.assertNotEqual(1, 2)
            self.assertAlmostEqual(0.1 + 0.2, 0.3, places=7)
    
        def test_truth_values(self):
            self.assertTrue(True)
            self.assertFalse(False)
            self.assertIsNone(None)
            self.assertIsNotNone("something")
    
        def test_membership(self):
            self.assertIn('a', 'abc')
            self.assertNotIn('x', 'abc')
    
        def test_collections(self):
            list1 = [1, 2, 3]
            list2 = [1, 2, 3]
            self.assertListEqual(list1, list2)
            self.assertCountEqual([1, 2, 3], [3, 2, 1])  # Order doesn't matter
    
        def test_types(self):
            self.assertIsInstance(42, int)
            self.assertIsInstance("hello", str)
    
        def test_regex(self):
            self.assertRegex("hello123", r"\w+\d+")
    Python

    🎭 Mocking and Test Doubles

    import unittest
    from unittest.mock import Mock, patch, MagicMock
    
    # Example function that makes external calls
    def get_user_data(user_id):
        # Simulates API call
        import requests
        response = requests.get(f"https://api.example.com/users/{user_id}")
        return response.json()
    
    def process_user(user_id):
        user_data = get_user_data(user_id)
        return f"Hello, {user_data['name']}!"
    
    class TestMocking(unittest.TestCase):
    
        @patch('requests.get')
        def test_get_user_data(self, mock_get):
            # Setup mock response
            mock_response = Mock()
            mock_response.json.return_value = {'name': 'Alice', 'id': 123}
            mock_get.return_value = mock_response
    
            # Test the function
            result = get_user_data(123)
    
            # Assertions
            self.assertEqual(result['name'], 'Alice')
            mock_get.assert_called_once_with("https://api.example.com/users/123")
    
        @patch('__main__.get_user_data')  # Patch in the module where it's used
        def test_process_user(self, mock_get_user_data):
            # Setup mock
            mock_get_user_data.return_value = {'name': 'Bob', 'id': 456}
    
            # Test
            result = process_user(456)
    
            # Assertions
            self.assertEqual(result, "Hello, Bob!")
            mock_get_user_data.assert_called_once_with(456)
    
        def test_with_mock_object(self):
            # Create mock objects
            mock_database = Mock()
            mock_database.get_user.return_value = {'name': 'Charlie'}
    
            # Test code that uses the mock
            user = mock_database.get_user(789)
            self.assertEqual(user['name'], 'Charlie')
    
            # Verify interactions
            mock_database.get_user.assert_called_with(789)
    Python
    # pip install pytest
    import pytest
    
    # Simple test functions (no classes needed)
    def test_addition():
        assert 1 + 1 == 2
    
    def test_string_operations():
        text = "hello world"
        assert "world" in text
        assert text.startswith("hello")
        assert len(text) == 11
    
    # Parameterized tests
    @pytest.mark.parametrize("a,b,expected", [
        (1, 2, 3),
        (0, 0, 0),
        (-1, 1, 0),
        (10, -5, 5)
    ])
    def test_addition_parametrized(a, b, expected):
        assert a + b == expected
    
    # Fixtures for setup/teardown
    @pytest.fixture
    def sample_data():
        """Provides test data for multiple tests"""
        return [1, 2, 3, 4, 5]
    
    def test_with_fixture(sample_data):
        assert len(sample_data) == 5
        assert sum(sample_data) == 15
    
    # Exception testing
    def test_division_by_zero():
        with pytest.raises(ZeroDivisionError):
            result = 1 / 0
    
    def test_exception_message():
        with pytest.raises(ValueError, match="invalid literal"):
            int("not_a_number")
    
    # Temporary files and directories
    def test_file_operations(tmp_path):
        # tmp_path is a pytest fixture that provides temporary directory
        test_file = tmp_path / "test.txt"
        test_file.write_text("Hello, World!")
    
        content = test_file.read_text()
        assert content == "Hello, World!"
    
    # Skipping tests
    @pytest.mark.skip(reason="Not implemented yet")
    def test_future_feature():
        pass
    
    @pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
    def test_unix_specific():
        pass
    Python

    🧪 Test-Driven Development (TDD) Example

    # Step 1: Write failing test
    import unittest
    
    class TestCalculator(unittest.TestCase):
        def test_add(self):
            calc = Calculator()
            result = calc.add(2, 3)
            self.assertEqual(result, 5)
    
    # Step 2: Write minimal code to pass
    class Calculator:
        def add(self, a, b):
            return a + b
    
    # Step 3: Refactor and add more tests
    class TestCalculatorExtended(unittest.TestCase):
        def setUp(self):
            self.calc = Calculator()
    
        def test_add_positive(self):
            self.assertEqual(self.calc.add(2, 3), 5)
    
        def test_add_negative(self):
            self.assertEqual(self.calc.add(-1, -1), -2)
    
        def test_add_zero(self):
            self.assertEqual(self.calc.add(5, 0), 5)
    
        def test_subtract(self):
            self.assertEqual(self.calc.subtract(5, 3), 2)
    
        def test_multiply(self):
            self.assertEqual(self.calc.multiply(3, 4), 12)
    
        def test_divide(self):
            self.assertEqual(self.calc.divide(10, 2), 5)
    
        def test_divide_by_zero(self):
            with self.assertRaises(ValueError):
                self.calc.divide(10, 0)
    
    # Enhanced Calculator implementation
    class Calculator:
        def add(self, a, b):
            return a + b
    
        def subtract(self, a, b):
            return a - b
    
        def multiply(self, a, b):
            return a * b
    
        def divide(self, a, b):
            if b == 0:
                raise ValueError("Cannot divide by zero")
            return a / b
    Python

    📊 Test Coverage

    # Install coverage: pip install coverage
    
    # Run tests with coverage
    # coverage run -m pytest tests/
    # coverage report
    # coverage html  # Creates HTML report
    
    # Example of testing coverage
    def fibonacci(n):
        """Calculate nth Fibonacci number"""
        if n <= 0:
            return 0
        elif n == 1:
            return 1
        else:
            return fibonacci(n-1) + fibonacci(n-2)
    
    class TestFibonacci(unittest.TestCase):
        def test_fibonacci_zero(self):
            self.assertEqual(fibonacci(0), 0)
    
        def test_fibonacci_one(self):
            self.assertEqual(fibonacci(1), 1)
    
        def test_fibonacci_positive(self):
            self.assertEqual(fibonacci(5), 5)
            self.assertEqual(fibonacci(7), 13)
    
        def test_fibonacci_negative(self):
            self.assertEqual(fibonacci(-1), 0)
    
    # This test suite provides 100% code coverage
    Python

    🔢 Data Structures & Algorithms

    📊 Array/List Operations & Complexity

    OperationSyntaxTime ComplexitySpace ComplexityExample
    Accessarr[i]O(1)O(1)nums[5]
    Searchitem in arrO(n)O(1)5 in [1,2,3,4,5]
    Insertion (end)arr.append(item)O(1) amortizedO(1)nums.append(6)
    Insertion (beginning)arr.insert(0, item)O(n)O(1)nums.insert(0, 0)
    Insertion (middle)arr.insert(i, item)O(n)O(1)nums.insert(2, 10)
    Deletion (end)arr.pop()O(1)O(1)nums.pop()
    Deletion (beginning)arr.pop(0)O(n)O(1)nums.pop(0)
    Deletion (middle)arr.pop(i)O(n)O(1)nums.pop(2)
    Sortarr.sort()O(n log n)O(1)nums.sort()
    Reversearr.reverse()O(n)O(1)nums.reverse()

    🗂️ Dictionary/Hash Table Operations

    OperationSyntaxAverage TimeWorst TimeExample
    Accessdict[key]O(1)O(n)ages['Alice']
    Searchkey in dictO(1)O(n)'Alice' in ages
    Insertiondict[key] = valueO(1)O(n)ages['Bob'] = 25
    Deletiondel dict[key]O(1)O(n)del ages['Alice']
    Get keysdict.keys()O(1)O(1)ages.keys()
    Get valuesdict.values()O(1)O(1)ages.values()
    Get itemsdict.items()O(1)O(1)ages.items()

    🔸 Set Operations & Complexity

    OperationSyntaxTime ComplexityExample
    Addset.add(item)O(1) averages.add(5)
    Removeset.remove(item)O(1) averages.remove(5)
    Searchitem in setO(1) average5 in s
    Union`set1 \set2`O(len(s1) + len(s2))
    Intersectionset1 & set2O(min(len(s1), len(s2)))s1 & s2
    Differenceset1 - set2O(len(s1))s1 - s2
    Symmetric Diffset1 ^ set2O(len(s1) + len(s2))s1 ^ s2

    🌲 Tree Data Structures Implementation

    Binary Tree Node

    class TreeNode:
        def __init__(self, val=0, left=None, right=None):
            self.val = val
            self.left = left
            self.right = right
    Python

    Tree Traversal Algorithms

    AlgorithmImplementationTimeSpaceUse Case
    PreorderRoot → Left → RightO(n)O(h)Copy tree structure
    InorderLeft → Root → RightO(n)O(h)Get sorted order (BST)
    PostorderLeft → Right → RootO(n)O(h)Delete nodes safely
    Level OrderBFS using queueO(n)O(w)Level-by-level processing
    # Tree Traversal Implementations
    def preorder(root):
        if not root: return []
        return [root.val] + preorder(root.left) + preorder(root.right)
    
    def inorder(root):
        if not root: return []
        return inorder(root.left) + [root.val] + inorder(root.right)
    
    def postorder(root):
        if not root: return []
        return postorder(root.left) + postorder(root.right) + [root.val]
    
    def level_order(root):
        if not root: return []
        from collections import deque
        queue, result = deque([root]), []
        while queue:
            node = queue.popleft()
            result.append(node.val)
            if node.left: queue.append(node.left)
            if node.right: queue.append(node.right)
        return result
    Python

    📚 Stack & Queue Operations

    Stack (LIFO) – Using List

    OperationSyntaxTimeSpaceExample
    Pushstack.append(item)O(1)O(1)stack.append(5)
    Popstack.pop()O(1)O(1)item = stack.pop()
    Top/Peekstack[-1]O(1)O(1)top = stack[-1]
    Is Emptylen(stack) == 0O(1)O(1)not stack
    Sizelen(stack)O(1)O(1)len(stack)

    Queue (FIFO) – Using collections.deque

    OperationSyntaxTimeSpaceExample
    Enqueuequeue.append(item)O(1)O(1)queue.append(5)
    Dequeuequeue.popleft()O(1)O(1)item = queue.popleft()
    Frontqueue[0]O(1)O(1)front = queue[0]
    Is Emptylen(queue) == 0O(1)O(1)not queue
    Sizelen(queue)O(1)O(1)len(queue)

    🔗 Linked List Implementation

    class ListNode:
        def __init__(self, val=0, next=None):
            self.val = val
            self.next = next
    
    class LinkedList:
        def __init__(self):
            self.head = None
            self.size = 0
    
        def append(self, val):              # O(n) time
            new_node = ListNode(val)
            if not self.head:
                self.head = new_node
            else:
                curr = self.head
                while curr.next:
                    curr = curr.next
                curr.next = new_node
            self.size += 1
    
        def prepend(self, val):             # O(1) time
            new_node = ListNode(val)
            new_node.next = self.head
            self.head = new_node
            self.size += 1
    
        def delete(self, val):              # O(n) time
            if not self.head: return
            if self.head.val == val:
                self.head = self.head.next
                self.size -= 1
                return
            curr = self.head
            while curr.next and curr.next.val != val:
                curr = curr.next
            if curr.next:
                curr.next = curr.next.next
                self.size -= 1
    
        def search(self, val):              # O(n) time
            curr = self.head
            while curr:
                if curr.val == val:
                    return True
                curr = curr.next
            return False
    Python

    🏔️ Heap Operations (Priority Queue)

    OperationSyntaxTime ComplexityExample
    Create Heapheapq.heapify(list)O(n)heapq.heapify([3,1,4,1,5])
    Pushheapq.heappush(heap, item)O(log n)heapq.heappush(heap, 2)
    Pop Minheapq.heappop(heap)O(log n)min_val = heapq.heappop(heap)
    Peek Minheap[0]O(1)min_val = heap[0]
    Push-Popheapq.heappushpop(heap, item)O(log n)heapq.heappushpop(heap, 5)
    Replaceheapq.heapreplace(heap, item)O(log n)heapq.heapreplace(heap, 3)
    N Largestheapq.nlargest(n, iterable)O(n log k)heapq.nlargest(3, [1,3,5,2,4])
    N Smallestheapq.nsmallest(n, iterable)O(n log k)heapq.nsmallest(2, [1,3,5,2,4])

    🔍 Search Algorithms

    def linear_search(arr, target):
        """Time: O(n), Space: O(1)"""
        for i, val in enumerate(arr):
            if val == target:
                return i
        return -1
    Python
    def binary_search(arr, target):
        """Time: O(log n), Space: O(1) - Array must be sorted"""
        left, right = 0, len(arr) - 1
        while left <= right:
            mid = (left + right) // 2
            if arr[mid] == target:
                return mid
            elif arr[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return -1
    
    def binary_search_recursive(arr, target, left=0, right=None):
        """Time: O(log n), Space: O(log n) due to recursion"""
        if right is None:
            right = len(arr) - 1
        if left > right:
            return -1
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            return binary_search_recursive(arr, target, mid + 1, right)
        else:
            return binary_search_recursive(arr, target, left, mid - 1)
    Python

    📊 Sorting Algorithms

    AlgorithmBest CaseAverage CaseWorst CaseSpaceStableIn-place
    Bubble SortO(n)O(n²)O(n²)O(1)YesYes
    Selection SortO(n²)O(n²)O(n²)O(1)NoYes
    Insertion SortO(n)O(n²)O(n²)O(1)YesYes
    Merge SortO(n log n)O(n log n)O(n log n)O(n)YesNo
    Quick SortO(n log n)O(n log n)O(n²)O(log n)NoYes
    Heap SortO(n log n)O(n log n)O(n log n)O(1)NoYes
    Tim Sort (Python default)O(n)O(n log n)O(n log n)O(n)YesNo

    Sorting Implementations

    def bubble_sort(arr):
        """Time: O(n²), Space: O(1)"""
        n = len(arr)
        for i in range(n):
            swapped = False
            for j in range(0, n - i - 1):
                if arr[j] > arr[j + 1]:
                    arr[j], arr[j + 1] = arr[j + 1], arr[j]
                    swapped = True
            if not swapped:
                break
        return arr
    
    def merge_sort(arr):
        """Time: O(n log n), Space: O(n)"""
        if len(arr) <= 1:
            return arr
        mid = len(arr) // 2
        left = merge_sort(arr[:mid])
        right = merge_sort(arr[mid:])
        return merge(left, right)
    
    def merge(left, right):
        result = []
        i = j = 0
        while i < len(left) and j < len(right):
            if left[i] <= right[j]:
                result.append(left[i])
                i += 1
            else:
                result.append(right[j])
                j += 1
        result.extend(left[i:])
        result.extend(right[j:])
        return result
    
    def quick_sort(arr):
        """Time: O(n log n) avg, O(n²) worst, Space: O(log n)"""
        if len(arr) <= 1:
            return arr
        pivot = arr[len(arr) // 2]
        left = [x for x in arr if x < pivot]
        middle = [x for x in arr if x == pivot]
        right = [x for x in arr if x > pivot]
        return quick_sort(left) + middle + quick_sort(right)
    Python

    🌐 Graph Algorithms

    Graph Representation

    # Adjacency List
    graph = {
        'A': ['B', 'C'],
        'B': ['A', 'D', 'E'],
        'C': ['A', 'F'],
        'D': ['B'],
        'E': ['B', 'F'],
        'F': ['C', 'E']
    }
    
    # Adjacency Matrix
    graph_matrix = [
        [0, 1, 1, 0, 0, 0],  # A
        [1, 0, 0, 1, 1, 0],  # B
        [1, 0, 0, 0, 0, 1],  # C
        [0, 1, 0, 0, 0, 0],  # D
        [0, 1, 0, 0, 0, 1],  # E
        [0, 0, 1, 0, 1, 0]   # F
    ]
    Python

    Graph Traversal

    AlgorithmData StructureTimeSpaceUse Case
    DFSStack/RecursionO(V + E)O(V)Path finding, cycle detection
    BFSQueueO(V + E)O(V)Shortest path, level-order
    def dfs(graph, start, visited=None):
        """Depth-First Search"""
        if visited is None:
            visited = set()
        visited.add(start)
        result = [start]
    
        for neighbor in graph[start]:
            if neighbor not in visited:
                result.extend(dfs(graph, neighbor, visited))
        return result
    
    def bfs(graph, start):
        """Breadth-First Search"""
        from collections import deque
        visited = set([start])
        queue = deque([start])
        result = []
    
        while queue:
            node = queue.popleft()
            result.append(node)
    
            for neighbor in graph[node]:
                if neighbor not in visited:
                    visited.add(neighbor)
                    queue.append(neighbor)
        return result
    Python

    🔄 Dynamic Programming Patterns

    Common DP Problems & Solutions

    ProblemRecurrenceTimeSpaceExample
    Fibonaccidp[i] = dp[i-1] + dp[i-2]O(n)O(1)fib(5) = 5
    Climbing Stairsdp[i] = dp[i-1] + dp[i-2]O(n)O(1)Ways to climb n steps
    Coin Changedp[i] = min(dp[i-coin] + 1)O(n*m)O(n)Min coins for amount
    Longest Common Subsequencedp[i][j] = dp[i-1][j-1] + 1O(n*m)O(n*m)LCS of two strings
    0/1 Knapsackdp[i][w] = max(dp[i-1][w], dp[i-1][w-weight[i]] + value[i])O(n*W)O(n*W)Max value in knapsack
    # Fibonacci with memoization
    def fibonacci_dp(n, memo={}):
        if n in memo:
            return memo[n]
        if n <= 1:
            return n
        memo[n] = fibonacci_dp(n-1, memo) + fibonacci_dp(n-2, memo)
        return memo[n]
    
    # Coin Change Problem
    def coin_change(coins, amount):
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0
    
        for coin in coins:
            for i in range(coin, amount + 1):
                dp[i] = min(dp[i], dp[i - coin] + 1)
    
        return dp[amount] if dp[amount] != float('inf') else -1
    
    # Longest Common Subsequence
    def lcs(text1, text2):
        m, n = len(text1), len(text2)
        dp = [[0] * (n + 1) for _ in range(m + 1)]
    
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if text1[i-1] == text2[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    
        return dp[m][n]
    Python

    🎯 Two Pointers Technique

    PatternUse CaseTimeExample
    Opposite EndsPalindrome, Two Sum (sorted)O(n)left=0, right=len(arr)-1
    Same DirectionRemove duplicates, sliding windowO(n)slow=0, fast=1
    Fast & SlowCycle detection, middle elementO(n)Floyd’s algorithm
    def two_sum_sorted(arr, target):
        """Two pointers for sorted array"""
        left, right = 0, len(arr) - 1
        while left < right:
            current_sum = arr[left] + arr[right]
            if current_sum == target:
                return [left, right]
            elif current_sum < target:
                left += 1
            else:
                right -= 1
        return []
    
    def is_palindrome(s):
        """Check palindrome using two pointers"""
        left, right = 0, len(s) - 1
        while left < right:
            if s[left] != s[right]:
                return False
            left += 1
            right -= 1
        return True
    
    def find_cycle(head):
        """Floyd's cycle detection algorithm"""
        if not head or not head.next:
            return None
    
        slow = fast = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                break
        else:
            return None  # No cycle
    
        # Find cycle start
        slow = head
        while slow != fast:
            slow = slow.next
            fast = fast.next
        return slow
    Python

    🪟 Sliding Window Technique

    PatternUse CaseTimeSpaceExample
    Fixed SizeMax sum of k elementsO(n)O(1)Moving average
    Variable SizeLongest substringO(n)O(k)Min window substring
    def max_sum_subarray(arr, k):
        """Fixed sliding window"""
        if len(arr) < k:
            return 0
    
        # Initial window sum
        window_sum = sum(arr[:k])
        max_sum = window_sum
    
        # Slide the window
        for i in range(k, len(arr)):
            window_sum = window_sum - arr[i-k] + arr[i]
            max_sum = max(max_sum, window_sum)
    
        return max_sum
    
    def longest_substring_without_repeating(s):
        """Variable sliding window"""
        char_index = {}
        left = max_length = 0
    
        for right, char in enumerate(s):
            if char in char_index and char_index[char] >= left:
                left = char_index[char] + 1
            char_index[char] = right
            max_length = max(max_length, right - left + 1)
    
        return max_length
    Python

    🔢 Bit Manipulation

    OperationSyntaxExampleUse Case
    ANDa & b5 & 3 = 1Check if bit is set
    OR`a \b``5 \
    XORa ^ b5 ^ 3 = 6Toggle bit, find unique
    NOT~a~5 = -6Flip all bits
    Left Shifta << b5 << 1 = 10Multiply by 2^b
    Right Shifta >> b5 >> 1 = 2Divide by 2^b
    def count_set_bits(n):
        """Count number of 1s in binary representation"""
        count = 0
        while n:
            count += n & 1
            n >>= 1
        return count
    
    def is_power_of_two(n):
        """Check if n is power of 2"""
        return n > 0 and (n & (n - 1)) == 0
    
    def find_single_number(nums):
        """Find the number that appears once (others appear twice)"""
        result = 0
        for num in nums:
            result ^= num
        return result
    
    def swap_numbers(a, b):
        """Swap without temporary variable"""
        a = a ^ b
        b = a ^ b
        a = a ^ b
        return a, b
    Python

    📈 Algorithm Complexity Cheat Sheet

    Time Complexity Hierarchy (Best to Worst)

    1. O(1) – Constant: Hash table access, array indexing
    2. O(log n) – Logarithmic: Binary search, balanced tree operations
    3. O(n) – Linear: Linear search, simple loops
    4. O(n log n) – Linearithmic: Efficient sorting (merge, heap)
    5. O(n²) – Quadratic: Nested loops, simple sorting (bubble, selection)
    6. O(n³) – Cubic: Triple nested loops
    7. O(2ⁿ) – Exponential: Recursive Fibonacci, subset generation
    8. O(n!) – Factorial: Permutation generation

    Space Complexity Patterns

    • O(1) – In-place algorithms
    • O(log n) – Recursive algorithms with balanced recursion
    • O(n) – Single array/list storage
    • O(n²) – 2D matrix storage

    🎲 Common Algorithmic Patterns

    PatternWhen to UseTimeExamples
    Divide & ConquerProblem can be splitO(n log n)Merge sort, binary search
    GreedyLocal optimal → global optimalVariesDijkstra, activity selection
    BacktrackingExplore all possibilitiesO(2ⁿ) typicallyN-Queens, sudoku solver
    Dynamic ProgrammingOverlapping subproblemsO(n) to O(n³)Fibonacci, knapsack
    Two PointersSearch pairs in sorted dataO(n)Two sum, palindrome
    Sliding WindowContiguous subarray problemsO(n)Max subarray, substring
    BFS/DFSGraph/tree traversalO(V + E)Shortest path, connectivity

    This cheat sheet covers the most commonly used Python features. For more advanced topics, refer to the official Python documentation.


    Discover more from Altgr Blog

    Subscribe to get the latest posts sent to your email.

    Leave a Reply

    Your email address will not be published. Required fields are marked *