CIT_2228_Functions_in_PythonV2
CIT_2228_Functions_in_PythonV2
Martin Wafula
Multimedia University of Kenya
Outline 2
Introduction to Functions
Function Syntax
Best Practices
Practical Examples
Conclusion
What Are Functions? 4
Function Definition 7
Basic Syntax
def function_name(parameters):
"""docstring - describes what the function does"""
# Function body
# ...
return value # optional
Example
def greet(name):
"""Prints a greeting message"""
print(f"Hello, {name}!")
return len(name) # returns length of name
Function Invocation 8
Calling a Function
result = function_name(arguments)
Example
Parameters vs. Arguments 10
Positional
def describe_pet(animal, name):
print(f"I have a {animal} named {name}")
describe_pet("dog", "Rex")
Keyword
describe_pet(name="Rex", animal="dog")
Default Arguments 12
Function Definition
def describe_pet(name, animal="dog"):
print(f"I have a {animal} named {name}")
Function Calls
describe_pet("Rex") # Uses default
describe_pet("Fluffy", "cat") # Overrides default
Variable-Length Arguments 13
def average(*numbers):
return sum(numbers)/len(numbers)
def person_info(**details):
for key, value in details.items():
print(f"{key}: {value}")
Return Statement 16
Example
def min_max(numbers):
return min(numbers), max(numbers)
Example
def increment():
global count
count += 1
Advanced Function Concepts
Lambda Functions 19
Example
square = lambda x: x * x
sorted_names = sorted(names, key=lambda x: x.lower())
Function Decorators 20
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"Time: {time.time()-start}")
return result
return wrapper
@timer
def compute():
# Long computation
Recursion 21
Example
def factorial(n):
if n == 0: # Base case
return 1
return n * factorial(n-1)
Best Practices
Function Design Guidelines 23
Good Documentation
def calculate_area(length, width):
"""
Calculate the area of a rectangle.
Args:
length (float): The length of the rectangle
width (float): The width of the rectangle
Returns:
float: The area of the rectangle
Raises:
ValueError: If either dimension is negative
"""
if length < 0 or width < 0:
raise ValueError("Dimensions must be positive")
return length * width
Practical Examples
Example 1: Temperature Conversion 26
def celsius_to_fahrenheit(celsius):
"""Convert Celsius to Fahrenheit"""
return (celsius * 9/5) + 32
def fahrenheit_to_celsius(fahrenheit):
"""Convert Fahrenheit to Celsius"""
return (fahrenheit - 32) * 5/9
# Usage
print(f"32°F = {fahrenheit_to_celsius(32):.1f}°C")
print(f"100°C = {celsius_to_fahrenheit(100):.1f}°F")
Example 2: Password Generator 27
import random
import string
def generate_password(length=12, use_special=True):
"""
Generate a random password.
Args:
length (int): Length of password (default 12)
use_special (bool): Include special chars (default
Returns:
str: Generated password
"""
chars = string.ascii_letters + string.digits
if use_special:
chars += string.punctuation
return ''.join(random.choice(chars) for _ in range(leng
Conclusion
Summary 29
Understanding Python’s Import System 32
Viewing sys.path
import sys
print(sys.path)
import sys
sys.path.append('/path/to/my/modules')
Detailed Import Mechanisms 34
Absolute Imports
"""Module documentation"""
import sys
def func():
pass
class MyClass:
pass
print(f"Namespace: {dir()}")
print(f"Name: {__name__}")
Package Initialization 36
▶ __init__.py files:
▶ Make directories recognizable as packages
▶ Can be empty or contain initialization code
▶ Executed when package is imported
▶ Can define __all__ to control from package import *
Example __init__.py
"""Package documentation"""
from .module1 import func1
from .module2 import func2
# Package-level initialization
print(f"Initializing {__name__}")
Advanced Import Features 37
Dynamic Imports
# Using __import__()
module_name = "math"
math = __import__(module_name)
print(math.sqrt(16))
# Using importlib
import importlib
math = importlib.import_module("math")
Import Hooks
▶ Customize import behavior
▶ Implement importlib.abc.MetaPathFinder or
importlib.abc.PathEntryFinder
▶ Used by tools like pytest, Django
Python’s Import Cache 38
import sys
import math
print('math' in sys.modules) # True
# Force reload
del sys.modules['math']
import math # Module is reloaded
Warning
Modifying sys.modules can lead to subtle bugs. Use
importlib.reload() instead.
Module Attributes 39
Attribute Purpose
__name__ Module name
__file__ Path to module file
__package__ Package name
__doc__ Module docstring
__annotations__ Variable annotations
__dict__ Module namespace
Inspecting a module
import math
print(math.__name__) # 'math'
print(math.__file__) # Path to math.py
print(math.__doc__) # Documentation
Common Import Patterns 40
Interface Pattern
▶ Use __init__.py to expose clean API
▶ Hide implementation details
Plugin Pattern
▶ Dynamically discover and load modules
▶ Using importlib or pkgutil
Import Gotchas 41
Circular Imports
# module_a.py
import module_b
def func_a():
module_b.func_b()
# module_b.py
import module_a
def func_b():
module_a.func_a()
Solutions
▶ Restructure code to remove circularity
▶ Move imports inside functions
▶ Use import at module level only
Python’s Module Types 42
import math
import mymodule
Package Structure
my_package/
__init__.py # Package initialization
module1.py # Regular module
subpackage/
__init__.py # Subpackage initialization
module2.py
data/
file.txt # Package data files
data = files('my_package.data').joinpath('file.txt')
Modern Python Packaging 44
[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"
[project]
name = "my_package"
version = "1.0.0"
dependencies = [
"requests>=2.25.0",
"numpy>=1.20.0"
]
Publishing a Package
1. Create pyproject.toml
2. Build distributions: python -m build
3. Upload: twine upload dist/*
Questions 46
Any questions?