Skip to content
ME-506 · Python/Quick Revision Short Notes

Python (ME-506) - Unit 3 Short Notes

UNIT 3: Python Programming - Intermediate Concepts & Practical Application


3.1. Object-Oriented Programming (OOP) - The Paradigm Shift

3.1.1. Core Concepts & Motivation
  • Class: A blueprint/template for creating objects. Defines attributes (data) and methods (functions).

  • Object (Instance): A concrete realization of a class. Each object has its own state (attribute values).

  • __init__() Method: The constructor. Called automatically when a new object is created (obj = ClassName()). Used to initialize instance attributes.

    
    class Student:
    
        def __init__(self, name, roll_no):  # Constructor
    
            self.name = name    # Instance attribute
    
            self.roll_no = roll_no
    
    
3.1.2. Defining Classes & Creating Objects
  • Syntax: class ClassName(ParentClass): (ParentClass is optional for inheritance).

  • self Parameter: The first parameter of any instance method. Refers to the specific object instance on which the method is called. Python passes it automatically.

    
    s1 = Student("Alice", 101)  # __init__(self, "Alice", 101) is called
    
    print(s1.name)  # Output: Alice
    
    
3.1.3. Key OOP Principles
Principle Concept Python Mechanism Key Idea
Encapsulation Bundling data + methods; restricting direct access. Naming conventions: _var (protected), __var (name mangling). @property for getters/setters. Hide internal state, expose controlled interface.
Inheritance Creating new classes (child) from existing ones (parent). class Child(Parent): Promotes code reuse. Child inherits parent's attributes/methods.
Method Overriding Child defines a method with the same name as parent's. Child's version is called on child objects.
super() super().__init__(params) calls the parent's constructor/method. Enables cooperative multiple inheritance.
Polymorphism "Many forms". Same operation behaves differently on different types. Duck Typing: "If it walks like a duck...". No explicit interface checks. len(obj) works for list, string, custom class with __len__.
Abstraction Hiding complex implementation, showing only essentials. Achieved via encapsulation and well-defined interfaces. Focus on what an object does, not how.

[!TIP] Common Pitfall: Forgetting self as the first parameter in instance methods causes TypeError. __init__ must return None.


3.2. Advanced Functions & Scoping

3.2.1. Lambda Functions
  • Definition: Small, anonymous, single-expression functions.

  • Syntax: lambda arguments: expression

  • Use Cases: Short functions for map(), filter(), sorted(key=), tkinter callbacks.

    
    square = lambda x: x**2
    
    nums = [1, 2, 3]
    
    squares = list(map(lambda x: x**2, nums))  # [1, 4, 9]
    
    sorted(students, key=lambda s: s.gpa)      # Sort by GPA
    
    

[!TIP] Rule: Lambda can only contain an expression, not statements (like if-else blocks, for loops). Use a regular def for complex logic.

3.2.2. Comprehensions & Generator Expressions
Type Syntax Result Type Evaluation
List [expr for item in iterable if cond] list Eager (builds full list)
Dict {key: val for item in iterable} dict Eager
Set {expr for item in iterable} set Eager
Generator (expr for item in iterable) generator Lazy (yields values on-demand)

gen = (x**2 for x in range(5))  # Creates generator object

print(next(gen))  # 0

print(next(gen))  # 1 (computed only when needed)

3.2.3. Variable Scope & Namespaces (LEGB Rule)

Python resolves names by searching scopes in this order:

  1. Local: Inside current function.

  2. Enclosing: In enclosing (outer) function scopes.

  3. Global: At the top level of the module/file.

  4. Built-in: In Python's built-in names (e.g., len, print).

  • global keyword: Modify a global variable from within a function.

    
    count = 0
    
    def inc():
    
        global count
    
        count += 1  # Now modifies global 'count'
    
    
  • nonlocal keyword: Modify a variable from an enclosing (non-global) scope.

    
    def outer():
    
        x = 10
    
        def inner():
    
            nonlocal x
    
            x = 20  # Modifies 'x' in outer()
    
        inner()
    
        print(x)  # 20
    
    

3.3. Error Handling & Exceptions

3.3.1. Understanding Exceptions
  • Syntax Errors: Code structure violations (caught by parser). Not exceptions.

  • Exceptions: Runtime errors. Occur during execution.

    • Common Built-ins: ValueError, TypeError, IndexError, KeyError, FileNotFoundError, IOError, ZeroDivisionError, Exception (base for all user-defined).
3.3.2. Try-Except Blocks

try:

    # Code that might raise an exception

    result = 10 / 0

