Python Fundamentals: Variables, Types, and Operators
Python is dynamically typed — you do not declare variable types. Python infers them at runtime. Built-in types: int (whole numbers, arbitrary precision), float (decimal — IEEE 754 double precision, be careful with floating-point arithmetic: 0.1 + 0.2 != 0.3), str (immutable sequence of Unicode characters), bool (True or False — subclass of int: True == 1, False == 0), NoneType (the None object — Python's null value). Type conversion: int('42') converts string to int, str(42) converts int to string, float('3.14') converts string to float. Operators: arithmetic (+, -, *, /, // floor division, % modulo, ** exponentiation), comparison (==, !=, <, >, <=, >= — return bool), logical (and, or, not — short-circuit evaluation), identity (is, is not — tests object identity, not equality — is None is the correct way to check for None), membership (in, not in — tests for membership in a sequence or collection). String operations: concatenation with +, repetition with *, indexing (s[0] = first char, s[-1] = last char), slicing (s[1:4] = chars 1, 2, 3 — end index is exclusive), len(), lower(), upper(), strip(), split(), join(), format(), f-strings (f'Hello {name}!').
Control Flow and Functions
Python uses indentation (not braces) to define code blocks — consistent indentation is syntactically required. Control flow: if / elif / else (Python has no switch statement — use if/elif chains or dictionaries for dispatch), for loops (iterate over any iterable — for item in list, for i in range(10)), while loops (continue while condition is True), break (exit the loop immediately), continue (skip to next iteration), else on for/while (runs if loop completes without hitting break — often surprising to newcomers). Functions: defined with def keyword, return a value with return (implicit return of None if no return statement). Default parameters (def greet(name='World'): — mutable default arguments like lists are a classic bug, use None as default and create the list inside), *args (variable positional arguments as a tuple), **kwargs (variable keyword arguments as a dict). Lambda functions: anonymous one-line functions — lambda x: x * 2 — useful for sort keys and functional programming patterns. List comprehensions: [x**2 for x in range(10) if x % 2 == 0] — creates a list, faster and more Pythonic than equivalent for-loop.
Data Structures: Lists, Tuples, Dicts, and Sets
Python's four main collection types each serve a different purpose. Lists (mutable, ordered, allow duplicates): my_list = [1, 2, 3]. Methods: append(), extend(), insert(), remove(), pop(), sort(), reverse(), index(). Lists are passed by reference — modifying a list inside a function modifies the original. Tuples (immutable, ordered, allow duplicates): my_tuple = (1, 2, 3). Use tuples for fixed data (coordinates, RGB values), as dictionary keys (lists cannot be dict keys), and for multiple return values. Dictionaries (mutable, key-value pairs, keys are unique): my_dict = {'key': 'value'}. Access: dict['key'] (raises KeyError if missing), dict.get('key', default) (safe access). Methods: keys(), values(), items(), update(), pop(). Iteration: for key, value in dict.items(). Sets (mutable, unordered, unique elements): my_set = {1, 2, 3}. Operations: union (|), intersection (&), difference (-), symmetric difference (^). Use sets for membership testing (O(1) lookup) and removing duplicates from a list (list(set(my_list))).
Object-Oriented Programming in Python
OOP in Python (PCAP-level): define classes with class keyword, create objects with the class as a constructor. __init__ is the initialiser (not strictly a constructor — the object is already created when __init__ runs). self refers to the instance — must be the first parameter of every instance method. Instance variables (set on self — unique per object), class variables (set on the class — shared by all instances). Inheritance: class Dog(Animal): inherits all attributes and methods of Animal, can override methods. super() calls the parent class method. Multiple inheritance is supported — Method Resolution Order (MRO) uses C3 linearisation. Magic methods (dunder methods): __str__ (string representation — used by print()), __repr__ (developer representation — used in REPL), __len__ (len() support), __eq__ (equality with ==), __lt__ (less-than for sorting), __add__ (+ operator overloading). Encapsulation conventions: _name (single underscore — convention for 'internal', not enforced), __name (double underscore — name mangling, makes attribute harder to access accidentally from outside the class).
Exception Handling, Modules, and File I/O
Exception handling: try / except / else / finally. except catches specific exceptions (except ValueError, except (TypeError, KeyError)). else block runs if no exception was raised. finally runs always — used for cleanup (close file, release lock). raise re-raises the current exception or raises a new one. Custom exceptions: class MyError(Exception): pass — inherit from Exception or a specific exception class. Common exceptions to know: ValueError (invalid value — int('abc')), TypeError (wrong type — 1 + '2'), KeyError (missing dict key), IndexError (list index out of range), FileNotFoundError (file does not exist), AttributeError (object has no such attribute), ImportError (module not found). Modules: import module (use as module.function()), from module import function (use as function() directly), import module as alias. The if __name__ == '__main__': guard prevents code from running when the module is imported. File I/O: open(path, mode) — modes: 'r' (read), 'w' (write, creates/truncates), 'a' (append), 'b' (binary). Use with open(path) as f: context manager — automatically closes file even if an exception occurs. f.read(), f.readline(), f.readlines(), f.write(). JSON: import json; json.dumps(obj) serialises to string, json.loads(string) deserialises to Python object, json.dump(obj, file) writes to file, json.load(file) reads from file.