Skip to content
CS-506 ยท Python/Quick Revision Short Notes

Python (CS-506) - Unit 2 Short Notes

1.0 Object-Oriented Programming (OOP) Deep Dive

1.1 Classes and Objects

  • Class: Blueprint for creating objects. Defined with class keyword.

  • Object: Instance of a class. Created by calling the class.

  • __init__(self, ...): Constructor method. Initializes instance attributes. Called automatically upon instantiation.

    
    class Dog:
    
        def __init__(self, name, breed):
    
            self.name = name   # Instance variable
    
            self.breed = breed
    
    my_dog = Dog("Buddy", "Golden Retriever")  # Instantiation
    
    

1.2 Instance vs. Class Variables

Feature Instance Variable Class Variable
Scope Unique to each object/instance Shared across all instances
Location Inside __init__ or other methods (self.var) Directly in class body
Modification Changes affect only that instance Changes affect all instances

class Student:

    school = "RGPV"  # Class Variable

    def __init__(self, name):

        self.name = name  # Instance Variable

1.3 Types of Methods

Decorator First Parameter Access Typical Use
None (Instance) self Instance & Class vars Operate on object state
@classmethod cls Class vars only Factory methods, alternative constructors
@staticmethod None Neither (unless passed) Utility functions, namespacing

class MyClass:

    count = 0

    def __init__(self):

        type(self).count += 1

    @classmethod

    def get_count(cls):

        return cls.count

    @staticmethod

    def is_valid(obj):

        return hasattr(obj, 'id')

1.4 Inheritance

  • Single: One child inherits from one parent.

  • Multiple: One child inherits from multiple parents. Caution: Diamond problem.

  • Multilevel: Chain of inheritance (Grandparent -> Parent -> Child).

  • super(): Used to call methods from parent class. Essential in MRO.

1.5 Method Resolution Order (MRO) & super()

  • MRO: Order Python searches for methods in inheritance hierarchy. Uses C3 Linearization algorithm.

  • View MRO: ClassName.__mro__ or ClassName.mro().

  • super(): Returns a proxy object to delegate method calls to parent class in the MRO. Crucial for cooperative multiple inheritance.

    
    class A: pass
    
    class B(A): pass
    
    class C(A): pass
    
    class D(B, C): pass
    
    print(D.__mro__) # (D, B, C, A, object)
    
    

1.6 Polymorphism

  • Duck Typing: "If it walks like a duck and quacks like a duck, it's a duck." Object suitability determined by presence of methods/attributes, not type.

    
    def make_sound(animal):
    
        animal.speak()  # Works for any object with .speak()
    
    
  • Operator Overloading: Implement special dunder methods.

    | Operator | Method | | :--- | :--- | | + | __add__(self, other) | | - | __sub__(self, other) | | * | __mul__(self, other) | | == | __eq__(self, other) | | < | __lt__(self, other) | | len(obj) | __len__(self) | | str(obj) | __str__(self) | | repr(obj) | __repr__(self) |

1.7 Encapsulation

  • Public: var (default). Accessible from anywhere.

  • Protected: _var (convention). Should be treated as non-public. Accessible but a hint.

  • Private: __var (name mangling). Python renames to _ClassName__var. Harder to access accidentally.

    
    class Secret:
    
        def __init__(self):
    
            self.public = 1
    
            self._protected = 2
    
            self.__private = 3
    
    

1.8 Properties (@property)

  • Decorator to define getters, setters, deleters for controlled access to attributes.

  • Allows validation or computation without changing the public interface.

    
    class Circle:
    
        def __init__(self, radius):
    
            self._radius = radius
    
        @property
    
        def radius(self):
    
            return self._radius
    
        @radius.setter
    
        def radius(self, value):
    
            if value <= 0: raise ValueError("Radius must be positive")
    
            self._radius = value
    
        @property
    
        def area(self):  # Read-only computed property
    
            return 3.14 * self._radius ** 2
    
    

1.9 Abstract Base Classes (ABCs)

  • From abc module. Define abstract methods that must be overridden by subclasses.

  • Cannot instantiate a class with unimplemented abstract methods.

    
    from abc import ABC, abstractmethod
    
    class Shape(ABC):
    
        @abstractmethod
    
        def area(self):
    
            pass
    
    class Rectangle(Shape):
    
        def __init__(self, w, h): self.w, self.h = w, h
    
        def area(self): return self.w * self.h  # Implementation required
    
    # s = Shape()  # TypeError: Can't instantiate abstract class
    
    

