Python Cheatsheet

Back to Cheatsheet Index

# Learning Python Basics
# --- Standard Libraries ---
from pyclbr import Class
import random # for generating random numbers
import datetime # for date and time manipulation
import time # for time-related functions
# --- File and Directory Libraries ---
import os # for operating system related functions
import pathlib # for filesystem paths
# --- Data Format Libraries ---
import csv # for CSV file handling
import json # for JSON parsing and generation
# --- Networking Libraries ---
import requests # for making HTTP requests
# --- Data Science Libraries ---
import numpy  # numerical computing
import pandas # data manipulation and analysis
import matplotlib # plotting and visualization
# save for later to learn: import seaborn
# save for later to learn: import tqdm

class Class_Basics:
    def __init__(self, name): # constructor, called when creating an instance
        self.name = name
    
    def greet(self):
        return f"Hello, {self.name}!"

    @classmethod                    # @classmethod decorator indicates this method belongs to the class, not instance
    def class_and_objects_demo(cls):
        obj = cls("Alice") # create an instance of Class_Basics
        print(obj.greet()) # call the greet method

    # We can call class_and_objects_demo without creating an instance by using Class_Basics.class_and_objects_demo()
    # because it does not use self and is effectively a static method.
    

def variables_and_types():
    # int, float, str, bool
    x = 42          # int
    y = 3.14        # float
    s = "hello"     # str
    flag = True     # bool
    print(type(x), type(y), type(s), type(flag))

def string_basics():
    s = "Python"
    print(s.upper())      # PYTHON
    print(s.lower())      # python
    print(s[0], s[-1])    # indexing (getting specific character)
    print(s[0:3])         # slicing (in this case, start at index 0 (the "P"). Go up to, but not including, index 3 (the "h")
    print(f"Hello {s}")   # f-string

def conditionals():
    n = 5
    if n > 0:
        print("Positive")
    elif n == 0:
        print("Zero")
    else:
        print("Negative")

def loops():
    for i in range(3):
        print("for loop:", i)
    j = 0
    while j < 3:
        print("while loop:", j)
        j += 1

def tuple_list_dictionary():
# --- Quick Reference ---
# Tuple: immutable → reassign only
# List:  remove(value), del[index], pop([index]), clear()
# Dict:  assign/update, del[key], pop(key), popitem(), clear()

    # Tuple
    a = ("a1","a2","a3") # () symbol is Tuple type, immutable, fixed collections, often used for records 
    a = ("a1","a4")  # Tuples are immutable; this is not an update, it's a reassignment
    print(a)
    a = () # We cannot delete a tuple, only make it empty by reassign
    print(a)

    # List
    b = ["b1", "b2", "b3", "b4", "b5", "b6"]  # [] is List type: mutable, dynamic array, great for iteration and modification
    print(f"Original b is: {b}")
    b.remove("b2")  # Removes the first occurrence of "b2"; raises ValueError if not found, takes value only, not index
    del b[0]            # Deletes item at index 0 (first item); accepts index only, not value
    popped = b.pop()    # Removes and returns last item; default is last index (-1)
                        # Can also pop specific item using index (e.g., b.pop(1)), but NOT string keys
    print(f"After .remove(\"b2\"), del b[0], pop() item is: {popped}")
    print(f"Current b is: {b}")
    popped = b.pop(1)   # Removes and returns item at index 1
    print(f"pop(1) item is: {popped}")
    b.clear()
    
    # Dictionary
    c = {"c1": "Hello", "c2": "world"}  # {} creates a dictionary: mutable, key-value pairs, like a mini database
    # Method 1 — Direct assignment (faster for single key)
    c["c3"] = "!"        # Adds a new key-value pair to the dictionary
    c["c3"] = "???"      # Updates the value of an existing key
    # Method 2 — Using .update() (slightly slower for one key, but supports batch updates and keyword args)
    c.update({"c4": "My name is", "c5": "Felix"})  # Adds multiple key-value pairs using a dictionary
    c.update(c5="Felix Lau")                       # Updates using keyword arguments (keys must be valid identifiers)
    c.update({"c3": "!!!!!"})  # Updates existing key using dictionary-style syntax
    c["c3"] = "" # This will NOT remove "c3", only assign "" to its value
    del c["c3"] # Remove "c3", unlike list, del in dict only take key 
    popped = c.pop("c2") # Remove c2 and return c2's value, unlike list, pop in dict only take key 
    popped = c.popitem()  # Removes and returns the last inserted (key, value) pair
    print(popped)
    key, popped = c.popitem()  # Always returns a (key, value) tuple, unpacked into two variables
    print(c)
    print(key)
    print(popped)
    c.clear()

