ADVANCED PROGRAMMING TECHNIQUES
PYTHON MODULAR PROGRAMMING
[Link] TIZIANA D’ALESSANDRO (PHD), UNIVERSITÀ DEGLI STUDI DI CASSINO E DEL LAZIO MERIDIONALE
[Link]@[Link]
CONTENTS
Modular code
Functions
Modules
Main
Benefits
Best Practices
Conclusion
2
MODULAR CODE
3
MODULAR CODE
Goal Key Concepts
• Write cleaner • Functions
• Reusable • Modules
• Organised code • Libraries
• Main entry point
MODULAR CODE
ADVANTAGES
Breaking a large program into smaller, Readability: Code is easier to follow
independent, and manageable parts (modules). when it is categorized.
Analogy: Instead of one giant machine, you Maintainability: Fix a bug in one
build small components that plug together. function without breaking the whole
script.
Benefit: Easier to debug, test, and reuse.
Collaboration: Different team
members can work on different
modules simultaneously.
FUNCTIONS
6
FUNCTIONS
The building blocks: Functions
A named block of code that performs a
specific task. Purpose: To avoid repeating the same code
It only runs when it is "called.“ (DRY: Don't Repeat Yourself).
A function can return data as a result.
FUNCTIONS – HOW TO CREATE A FUNCTION
Syntax Breakdown
def: The keyword to define the function. a function is defined using the def
keyword, followed by a function name
Parameters: Inputs the function receives. and parentheses
return: Sends a value back to the caller.
FUNCTIONS – HOW TO CALL A FUNCTION
FUNCTIONS – PARAMETERS/ARGUMENTS
Information can be passed into functions as arguments. From a function's
perspective:
Arguments are specified after the function name, inside the
parentheses.
A parameter is the
You can add as many arguments as you want, just separate variable listed inside
them with a comma. the parentheses in the
function definition.
An argument is the
actual value that is
sent to the function
when it is called.
FUNCTIONS – *ARGS AND **KWARGS
By default, a function must be called with the correct number of arguments.
However, sometimes you may not know how many arguments that will be
passed into your function.
*args and **kwargs allow functions to accept a unknown number of
arguments.
FUNCTIONS – *ARGS AND **KWARGS
If you do not know how many arguments will be passed into your function, add a * before
the parameter name.
This way, the function will receive a tuple of arguments and can access the items
accordingly
FUNCTIONS – *ARGS AND **KWARGS
The *args parameter allows a
function to accept any
number of positional
arguments.
Inside the function, args
becomes a tuple containing
all the passed arguments:
FUNCTIONS – LOCAL/GLOBAL VARIABLES
Local Variables: Created
inside a function and A variable created inside a function belongs to the local scope of
only exist there. that function, and can only be used inside that function.
Global Variables: global variables are variables defined outside of any function or
Created outside and class. They are typically placed at the top level of a script or
accessible everywhere. module.
Best Practice:
Favour local variables to
keep modules
independent.
FUNCTIONS – GLOBAL VARIABLES
Global variables can be accessed from anywhere within the same module (the .py file), including inside
functions.
▪ Scope: They belong to the __main__ scope or the specific module they are defined in.
▪ Reading: You can read a global variable inside a function without any special keywords.
FUNCTIONS – GLOBAL VARIABLES
▪ To modify a global variable inside a function, you must use the global keyword.
▪ If you don't use the global keyword, Python will assume you are creating a new local variable with the
same name, leaving the global one untouched (this is called "shadowing").
FUNCTIONS – GLOBAL VARIABLES
▪ While global variables are easy to use, they are often considered "bad practice" in larger programs
because:
▪ They make debugging difficult (any function can change them).
▪ They make code less modular.
▪ They can lead to "spaghetti code.“
▪ Note: If you are working with variables across different files, you should import the module and
access the variable as module_name.variable_name.
FUNCTIONS – DECORATORS
A decorator is a function that takes another function as an argument and extends its behaviour without
explicitly modifying it. A decorator is a function that takes another function as input and returns a new
function.
▪ Syntax: Uses the @decorator_name symbol above a function definition.
▪ The Concept: It "wraps" a function in a container of new logic.
▪ Real-world analogy: Putting on a coat. You are still "you" (the function), but now you have the "extra
feature" of being waterproof (the decorator).
▪ Decorators help you keep your code DRY (Don't Repeat Yourself). Instead of writing the same logic in
ten different functions, you write it once in a decorator.
FUNCTIONS – DECORATORS
Common Use Cases: A decorator technically does this:
▪ Logging: Record every time a [Link] a function as input.
function is called. [Link] an internal wrapper
▪ Authentication: Check if a user is function.
logged in before running a sensitive [Link] the wrapper, it calls the
function. original function.
▪ Timing: Measure how long a piece of [Link] the wrapper function to
code takes to execute. replace the original.
▪ Caching: Store results of expensive
calculations to reuse them later.
FUNCTIONS – DECORATORS
--- The function is about to start!
---
Hello World!
--- The function has finished! ---
Decorator
Decorated
FUNCTIONS – LAMBDA
A lambda function is a small, anonymous
function that can have any number of Syntax:
arguments, but can only have one single
lambda arguments : expression
expression.
▪ Syntax: lambda arguments: expression
▪ Anonymous: It doesn't need a name
(unless you assign it to a variable).
▪ Implicit Return: You don't type the
return keyword; the result of the
expression is returned automatically.
▪ A lambda function can take any
number of arguments, but can only
have one expression.
FUNCTIONS – LAMBDA
A lambda function is a small, anonymous
function that can have any number of
arguments, but can only have one single
expression.
▪ Syntax: lambda arguments: expression
▪ Anonymous: It doesn't need a name
(unless you assign it to a variable).
▪ Implicit Return: You don't type the
return keyword; the result of the
expression is returned automatically.
▪ A lambda function can take any
number of arguments, but can only
have one expression.
FUNCTIONS – LAMBDA
▪ Lambdas are rarely used alone. Their true power comes when they are passed as arguments to Higher-
Order Functions like map(), filter(), or sort().
▪ Sorting: Sort a list of tuples by the second element.
▪ Filtering: Quickly extract items from a list that meet a [Link]
▪ Logic: Great for GUI buttons or data processing where a full function would be "overkill."
FUNCTIONS – LAMBDA WITH FILTER()
▪ The filter() function creates a list of items for which a function returns True:
FUNCTIONS – LAMBDA WITH SORTED()
▪ The filter() function creates a list of items for which a function returns True:
FUNCTIONS – RECURSION
▪ Recursion is a fundamental concept in computer science where a function calls itself to solve a
problem. It occurs when a function is defined in terms of itself. It breaks a complex problem down
into smaller, identical sub-problems.
▪ The Concept: Instead of using a for or while loop, the function repeats its logic by calling itself with a
"smaller" input.
▪ The Structure: Every recursive function must have two parts:
▪ Base Case: The condition that stops the recursion.
▪ Recursive Step: The part where the function calls itself with a modified argument.
FUNCTIONS – RECURSION
Without a Base Case, a recursive
function would call itself forever,
leading to a RecursionError (the
famous Stack Overflow).
𝑛! = 𝑛 ∗ 𝑛 − 1 ∗ 𝑛 − 2 ∗ … ∗ 1
4! = 4 ∗ 4 − 1 ∗ 4 − 2 ∗ 4 − 3
FUNCTIONS – RECURSION
When a function calls itself, Python doesn't "finish" the first call immediately. It "suspends" the
current function and moves to the next one, piling them up in the Call Stack:
1. factorial(4) waits for factorial(3)
2. factorial(3) waits for factorial(2)
3. factorial(2) waits for factorial(1)
4. factorial(1) returns 1 (Base case reached!)
5. The values then "bubble up" back through the stack to calculate the final result.
The base case is crucial. Always make sure your recursive
function has a condition that will eventually be met.
FUNCTIONS – RECURSION VS ITERATION
Feature Recursion Iteration (Loops)
Code Style Often more elegant and shorter. Can be more "wordy" or complex.
Memory Uses more memory (Stack space). Very memory efficient.
Tree structures, sorting
Best For Simple counting, searching lists.
(QuickSort), Fractals.
Python Hint: Python has a default limit of 1000 recursive calls to protect
your memory. You can check it using [Link]().
FUNCTIONS – RECURSION VS ITERATION
What happens if I call factorial(2000)?
FUNCTIONS – GENERATOR
A Generator is a function that behaves like an iterator. It allows you to loop over a sequence of values
without storing the entire sequence in memory.
▪ The Key Keyword: Instead of return, generators use yield.
▪ The Difference:
▪ return kills the function and sends back a value.
▪ yield pauses the function, saves its state, and sends a value back. When called again, the function
resumes right where it left off.
FUNCTIONS – GENERATOR
▪ Generators are functions that can pause
and resume their execution.
▪ When a generator function is called, it
returns a generator object, which is an
iterator.
▪ The code inside the function is not
executed yet, it is only compiled. The
function only executes when you iterate
over the generator.
FUNCTIONS – GENERATOR
Why Use Generators? Memory Efficiency
Generators are "lazy." They only calculate the next value when you specifically ask for it.
▪ Standard List: If you create a list of 1 million integers, it sits in your RAM, consuming space.
▪ Generator: It only remembers the current number and the logic to get to the next one. It uses almost
zero memory, regardless of whether you are generating 10 or 10 billion items.
FUNCTIONS – GENERATOR
A generator function looks exactly like a normal
function but contains at least one yield
statement.
Once a generator reaches the end, it raises a
StopIteration error, which tells loops to stop.
34
FUNCTIONS – GENERATOR –NEXT() AND LOOPS
You can interact with a generator in two main ways:
Manual: Use the next() function to get the next
value.
Automatic: Use a for loop. The loop automatically
handles calling next() and stops when the generator
is empty.
35
MODULES
From Script to Module
▪ A Module is simply a .py file containing functions and variables that you want to include in your
application
▪ Consider a module to be the same as a code library.
▪ By saving your code in sensor_utils.py, you have created a module.
Eg. Creating a Modular Script
The Setup:
1. [Link]: Contains your mathematical functions.
2. [Link] or [Link]: Your "main" script that uses those functions.
This separation keeps your "Engine" (logic) separate from your "User Interface" (app).
MODULES
Eg. Creating a Modular Script
The Setup:
1. [Link]: Contains your mathematical functions.
2. [Link] or [Link]: Your "main" script that uses those functions.
This separation keeps your "Engine" (logic) separate from your "User Interface" (app).
[Link] [Link]
MODULES - IMPORT
Different Ways to Import
▪ To use calculate_average() from [Link] you
▪ import math: Imports the whole module.
have to import the logic script
▪ from math import sqrt: Imports only a
▪ This tells Python to load the functions from
specific function.
that specific file.
▪ import numpy as np: Imports with a shorter
nickname (alias).
[Link] [Link]
MODULES – DIR()
▪ dir() is a built-in function to list all the
function names (or variable names)
in a module.
▪ It can be used on all modules, also
the ones you create yourself.
LIBRARIES
▪ Library Definition: A collection of related modules bundled together.
▪ Analogy: If a function is a tool and a module is a toolbox, a library is the entire hardware store.
▪ Standard Library: Python comes with many built-in libraries (like os, math, datetime).
Using External Libraries
▪ The Power of Community: You don't have to build everything.
▪ Examples:
▪ Pandas: For data analysis.
▪ Requests: For web communication.
▪ TensorFlow: For AI.
MAIN
▪ In many languages (C++, Java), the main function is the mandatory starting point.
▪ In Python, it is a convention to organize the "entry point" of your script.
▪ Safety: Prevents test code or print statements from
running when you just want to use a function in
another file.
▪ Cleanliness: Separates the definitions
(functions/classes) from the execution (running the
program).
▪ This ensures code only runs if the script is executed
directly.
▪ If the script is imported as a module, the main() part
won't run automatically.
ORGANISING PROJECT FOLDER
▪ Standard Modular structure
BENEFITS
Reusability Testing
Encapsulation
Using the same You can test
Hiding complex logic
[Link] across five individual modules in
inside functions.
different projects. isolation.
BEST PRACTICES
Single Responsibility: Each module should do one thing
well (e.g., db_utils.py only handles database code).
Docstrings: Use triple quotes """ to explain what your
functions do.
Consistent Naming: Keep filenames lowercase and
descriptive.
CONCLUSION
Think Modular!
▪ Modular code is the difference between a beginner's script and a
professional application.
▪ Start Small: Turn repeated code into functions.
▪ Scale Up: Move those functions into separate files (modules).
CONCLUSIONS – Q&A
Questions?
THANK YOU
[Link]@[Link]