1.10 Data Classes (@dataclass)

  • Decorator (Python 3.7+) to automatically generate __init__, __repr__, __eq__, etc.

  • Reduces boilerplate for classes primarily storing data.

    
    from dataclasses import dataclass
    
    @dataclass
    
    class Point:
    
        x: float
    
        y: float
    
        color: str = 'red'  # Default value
    
    p = Point(1.0, 2.0)  # Auto-generated __init__
    
    

[!TIP] Exam Focus: Be prepared to write code for super() in multiple inheritance, implement a dunder method (like __add__), and convert a regular class to a @dataclass.


2.0 Advanced Functions & Functional Programming Tools

2.1 First-Class Functions & Closures

  • First-Class: Functions can be assigned to variables, passed as arguments, returned from other functions.

  • Closure: Inner function that captures and remembers variables from its enclosing scope, even after the outer function has finished execution.

    
    def outer(msg):
    
        def inner():  # Closure
    
            print(msg)  # Captures 'msg' from outer scope
    
        return inner
    
    closure_func = outer("Hello")
    
    closure_func()  # Prints "Hello"
    
    

2.2 Lambda Functions

  • Anonymous, single-expression functions: lambda arguments: expression.

  • Used for short, throwaway functions, often with map, filter, sorted.

    
    square = lambda x: x**2
    
    pairs = [(1, 'one'), (2, 'two')]
    
    pairs.sort(key=lambda p: p[1])  # Sort by second element
    
    

2.3 Higher-Order Functions: map, filter, reduce

Function Purpose Returns Example
map(func, iterable) Apply func to every item Iterator list(map(str, [1,2,3])) -> ['1','2','3']
filter(func, iterable) Keep items where func(item) is True Iterator list(filter(lambda x: x%2, [1,2,3])) -> [1,3]
reduce(func, iterable) Cumulatively apply func (left to right) Single value from functools import reduce; reduce(lambda a,b: a*b, [1,2,3,4]) -> 24

2.4 Comprehensions & Generator Expressions

  • List Comprehension: [expr for item in iterable if condition]

  • Dict Comprehension: {key: value for item in iterable}

  • Set Comprehension: {expr for item in iterable}

  • Generator Expression: (expr for item in iterable) โ€“ lazy evaluation, memory efficient.

    
    squares_gen = (x*x for x in range(10))  # Generator, not computed yet
    
    

2.5 Decorators

  • Function that takes another function as argument and returns a modified function.

  • Syntax: @decorator above function definition.

    
    def my_decorator(func):
    
        def wrapper():
    
            print("Before")
    
            func()
    
            print("After")
    
        return wrapper
    
    @my_decorator
    
    def say_hello():
    
        print("Hello")
    
    
  • Decorators with Arguments: Need an extra layer of nesting.

    
    def repeat(n):
    
        def decorator(func):
    
            def wrapper(*args, **kwargs):
    
                for _ in range(n): func(*args, **kwargs)
    
            return wrapper
    
        return decorator
    
    @repeat(3)
    
    def greet(): print("Hi")
    
    

2.6 functools Module

  • @wraps: Preserves metadata (__name__, __doc__) of original function in decorators.

    
    from functools import wraps
    
    def deco(func):
    
        @wraps(func)
    
        def wrapper(*args, **kwargs): ...
    
    
  • lru_cache(maxsize): Memoization decorator for expensive pure functions (Least Recently Used cache).

    
    from functools import lru_cache
    
    @lru_cache(maxsize=128)
    
    def fib(n):
    
        if n < 2: return n
    
        return fib(n-1) + fib(n-2)
    
    
  • partial(func, *args, **kwargs): Freeze some arguments of a function, creating a new function with fewer parameters.

2.7 itertools Module

  • Infinite Iterators: count(start=0, step=1), cycle(iterable), repeat(object, times=None).

  • Combinatoric Iterators:

    • product(*iterables, repeat=1): Cartesian product.

    • permutations(iterable, r=None): r-length permutations, no repeated elements.

    • combinations(iterable, r): r-length combinations, no repeated elements, order doesn't matter.

    • combinations_with_replacement(iterable, r): Allows repeated elements.

[!TIP] Exam Focus: Differentiate between map/filter (returns iterator) vs list comprehensions. Know when to use a generator expression for memory efficiency. Understand lru_cache for recursive problems.