def set_and_operations_basics():
    # --- SET BASICS ---
    # A set is a collection of unique, unordered elements.
    # - Mutable: you can add/remove elements.
    # - Elements must be immutable (e.g., numbers, strings, tuples).
    # - Duplicates are automatically removed.
    s = {1, 1, 2, 3}  # Duplicate "1" is ignored → set becomes {1, 2, 3}
    s.add(4)          # Adds a new element → {1, 2, 3, 4}
    s.remove(2)       # Removes element 2; raises KeyError if 2 not in set
    print(s)          # Example output: {1, 3, 4}
    print(type(s))    # 

    # --- SET OPERATIONS ---
    # Sets support mathematical operations:
    a = {1, 2, 3}
    b = {3, 4, 5}
    print(a | b)    # UNION: all unique elements from both sets → {1, 2, 3, 4, 5}
    print(a & b)    # INTERSECTION: elements common to both → {3}
    print(a - b)    # DIFFERENCE: elements in a but not in b → {1, 2}
    # Note: There is also symmetric difference (^) → elements in either set but not both.

    # --- DICTIONARY BASICS ---
    d = {}
    print(type(d))  # {} with nothing inside defaults to a dict, not a set

    d1 = {"a": 1, "b": 2}
    d2 = {"b": 3, "c": 4}

    # --- DICT MERGE OPERATOR (Python 3.9+) ---
    # "|" merges two dicts. If keys overlap, the right-hand dict wins.
    print(d1 | d2)        # {'a': 1, 'b': 3, 'c': 4}
    print(d1 | {"d": 5})  # {'a': 1, 'b': 2, 'd': 5}

    # --- DICT KEYS AS SETS ---
    # dict.keys() returns a set-like view, so you can use set operations:
    print(d1.keys() & d2.keys())  # INTERSECTION of keys → {'b'}
    print(d1.keys() - d2.keys())  # DIFFERENCE of keys → {'a'}

    # --- DICT ITEMS AND VALUES ---
    d1 = {"a": 1, "b": 2, "c": 3}
    d2 = {"b": 2, "c": 4, "d": 5}

    # dict.items() returns (key, value) pairs as a set-like view.
    # Intersection finds exact matches of both key AND value.
    print(d1.items() & d2.items())  # {('b', 2)} → only ('b', 2) matches in both

    # To compare values only, convert dict.values() to a set:
    print(set(d1.values()) & set(d2.values()))  # {2} → shared values

def functions_demo():
    def greet(name="World"): # This set the default as "World"
        return f"Hello, {name}!"
    print(greet()) # Hello, World!
    print(greet("Felix")) #Hello, Felix!

def exceptions_demo():
    try:
        x = 1 / 0
    except ZeroDivisionError as e:
        print("Error:", e)
    finally:
        print("Cleanup code runs here")

def random_basics():
    # --- NUMBERS ---
    print("Random integer between 1 and 10:", random.randint(1, 10))
    print("Random float between 0 and 1:", random.random())
    print("Random float between 5 and 10:", random.uniform(5, 10))

    # --- SEQUENCES ---
    items = ['apple', 'banana', 'cherry']
    print("Random choice from list:", random.choice(items))
    print("Random sample of 2 items:", random.sample(items, 2))
    random.shuffle(items)
    print("Shuffled list:", items)

    # --- REPRODUCIBILITY ---
    random.seed(42)
    print("Deterministic random integer:", random.randint(1, 10))
    random.seed(None) # Reset seed to system time or entropy source

def datetime_basics():
    now = datetime.datetime.now()
    print("Current date and time:", now) # default format: YYYY-MM-DD HH:MM:SS.mmmmmm
    print("ISO 8601 (built-in):", now.isoformat()) # ISO 8601 format

    dt = datetime.datetime.strptime("2025-10-18 20:30:00", "%Y-%m-%d %H:%M:%S") # parsing string to datetime
    print("Parsed datetime:", dt) # formatting codes: %Y year, %m month, %d day, %H hour, %M minute, %S second


    print("Formatted date:", now.strftime("%Y-%m-%d %H:%M:%S")) # formatting codes: %Y year, %m month, %d day, %H hour, %M minute, %S second
    # other useful formats: %A full weekday name, %a abbreviated weekday name, %B full month name, %b abbreviated month name
    
    delta = datetime.timedelta(days=5) # timedelta() represents a duration, the difference between two dates or times
    # other timedelta arguments: weeks, hours, minutes, seconds, milliseconds, microseconds
    
    future_date = now + delta
    print("Date after 5 days:", future_date)

    # other useful datetime methods: .date(), .time(), .year, .month, .day, .hour, .minute, .second
    print("Current date:", now.date())
    print("Current time:", now.time())
    print("Current year:", now.year)
    print("Current month:", now.month)
    print("Current day:", now.day)
    print("Current hour:", now.hour)
    print("Current minute:", now.minute)
    print("Current second:", now.second)

