7.function Notes
7.function Notes
Functions :
What is a Function?
A function is a reusable block of code designed to perform a specific task.
Functions help in organ reducing redundancy, and enhancing readability and
maintainability. They allow you to encapsulate logic and reuse it wherever needed,
making your code modular and efficient.
Functions: 1
In Python, functions are created using the def keyword followed by the function
name and parentheses. Optionally, you can include parameters in the
parentheses. The function body is indented and contains the code to be executed.
Syntax:
def function_name(parameters):
# Function body
# Code to execute
return value # Optional
Example:
def greet(name):
return f"Hello, {name}!"
Here, greet is the function name, and name is a parameter. The function returns a
greeting message.
Features of Functions
1. Encapsulation: Functions encapsulate a specific task or logic, making code
easier to manage and understand.
Functions: 2
6. Return Values: Functions can return values to the caller, which can be used in
further computations or outputs.
3. Modular Design: Functions help in breaking down large programs into smaller,
manageable parts, making development and debugging easier.
Functions: 3
Parameters define the type and number Arguments are the specific
Role of inputs a function can accept. They are values provided to the
part of the function's signature. function when it is executed.
Example in In def add(num1, num2):, num1 and In add(5, 3), 5 and 3 are
Code num2 are parameters. arguments.
Parameters and arguments are related concepts but refer to different aspects of
functions:
Parameters: These are the names used in a function definition to specify what
kind of arguments the function expects. They act as placeholders for the
actual values that will be passed into the function when it is called.
Example:
Functions: 4
def greet(name): # 'name' is a parameter
print(f"Hello, {name}!")
a. Positional Arguments
These arguments are passed to functions based on their position. The order of
arguments matters.
Example:
b. Keyword Arguments
These arguments are passed by explicitly naming each parameter and providing a
value. The order of these arguments does not matter.
Example:
Functions: 5
greet(message="Good morning", name="princ") # Output: Good m
orning, Bob!
c. Default Arguments
These arguments have default values defined in the function. If the caller does not
provide a value, the default is used.
Example:
def greet(name="Guest"):
print(f"Hello, {name}!")
d. Variable-Length Arguments
These arguments allow you to pass a variable number of arguments to a function.
They are used with *args for positional arguments and **kwargs for keyword
arguments.
Example:
pythonCopy code
def add(*numbers):
return sum(numbers)
Functions: 6
pythonCopy code
def print_info(**info):
for key, value in info.items():
print(f"{key}: {value}")
1. Local Scope
Definition: Variables created inside a function belong to the local scope of
that function. They can only be accessed inside that function.
Example:
pythonCopy code
def my_function():
x = 10 # Local variable
print(x) # This works
my_function() # Output: 10
# print(x) # This will raise an error because x is not acces
sible outside the function
Example:
Functions: 7
pythonCopy code
def outer_function():
x = 20 # Enclosing variable
def inner_function():
nonlocal x # Refers to the x in the outer function
x = 30 # Modifying the enclosing variable
print("Inner:", x)
inner_function()
print("Outer:", x)
3. Global Scope
Definition: Variables defined at the top level of a script or module, outside of
any function, belong to the global scope. These variables can be accessed
throughout the code, including inside functions (unless shadowed by a local
variable).
Example:
pythonCopy code
x = 50 # Global variable
def my_function():
global x # Refers to the global variable
x = 60 # Modifying the global variable
print("Inside function:", x)
Functions: 8
print("Outside function:", x) # Output: Outside function: 60
4. Built-in Scope
Definition: The built-in scope contains names that are pre-defined in Python,
such as built-in functions ( print() , len() , etc.) and exceptions. These are
always available and accessible from any part of the code.
Example: Built-in functions like len() and print() are always accessible.
Example:
pythonCopy code
def my_function():
print("This is a built-in function.") # Using a built-in
function
L (Local): Python first looks for a variable in the local scope (inside the current
function).
G (Global): If still not found, it checks the global scope (outside the function
but in the current module).
B (Built-in): Finally, it checks the built-in scope for Python’s built-in functions
and constants.
Functions: 9
pythonCopy code
x = "global"
def outer_function():
x = "enclosing"
def inner_function():
x = "local"
print(x) # Output: local
inner_function()
print(x) # Output: enclosing
outer_function()
print(x) # Output: global
pythonCopy code
x = 5
def modify_global():
global x # Refers to the global variable
x = 10
modify_global()
print(x) # Output: 10
Functions: 10
Nonlocal Keyword Example:
pythonCopy code
def outer():
x = "outer"
def inner():
nonlocal x # Refers to the outer function's x
x = "inner"
print(x) # Output: inner
inner()
print(x) # Output: inner
outer()
1. Purpose
print() : Displays output to the console.
Example:
pythonCopy code
def greet_with_print():
print("Hello!") # Display output to the console
def greet_with_return():
return "Hello!" # Return value to the caller
Functions: 11
2. Location
print() : Can be used anywhere in the code.
return : Ca
Example:
def inside_function():
return "This is a return statement"
3. Effect on Execution
print() : Does not affect the execution flow.
Example:
pythonCopy code
def print_example():
print("First")
print("Second")
print("Third")
def return_example():
print("First")
return "Second"
print("Third") # This line will never execute
Functions: 12
print(return_example()) # Output: First, Second (Third is ne
ver printed)
4. Return Value
print() : Always returns None .
Example:
pythonCopy code
def print_none():
result = print("Displayed") # Output: Displayed
print(f"Return value from print: {result}")
def return_value():
return 42 # Returns an integer
5. Visibility
print() : Produces visible output on the console.
Example:
def visible_print():
print("Visible output")
Functions: 13
def invisible_return():
return "This is returned, not printed"
6. Multiple Values
print() : Can print multiple values in a single call.
Example:
def print_multiple():
print("Hello", "World", 123) # Output: Hello World 123
def return_multiple():
return "Hello", "World", 123 # Returns a tuple
Example:
Feature print() return
Functions: 14
Effect on Stops further execution of the
Does not affect flow
Execution function
# Function call
sum_result = add(3, 5)
print(sum_result) # Output: 8
Code:
Functions: 15
def classify_number(num):
if num > 0:
return "Positive"
elif num < 0:
return "Negative"
else:
return "Zero"
# Function calls
print(classify_number(10)) # Output: Positive
print(classify_number(-5)) # Output: Negative
print(classify_number(0)) # Output: Zero
pythonCopy code
def print_numbers():
for i in range(1, 11): # Loop from 1 to 10
if i % 2 == 0: # Skip even numbers
continue
if i > 7: # Stop the loop if i is greater than 7
break
print(i)
# Example usage
print_numbers()
Functions: 16
def calculate_grade(math_score, science_score, english_scor
e):
total_score = math_score + science_score + english_score
average_score = total_score / 3
# Example usage
math = 85
science = 75
english = 90
Functions: 17
Example 3: Nested Function Calls
This example illustrates how functions can call other functions and how execution
flows through multiple layers of function calls.
Code:
# Function call
result = sum_of_squares(3, 4)
print(result) # Output: 25
def check_numbers(numbers):
for num in numbers:
if num % 2 == 0:
print(f"{num} is even. (ID: {id(num)})")
else:
print(f"{num} is odd. (ID: {id(num)})")
Functions: 18
numbers = [1, 2, 3, 4, 5]
check_numbers(numbers)
pythonCopy code
def categorize_scores(scores):
def categorize(score):
if score >= 90:
return "Excellent"
elif score >= 75:
return "Good"
else:
return "Needs Improvement"
categories = {}
for name, score in scores.items():
category = categorize(score)
categories[name] = category
return categories
student_scores = {
"Alice": 95,
"Bob": 82,
"Charlie": 70,
"David": 60
}
result = categorize_scores(student_scores)
for student, category in result.items():
print(f"{student}: {category} (ID: {id(category)})")
Functions: 19
def factorial(num):
if num == 1:
return 1
else:
return num * factorial(num - 1)
def process_numbers(numbers):
for num in numbers:
fact = factorial(num)
if fact % 2 == 0:
print(f"Factorial of {num} is {fact}, and it's ev
en. (ID: {id(fact)})")
else:
print(f"Factorial of {num} is {fact}, and it's od
d. (ID: {id(fact)})")
numbers = [3, 4, 5]
process_numbers(numbers)
Nested Functions:
Functions: 20
Syntax
def outer_function(outer_args):
def inner_function(inner_args):
# Code for inner function: Perform a simple operation
using inner_args
result = outer_args + inner_args
return result
# Function call
result = outer_function(10)
print(result) # Output: 15
Features
1. Access to Outer Scope: Inner functions can access variables from their
enclosing scope (the outer function).
2. Encapsulation: The inner function is not accessible from outside the outer
function, which helps in keeping the inner function’s scope private.
3. Closure: Inner functions can form closures, meaning they remember the
environment in which they were created.
Examples
Functions: 21
return x * y
def square(x):
"""Squares a number using the multiply function."""
return multiply(x, x)
# Function call
result = sum_of_squares(3, 4)
print(result) # Output: 25
def print_nested_loops():
for i in range(1, 4): # Outer loop
for j in range(1, 4): # Middle loop
for k in range(1, 4): # Inner loop
print(f"i={i}, j={j}, k={k}")
print_nested_loops()
pythonCopy code
def outer_function(x):
def inner_function(y):
return y * y
return inner_function(x) + 10
Functions: 22
result = outer_function(5)
print(result) # Output: 35
1. Built-in Functions
Definition: Built-in functions are functions that are pre-defined in Python and are
available for use without the need for imports or additional definitions.
Key Points:
Examples:
pythonCopy code
# print() - prints objects to the console
print("Hello, World!") # Output: Hello, World!
What is an Iterable?
An Iterable is an object capable of returning its members one at a time, allowing
you to iterate (loop) over its elements. Examples of iterables include lists, tuples,
Functions: 23
dictionaries, strings, and sets. Any object with an __iter__() method is considered
an iterable.
Common Iterable Objects: Lists, tuples, strings, dictionaries, and sets are all
iterable because you can loop over them.
What is an Iterator?
An Iterator is an object that represents a stream of data. It returns data, one
element at a time, when you repeatedly call its __next__() method. Once all
elements have been returned, it raises a StopIteration exception to signal the end
of the iteration.
Iterators are "lazy": They only compute the next value when requested,
making them memory efficient for large datasets.
Iterator: An object that produces the next value when calling __next__() on it
and keeps track of its state.
Example:
Iterable: A list ( [1, 2, 3] ) is an iterable. You can loop through it using a for
loop.
Iterator: An iterator is created from the iterable, which gives you values one by
one when you call next() on it.
Example:
Functions: 24
pythonCopy code
# Iterable (a list)
my_list = [1, 2, 3, 4]
3. Lambda Functions
Definition: Lambda functions are small, anonymous functions defined using the
lambda keyword. They are used for short, throwaway functions.
Key Points:
Example:
Functions: 25
squared = list(map(lambda x: x**2, numbers))
print(squared) # Output: [1, 4, 9, 16]
1. Generators:
Generators are special functions in Python that allow you to yield a sequence of
values over time, instead of returning all values at once. They are memory-
efficient and allow lazy evaluation.
The generator keeps its state in memory and resumes where it left off when
you call next() on it.
pythonCopy code
def countdown(num):
while num > 0:
yield num
num -= 1
Explanation:
This generator function countdown() starts from the number you pass and
decrements it until it reaches 0, yielding each number one by one.
Functions: 26
This example shows how to iterate over a generator using a for loop.
pythonCopy code
def fibonacci(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
Explanation:
This demonstrates how you can use generators to handle sequences like
Fibonacci numbers lazily.
Higher-Order Functions
Definition: Higher-order functions take other functions as arguments or return
functions as results.
Key Points:
Example:
Functions: 27
pythonCopy code
def apply_function(func, x):
return func(x)
def square(n):
return n * n
result = apply_function(square, 4)
print(result) # Output: 16
Examples:
pythonCopy code
from functools import reduce
# map() function
numbers = [1, 2, 3, 4]
squared = list(map(lambda x: x**2, numbers))
print(squared) # Output: [1, 4, 9, 16]
# filter() function
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # Output: [2, 4]
Functions: 28
# reduce() function
sum_all = reduce(lambda x, y: x + y, numbers)
print(sum_all) # Output: 10
9. Decorator Functions
Definition: Decorators are functions that modify the behavior of other functions.
They are applied using the @ syntax.
Key Points:
Example:
def decorator_function(func):
def wrapper():
print("Something is happening before the function is
called.")
func()
print("Something is happening after the function is c
alled.")
return wrapper
@decorator_function
def say_hello():
print("Hello!")
say_hello()
pythonCopy code
import time
Functions: 29
def time_decorator(func):
def wrapper():
start_time = time.time() # Record start time
result = func() # Call the original function
end_time = time.time() # Record end time
print(f"Execution time: {end_time - start_time:.5f} s
econds")
return result # Return the result of the original fu
nction
return wrapper
@time_decorator
def example_function():
print("Executing the function...")
time.sleep(2) # Simulating a time-consuming task
pythonCopy code
def symbol_decorator(func):
def wrapper():
print("### Start of Output ###")
func() # Call the original function
print("### End of Output ###")
return wrapper
@symbol_decorator
def greet():
print("Hello, World!")
Functions: 30
# Using the decorated function
greet()
return Features
1. Terminates the Function: When return is called, the function's execution
ends, and a value is sent back to the caller.
pythonCopy code
def terminate_function(x):
return x * 2 # Function ends here and returns the result
result = terminate_function(5)
print(result) # Output: 10
1. Single Value Return: return typically returns a single value (or multiple values
packed as a tuple).
pythonCopy code
def single_return(x):
return x * 3 # Returns a single value
result = single_return(4)
print(result) # Output: 12
1. Normal Function: Functions that use return are standard functions and do not
retain their state between function calls.
pythonCopy code
def normal_function():
Functions: 31
x = 5
return x
1. Once Executed: After return is executed, the function is done, and the
function's state is not saved.
pythonCopy code
def once_executed(x):
return x * 2
result = once_executed(6)
# Trying to access state here is not possible as the function
has ended
yield Features
1. Pauses the Function: When yield is called, the function's state is saved, and
it pauses the execution, returning a value to the caller. The function can be
resumed from where it left off.
pythonCopy code
def pause_function():
yield 1 # Pauses and returns 1
yield 2 # Resumes and returns 2
yield 3 # Resumes and returns 3
gen = pause_function()
print(next(gen)) # Output: 1
Functions: 32
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3
1. Multiple Values Over Time: yield can produce multiple values over time in a
sequence, one at a time.
pythonCopy code
def multiple_values():
for i in range(4):
yield i # Yields values 0, 1, 2, 3 in sequence
gen = multiple_values()
for value in gen:
print(value) # Output: 0 1 2 3 (each on a new line)
1. Generator Function: Functions that use yield are called generators and can
be iterated over.
pythonCopy code
def generator_function():
yield 'a'
yield 'b'
yield 'c'
gen = generator_function()
for letter in gen:
print(letter) # Output: 'a' 'b' 'c' (each on a new line)
1. State Retention: Generators maintain their internal state and allow the function
to resume where it left off after yielding a value.
Functions: 33
pythonCopy code
def state_retention():
x = 0
while x < 3:
yield x
x += 1
gen = state_retention()
print(next(gen)) # Output: 0
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
# Function state is retained across yields
Return Type Returns a single value (or tuple) Returns a generator object
Used when you want to return a Used when you want to generate
Use Case
value and stop execution a sequence of values
Functions: 34
Functions: 35