3.0 Modules, Packages, and Project Structure

3.1 The import System

  • Absolute Import: Full path from project root. Recommended.

    
    from mypackage.mymodule import myfunction
    
    
  • Relative Import: Using . for current package, .. for parent. Only within a package.

    
    from .sibling import func  # Current package
    
    from ..parent import func  # Parent package
    
    

3.2 __name__ == "__main__" Idiom

  • Code inside this block runs only when the script is executed directly (python script.py), not when imported as a module.

  • Standard pattern for making a module both importable and executable.

    
    def main():
    
        # program logic
    
        pass
    
    if __name__ == "__main__":
    
        main()
    
    

3.3 Packages

  • Package: Directory containing __init__.py (can be empty) and submodules.

  • Subpackage: Nested package directory.

  • __init__.py: Initializes package, can define __all__ (list of public names for from package import *).

3.4 Namespace Packages (PEP 420)

  • Packages without __init__.py file.

  • Can be split across multiple locations on sys.path.

  • Created implicitly when Python finds a directory with modules but no __init__.py.

3.5 Module Search Path (sys.path)

  • List of directory names Python searches for modules.

  • Order: Current directory โ†’ PYTHONPATH โ†’ installation-dependent default.

  • Can be modified at runtime (usually not recommended).

3.6 Virtual Environments (venv)

  • Isolated Python environment with its own site-packages.

  • Purpose: Manage project-specific dependencies without global conflicts.

  • Creation: python -m venv myenv

  • Activation:

    • Windows (cmd): myenv\Scripts\activate.bat

    • Unix/macOS: source myenv/bin/activate

3.7 Dependency Management

  • pip: Package installer. pip install package, pip freeze > requirements.txt.

  • requirements.txt: Lists exact package versions for reproducible environments.

    
    Flask==2.3.3
    
    numpy>=1.24.0
    
    
  • Install all: pip install -r requirements.txt.

3.8 Publishing Packages

  • setup.py/setup.cfg: Traditional setuptools configuration (metadata, dependencies).

  • pyproject.toml: Modern standard (PEP 518, 621). Defines build system requirements and project metadata. Tools: setuptools, flit, poetry.

[!TIP] Common Pitfall: Confusing absolute and relative imports. Use absolute imports for clarity unless there's a strong reason for relative. Always use a virtual environment for projects.


4.0 File I/O and Context Management

4.1 File Modes

Mode Meaning File Position Creates New?
'r' Read (default) Start No
'w' Write (truncate) Start Yes
'a' Append End Yes
'x' Exclusive creation Start Yes, fails if exists
'b' Binary mode - -
't' Text mode (default) - -
'+' Update (read & write) Start -
  • Common combinations: 'rt' (default), 'wt', 'rb', 'w+b'.

4.2 Reading Files

  • f.read(size=-1): Read size bytes/chars. -1/omitted reads entire file.

  • f.readline(): Read single line (includes trailing \n).

  • f.readlines(): Read all lines into list.

  • Iteration (Best for large files): for line in f: reads line by line lazily.

    
    with open('file.txt') as f:
    
        for line in f:  # Memory efficient
    
            print(line.strip())
    
    

4.3 Writing Files

  • f.write(string): Write string to file. Returns number of characters written.

  • f.writelines(iterable): Write each string from iterable. No newlines added automatically.

4.4 Working with Paths

  • os.path (legacy, string-based):

    
    import os.path as op
    
    op.join('dir', 'file.txt')
    
    op.exists('path')
    
    
  • pathlib (modern, object-oriented โ€“ Recommended):

    
    from pathlib import Path
    
    p = Path('dir') / 'file.txt'  # Overloaded /
    
    p.exists()
    
    p.read_text()  # Read entire file
    
    p.write_text('data')  # Write string
    
    p.mkdir(parents=True, exist_ok=True)
    
    

4.5 The with Statement & Context Managers

  • Ensures resources (files, locks, connections) are properly acquired and released.

  • with open(...) as f: automatically calls f.close() on block exit, even on exceptions.

  • Protocol: Object must have __enter__() (returns resource) and __exit__() (handles cleanup) methods.