except ZeroDivisionError as e:

    # Handle specific exception

    print(f"Cannot divide by zero: {e}")

except (TypeError, ValueError):

    # Handle multiple exceptions

    print("Type or value error occurred.")

except Exception as e:

    # Catch-all (use cautiously)

    print(f"Unexpected error: {e}")

else:

    # Executes ONLY if try block had NO exception

    print("Operation successful.")

finally:

    # ALWAYS executes (cleanup: close files, release resources)

    print("Cleanup complete.")

[!TIP] Order Matters: Catch specific exceptions before general ones (Exception). finally runs even if an exception is caught or uncaught (but not on sys.exit() or keyboard interrupt).

3.3.3. Raising Exceptions
  • raise: Signal an error condition.

    
    def set_age(age):
    
        if age < 0:
    
            raise ValueError("Age cannot be negative")
    
        self.age = age
    
    
  • Re-raising: Use raise without arguments inside an except block to propagate the caught exception up the call stack.


3.4. File Input/Output (I/O) & Data Persistence

3.4.1. Working with Text Files
  • Opening Files: open(filename, mode)

    • Modes: 'r' (read), 'w' (write, truncate), 'a' (append), 'r+' (read/write), 'b' (binary, e.g., 'rb').
  • Context Manager (with statement): BEST PRACTICE. Automatically closes file, even on errors.

    
    with open('data.txt', 'r') as f:
    
        content = f.read()  # Read entire file
    
        # f is automatically closed here
    
    
  • Reading Methods:

    • f.read(size): Read size bytes/entire file.

    • f.readline(): Read one line (including \n).

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

  • Writing Methods:

    • f.write(string): Write a string.

    • f.writelines(list_of_strings): Write multiple strings (no newlines added automatically).

3.4.2. Working with Structured Data
Format Module Key Functions Notes
CSV csv csv.reader(f), csv.writer(f) Handles commas, quotes. Use with on file.
JSON json json.load(f) (read), json.dump(obj, f) (write) Converts between Python objects (dict, list) and JSON strings. indent for pretty-print.
Pickle pickle pickle.dump(obj, f), pickle.load(f) Serializes ANY Python object. SECURITY RISK: Never unpickle data from untrusted sources.

3.5. Modules, Packages, and the Standard Library

3.5.1. Modular Programming
  • Module: A .py file containing Python definitions and statements.

  • Importing:

    
    import module                 # Use: module.func()
    
    from module import func       # Use: func()
    
    from module import *          # Use: all public names (discouraged)
    
    
  • if __name__ == "__main__": idiom: Code inside this block runs only when the file is executed directly (not when imported as a module). Used for test code or demo.

3.5.2. Packages
  • Package: A directory containing:

    1. Module files (.py).

    2. A special __init__.py file (can be empty). This tells Python the directory is a package.

  • Hierarchical Import: from package.subpackage import module

3.5.3. Key Standard Library Modules (Examples)
Module Purpose Example
os / os.path OS interactions (dirs, paths, env vars). os.getcwd(), os.path.join(a, b)
sys System params, command-line args. sys.argv, sys.exit()
datetime Date/time objects & arithmetic. datetime.datetime.now()
math Mathematical functions (floor, sqrt, trig). math.pi, math.log10()
random Pseudo-random number generation. random.randint(1, 10), random.choice(list)
collections Specialized containers. collections.Counter, collections.defaultdict
itertools Efficient looping/iteration tools. itertools.permutations(), itertools.chain()

3.6. Introduction to Virtual Environments & Package Management

3.6.1. Why Virtual Environments?

Isolate project dependencies. Prevents version conflicts between projects (e.g., Project A needs numpy==1.20, Project B needs numpy==1.24).

3.6.2. Using venv

# Create a virtual environment named 'venv' in current directory

python -m venv venv

# Activate (Linux/macOS)

source venv/bin/activate

# Activate (Windows)

venv\Scripts\activate

# Deactivate (any OS)

deactivate

[!TIP] Naming Convention: Common to name the environment directory venv or .venv and add it to .gitignore.

3.6.3. Using pip
Command Purpose
pip install package_name Install latest version from PyPI.
pip install package_name==1.2.3 Install specific version.
pip list List all installed packages in current environment.
pip freeze > requirements.txt Export exact versions of all installed packages.
pip install -r requirements.txt Install packages from a requirements file.
pip uninstall package_name Remove a package.

[!TIP] Critical: Always activate the correct virtual environment before running pip install. pip installs to the currently active environment.

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