def time_basics():
    # --- TIMING CODE EXECUTION ---
    start_time = time.time()
    time.sleep(1)
    end_time = time.time()
    print(f"Execution time (time.time): {end_time - start_time:.4f} seconds")

    start = time.perf_counter() # High-resolution timer for performance measurement
    time.sleep(1)
    end = time.perf_counter()
    print(f"Execution time (perf_counter): {end - start:.4f} seconds")

    # --- STRUCT_TIME AND COMPONENTS ---
    print("Current local time (struct_time):", time.localtime())
    t = time.localtime()
    print(f"Year: {t.tm_year}, Month: {t.tm_mon}, Day: {t.tm_mday}") # We can access individual components like this

    # --- FORMATTING WITH strftime ---
    print("Formatted time:", time.strftime("%Y-%m-%d %H:%M:%S", t))
    print("ISO 8601:", time.strftime("%Y-%m-%dT%H:%M:%S", t))
    print("Day and Month:", time.strftime("%A, %B %d", t))
    print("Current time:", time.strftime("%H:%M:%S", t))
    print("Current timezone:", time.tzname[time.daylight])
    # Formatting codes: %Y year, %m month, %d day, %H hour, %M minute, %S second, %A full weekday name, %B full month name, %I hour (12-hour clock), %p AM/PM, %Z timezone name,
    # other useful codes: %j day of year, %U week number (Sunday as first day), %W week number (Monday as first day)

    # --- OTHER USEFUL FUNCTIONS ---
    print("Current GMT (struct_time):", time.gmtime()) # time.gmtime() returns UTC time
    print("UTC formatted:", time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()))  # Formatting UTC time
    print("Local formatted:", time.strftime("%Y-%m-%d %H:%M:%S", t)) # Formatting local time
    print("asctime() (fixed format):", time.asctime()) # asctime() has a fixed format; use strftime() for custom formatting
    print("asctime() with gmtime() (fixed format):", time.asctime(time.gmtime())) # asctime() with gmtime()
    print("Seconds since epoch (via mktime):", time.mktime(t)) # Convert struct_time to seconds since epoch, useful for converting back to a timestamp (inverse of localtime())

def os_and_pathlib_basics():
    # --- OS MODULE BASICS ---
    # The os module provides functions for interacting with the operating system.

    # Current working directory
    print("Current Working Directory:", os.getcwd())

    # List files and directories in the current directory
    print("List of files and directories:", os.listdir('.'))

    # Create and remove directories
    os.makedirs('test_dir/sub_dir', exist_ok=True)  # Create nested directories
    # Argument exist_ok=True prevents error if directory already exists
    os.rmdir('test_dir/sub_dir')  # Remove subdirectory, must be empty
    os.rmdir('test_dir')          # Remove main directory, must be empty

    # Environment variables
    print("All Environment Variables:", os.environ) # prints all environment variables as a dict-like object
    print("PATH:", os.environ.get('PATH')) # get specific environment variable
    print("HOME:", os.environ.get('HOME')) # get specific environment variable

    # Path operations
    print("Join paths:", os.path.join('folder', 'file.txt'))
    print("Path exists?", os.path.exists('folder'))
    print("Is file?", os.path.isfile('folder'))
    print("Is directory?", os.path.isdir('folder'))

    # File metadata with os.stat()
    # Returns info like size, modification time, etc.
    # (Requires an existing file, so here we just show the call)
    # stat_info = os.stat('some_file.txt')
    # print("File size:", stat_info.st_size, "bytes")

    # Recursively walk through directories with os.walk()
    # os.walk() yields (dirpath, dirnames, filenames)
    for dirpath, dirnames, filenames in os.walk('.'): # '.' means start from current directory
        print("Walking:", dirpath)
        print(" Subdirectories:", dirnames)
        print(" Files:", filenames)
        break  # remove break to walk the entire tree

    # --- PATHLIB MODULE BASICS ---
    # Pathlib is a modern, object-oriented alternative to os.path.

    p = pathlib.Path('.')  # Current directory as a Path object
    print("Pathlib CWD:", p.resolve())

    # Iterate over children in a directory
    for child in p.iterdir():
        print("Child item:", child)

    # Create and delete a file
    new_file = p / 'example.txt' # Create a Path object for new file, this does not create the file yet
    new_file.write_text("Hello, Pathlib!")  # Create file and write text
    print("Created file with content:", new_file)

    print("File content:", new_file.read_text())  # Read file content

    new_file.rename('example_renamed.txt')  # Rename file
    renamed_file = p / 'example_renamed.txt' # Update Path object to new name so we can delete it later
    print("Renamed file:", renamed_file)

    renamed_file.unlink()  # Delete the file
    print("Deleted file:", renamed_file)

    # Path checks
    print("Path exists?", renamed_file.exists())
    print("Is directory?", p.is_dir())

    # Pattern matching with glob
    print("All .py files in current dir:")
    for py_file in p.glob("*.py"):
        print(" -", py_file)

    # File metadata with Path.stat()
    # (Requires an existing file, so here we just show the call)
    # print("File size:", renamed_file.stat().st_size, "bytes")

    # Other useful pathlib methods:
    # .mkdir()   -> make a directory
    # .rmdir()   -> remove a directory, must be empty
    # .is_file() -> check if path is a file
    # .is_dir()  -> check if path is a directory

def main():
    return 0

if __name__ == "__main__":
    f = Class_Basics("Felix")
    print(f.greet())
    Class_Basics.class_and_objects_demo()