4.6 Creating Custom Context Managers

  • Class-based:

    
    class Timer:
    
        def __enter__(self):
    
            import time; self.start = time.time()
    
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
    
            self.end = time.time()
    
            print(f"Elapsed: {self.end - self.start:.2f}s")
    
    with Timer():
    
        # code to time
    
        pass
    
    
  • contextlib.contextmanager (decorator for generator functions):

    
    from contextlib import contextmanager
    
    @contextmanager
    
    def managed_file(filename):
    
        f = open(filename, 'w')
    
        try:
    
            yield f  # Resource provided to `with` block
    
        finally:
    
            f.close()
    
    

[!TIP] Exam Focus: Always use with for file operations. Know pathlib.Path methods over os.path. Be able to write a simple custom context manager (both class and @contextmanager styles).


5.0 Advanced Exception Handling

5.1 Exception Hierarchy


BaseException

 โ”œโ”€โ”€ SystemExit

 โ”œโ”€โ”€ KeyboardInterrupt

 โ”œโ”€โ”€ GeneratorExit

 โ””โ”€โ”€ Exception  # Most built-in exceptions inherit from here

      โ”œโ”€โ”€ StopIteration

      โ”œโ”€โ”€ ArithmeticError (ZeroDivisionError, OverflowError)

      โ”œโ”€โ”€ LookupError (IndexError, KeyError)

      โ”œโ”€โ”€ OSError (FileNotFoundError, PermissionError)

      โ”œโ”€โ”€ RuntimeError

      โ”œโ”€โ”€ TypeError

      โ”œโ”€โ”€ ValueError

      โ””โ”€โ”€ ... (many others)

5.2 try/except/else/finally

  • Order: try โ†’ (one or more except) โ†’ (else?) โ†’ (finally?).

  • else: Runs if try block did not raise an exception.

  • finally: Always runs (cleanup code), regardless of exception. Runs after else if present.

    
    try:
    
        result = 10 / 0
    
    except ZeroDivisionError as e:
    
        print(f"Caught: {e}")
    
    else:
    
        print("No error")  # Not executed here
    
    finally:
    
        print("Cleanup")  # Always executed
    
    

5.3 Catching Multiple Exceptions

  • Multiple except clauses:

    
    try: ...
    
    except TypeError: ...
    
    except ValueError: ...
    
    
  • Exception tuple (handle same way):

    
    try: ...
    
    except (TypeError, ValueError) as e:
    
        print(f"Type or Value error: {e}")
    
    

5.4 The as Keyword

  • Captures the exception instance for inspection.

    
    try:
    
        int("abc")
    
    except ValueError as e:
    
        print(e.args)  # ('invalid literal for int() with base 10: \'abc\'',)
    
        print(type(e)) # <class 'ValueError'>
    
    

5.5 Raising & Chaining Exceptions

  • raise: Re-raise current exception (in except block) or raise new one.

  • raise NewException from original_exception: Explicit exception chaining. Preserves original traceback.

    
    try:
    
        open("missing.txt")
    
    except FileNotFoundError as e:
    
        raise RuntimeError("Failed to open file") from e
    
    # Output shows both exceptions and "The above exception was the direct cause..."
    
    

5.6 Custom Exception Classes

  • Inherit from Exception (or a more specific built-in).

    
    class InsufficientFundsError(Exception):
    
        def __init__(self, balance, amount):
    
            self.balance = balance
    
            self.amount = amount
    
            super().__init__(f"Balance {balance}, tried to withdraw {amount}")
    
    

5.7 The warnings Module

  • Issue warnings (not errors) for potential issues.

    
    import warnings
    
    warnings.warn("This is a warning", DeprecationWarning)
    
    
  • Control filtering: warnings.filterwarnings('ignore', category=DeprecationWarning).

[!TIP] Common Pitfall: Using a bare except: (catches BaseException, including SystemExit/KeyboardInterrupt). Always specify exception type(s). Use finally for critical cleanup (closing files, releasing locks).


6.0 Testing, Debugging, and Profiling

6.1 Unit Testing with unittest

  • Structure: Inherit from unittest.TestCase.

  • Methods start with test_.

  • Assertions: assertEqual(a, b), assertTrue(x), assertRaises(exception).

  • Setup/Teardown:

    
    import unittest
    
    class TestMath(unittest.TestCase):
    
        def setUp(self):  # Runs before *each* test
    
            self.value = 5
    
        def test_something(self):
    
            self.assertEqual(self.value * 2, 10)
    
        def tearDown(self):  # Runs after *each* test
    
            del self.value
    
    
  • Run: python -m unittest test_module.py or discover.

6.2 pytest (Third-Party)

  • Simpler syntax. Functions, not necessarily classes.

  • Fixtures: @pytest.fixture for setup/teardown. Scope control (function, module, session).

  • Assertions: Simple assert statements with rich introspection.

  • Parametrization: @pytest.mark.parametrize("input,expected", [(1,2), (3,4)]).

6.3 Test Coverage (coverage.py)

  • Measures how much code is executed by tests.

  • Run: coverage run -m pytest, then coverage report -m (shows missing lines).

  • HTML report: coverage html.

6.4 Debugging with pdb

  • Python Debugger. Insert import pdb; pdb.set_trace() or breakpoint() (Python 3.7+).

  • Key Commands:

    • n (next), s (step into), c (continue)

    • l (list code), p expr (print expression)

    • q (quit), h (help)

  • Can also run script directly: python -m pdb script.py.

6.5 Logging (logging module)

  • Levels (increasing severity): DEBUG < INFO < WARNING < ERROR < CRITICAL.

  • Basic Config: logging.basicConfig(level=logging.INFO)

  • Recommended Setup:

    
    import logging
    
    logger = logging.getLogger(__name__)  # Per-module logger
    
    logger.setLevel(logging.DEBUG)
    
    handler = logging.FileHandler('app.log')
    
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    handler.setFormatter(formatter)
    
    logger.addHandler(handler)
    
    logger.info("Application started")
    
    

6.6 Profiling

  • cProfile: Execution time, function calls.

    
    python -m cProfile -s cumulative my_script.py
    
    
  • memory_profiler: Line-by-line memory usage. Decorate function with @profile. Run: python -m memory_profiler script.py.

[!TIP] Exam Focus: Know the basic unittest structure. Understand when to use pdb vs logging. Know the difference between DEBUG and INFO levels. coverage.py measures line execution, not correctness.


7.0 Concurrency and Parallelism

7.1 Concurrency vs. Parallelism & GIL

  • Concurrency: Dealing with multiple tasks at once (may interleave on single CPU). I/O-bound tasks.

  • Parallelism: Doing multiple tasks simultaneously on multiple CPUs. CPU-bound tasks.

  • GIL (Global Interpreter Lock): Mutex in CPython that allows only one thread to execute Python bytecode at a time. Limits CPU-bound multi-threading but doesn't affect I/O or multi-processing.

7.2 Threading (threading)

  • Use Case: I/O-bound (network, file I/O). Overcomes GIL during I/O waits.

  • Basic Usage:

    
    import threading
    
    def task():
    
        print(threading.current_thread().name)
    
    t = threading.Thread(target=task, name="MyThread")
    
    t.start()
    
    t.join()  # Wait for completion
    
    
  • Synchronization Primitives (prevent race conditions):

    • Lock: Basic mutual exclusion. acquire(), release() (or use with lock:).

    • RLock: Re-entrant lock (same thread can acquire multiple times).

    • Semaphore: Allows n threads concurrent access.

    • Event, Condition, Barrier.

7.3 Multiprocessing (multiprocessing)

  • Use Case: CPU-bound tasks. Bypasses GIL by using separate memory space (processes).

  • Basic Usage:

    
    from multiprocessing import Process
    
    def f(name):
    
        print(f'Hello {name}')
    
    p = Process(target=f, args=('Bob',))
    
    p.start()
    
    p.join()
    
    
  • Queue: Process-safe communication (unlike threading where data is shared).

  • Pool: Manages worker processes. pool.map(func, iterable).

7.4 Asynchronous Programming (asyncio)

  • Use Case: High-concurrency I/O-bound (thousands of connections). Single-threaded event loop.

  • Coroutines: async def func(): .... Defined with async.

  • await: Pauses coroutine, yields control to event loop until result ready.

  • Event Loop: Runs tasks. asyncio.run(main()) (Python 3.7+).

    
    import asyncio
    
    async def fetch_data():
    
        await asyncio.sleep(1)  # Simulate I/O
    
        return {'data': 1}
    
    async def main():
    
        task1 = asyncio.create_task(fetch_data())
    
        task2 = asyncio.create_task(fetch_data())
    
        res1, res2 = await asyncio.gather(task1, task2)
    
    asyncio.run(main())
    
    

7.5 Concurrent Futures (concurrent.futures)

  • High-level interface for async execution.

  • ThreadPoolExecutor: For I/O-bound.

    
    from concurrent.futures import ThreadPoolExecutor
    
    with ThreadPoolExecutor(max_workers=4) as executor:
    
        future = executor.submit(func, arg)
    
        result = future.result()  # Blocks until done
    
    
  • ProcessPoolExecutor: For CPU-bound.

  • executor.map(func, iterable) returns iterator of results.

[!TIP] Key Decision Flow:

I/O-bound? โ†’ threading (simple) or asyncio (high concurrency).

CPU-bound? โ†’ multiprocessing or ProcessPoolExecutor.

Remember: GIL prevents CPU-bound threads from running in parallel.


8.0 Additional Advanced Topics

8.1 Metaclasses

  • Metaclass: Class of a class. Defines how classes behave. Default metaclass is type.

  • Custom Metaclass: Inherit from type, override __new__(mcs, name, bases, attrs) or __init__.

  • Use Case: API enforcement, automatic registration, ORM field mapping.

    
    class Meta(type):
    
        def __new__(mcs, name, bases, attrs):
    
            attrs['registry'] = {}
    
            return super().__new__(mcs, name, bases, attrs)
    
    class MyClass(metaclass=Meta):
    
        pass
    
    

8.2 Descriptors

  • Object that defines any of __get__, __set__, __delete__.

  • Used to manage attribute access. Foundation for @property, classmethod, staticmethod.

  • Data Descriptor: Implements __set__. Takes precedence over instance dict.

  • Non-Data Descriptor: Only __get__. Instance dict takes precedence.

    
    class Descriptor:
    
        def __get__(self, obj, objtype=None):
    
            return self.value
    
        def __set__(self, obj, value):
    
            self.value = value
    
    class MyClass:
    
        attr = Descriptor()
    
    

8.3 Type Hints (typing module)

  • Purpose: Static analysis (mypy), IDE autocomplete, documentation. Not enforced at runtime.

  • Basic: def func(name: str, age: int) -> bool: ...

  • Containers: List[int], Dict[str, float] (use from typing for Python <3.9).

  • Optional[T]: Union[T, None]. def f(x: Optional[int] = None) -> None: ...

  • Any: Disables type checking.

  • Generics: from typing import TypeVar, Generic

    
    T = TypeVar('T')
    
    class Box(Generic[T]):
    
        def __init__(self, item: T): self.item = item
    
        def get(self) -> T: return self.item
    
    
  • TypedDict: For dictionaries with specific keys.

  • Protocol: Structural subtyping (duck typing with types).

8.4 Working with Databases

  • DB-API 2.0 (PEP 249): Standard for Python database drivers.

  • sqlite3 (built-in): Lightweight disk-based DB.

    
    import sqlite3
    
    conn = sqlite3.connect('test.db')
    
    cur = conn.cursor()
    
    cur.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
    
    cur.execute("INSERT INTO users (name) VALUES (?)", ("Alice",))
    
    conn.commit()
    
    for row in cur.execute("SELECT * FROM users"): print(row)
    
    conn.close()
    
    
  • ORMs (e.g., SQLAlchemy): Map tables to classes. Higher-level, database-agnostic.

8.5 Introduction to Web Frameworks

  • Flask (Microframework): Lightweight, flexible. Routes via @app.route('/'). request object, render_template.

  • Django (Full-stack): Batteries-included (ORM, admin, auth). MTV pattern (Model-Template-View). urls.py, views.py, models.py.

  • Core Concept: HTTP request/response cycle, routing, templating, (for Django) ORM and admin.

8.6 subprocess Module

  • Run external commands, capture output.

  • Preferred: subprocess.run() (Python 3.5+).

    
    import subprocess
    
    result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
    
    print(result.stdout)
    
    if result.returncode != 0:
    
        print(f"Error: {result.stderr}")
    
    
  • Security: Avoid shell=True with untrusted input (risk of shell injection).

[!TIP] Exam Focus: Metaclasses and descriptors are advanced; understand the concept and simple use cases. Type hints are increasingly important. For DBs, know the basic sqlite3 flow (connect, cursor, execute, commit, close). subprocess.run is the modern way to shell out.

Go to where you left off?

Quick Add to Notes

Save questions, your own notes and screenshots into notes filed by unit. It takes a free account.

Create free account

Have an account? Log in