Functions in Python- Definition

Functions in Python are blocks of code that perform a specific task, and they can be defined using the def keyword.

Function template

def function_name(input_varibales, ...):
    processing
    return output_value_or_exppression

output_variable = function_name(output_values, ...)
print(output_variable)


Definition
:

  • A function in Python is a block of reusable code that performs a specific task.
  • It allows you to break down your program into smaller, more manageable pieces, making your code modular and easier to understand.

Function Call:

  • To use a function, you call it by its name followed by parentheses ().

Function Name:

  • Can contain letters (a-z, A-Z), digits (0-9), and underscores (_)
  • Must start with a letter or underscore
  • Case-sensitive

Parameters

  • Can be positional or keyword-based
  • Can have default values
  • Can be variable-length (using *args or **kwargs)

Function Body

  • Indented block of code
  • Can contain statements, expressions, and other functions
  • Can include a return statement to output values
  • Can include a pass statement as a placeholder when no action is needed

Docstring

  • Optional string literal that occurs as the first statement in a function
  • Used to document the function’s purpose, parameters, and return values
  • Triple quotes (""") are commonly used to delimit docstrings

Return Statement

  • Used to output values from a function
  • Can return multiple values using tuples or lists
  • If no return statement is present, the function returns None by default

Pass Statement

  • Used as a placeholder when no action is needed
  • Can be used to define a function with no body

Lambda Functions

  • Small, anonymous functions defined with the lambda keyword
  • Can take any number of arguments, but can only have one expression

Default Argument Values

  • Can be specified using the = operator
  • Must be specified after non-default arguments

Variable-Length Arguments

  • Can be specified using *args or **kwargs
  • *args collects positional arguments into a tuple
  • **kwargs collects keyword arguments into a dictionary
def function_name(*args):
    # args is a tuple of non-keyword arguments
    pass
def greet(*names):
    for name in names:
        print(f"Hello, {name}!")

greet("John", "Alice", "Bob")
def function_name(**kwargs):
    # kwargs is a dictionary of keyword arguments
    pass
def greet(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

greet(name="John", age=30, city="New York")

Keyword-Only Arguments

  • Can be specified using the * operator
  • Must be specified after non-keyword-only arguments

Python 3.x

def function_name(*, arg1, arg2, ...):
    # arg1, arg2, ... are keyword-only arguments
    pass

Example:

def greet(*, name, age):
    print(f"Hello, {name}! You are {age} years old.")

greet(name="John", age=30)

Combination of *args, **kwargs, and Keyword-Only Arguments

def function_name(arg1, arg2, *args, kwarg1, kwarg2, **kwargs):
    pass

Example:

def greet(name, age, *hobbies, city, country, **kwargs):
    print(f"Hello, {name}! You are {age} years old.")
    print(f"Hobbies: {hobbies}")
    print(f"City: {city}, Country: {country}")
    print(f"Additional info: {kwargs}")

greet("John", 30, "reading", "hiking", city="New York", country="USA", occupation="Developer")

Type Hints

  • Can be used to specify the expected types of arguments and return values
  • Do not affect runtime behavior, but can be used by IDEs and static type checkers

Example

def greet(name: str, age: int = 30) -> str:
    """
    Returns a personalized greeting message.

    Args:
        name (str): The person's name.
        age (int, optional): The person's age. Defaults to 30.

    Returns:
        str: The greeting message.
    """
    return f"Hello, {name}! You are {age} years old."


# Test the function
print(greet("John"))  # Output: Hello, John! You are 30 years old.
print(greet("Jane", 25))  # Output: Hello, Jane! You are 25 years old.

In simple words-

  • def : It is a keyword to define a function.
  • Function name should preferably be in snake_case.
  • Function defintion can consist of input parameters within ().
  • Function definition concludes with : and the body of function continues with indent, typically a tab space.
  • Function Call: When the function is called, the flow of control jumps to the function definition.
  • Execute Function: Perform the tasks defined inside the function.
  • If there’s a return statement, the function returns a value to the caller. return keyword returns the computed value in memory which can be accessed via the calling/output variable.
  • It the return statement is not present or not executed the function then returns a None value.
  • End: End of the function execution, control returns to the caller.

Snake case, also known as underscore_case, is a naming convention where each word in a compound name is separated by an underscore (_). All letters are lowercase. Here are some examples:

  • my_function_name
  • total_sales_amount
  • is_user_authenticated

Benefits of Snake Case:

  • Readability: Snake case improves code readability by clearly separating words, especially for longer names.
  • Consistency: Following a consistent naming convention makes code easier to understand and maintain for both you and others who collaborate on the project.
  • Python Convention: Snake case is the widely accepted convention for variable and function names in Python. Using it aligns your code with established practices in the Python community.

Examples of Naming with Snake Case:

Here’s a table illustrating how you can convert function names from other conventions to snake_case:

Original NameSnake Case Name
calculateTotalSalescalculate_total_sales
isUserLoggedInis_user_logged_in
checkIfStringIsEmptycheck_if_string_is_empty

Example Imagine a Function as a MonsterMachine

Think of a function as a special machine in your Python code. You give it certain inputs (like ingredients for a recipe), it performs a specific task (like cooking the ingredients), and then it can optionally provide an output (like the delicious meal!).

Steps to Build Your Function MonsterMachine:

  1. Name Your MonsterMachine: Choose a descriptive name for your function that reflects what it does. Let’s call our function greet.
  2. Define the Inputs (if any): These are like the ingredients you feed into your machine. If your function needs information to complete its task, specify variables within parentheses after the function name. For example, sayhello(name). Here, name is the input variable. These are Function Parameters:- Functions can take zero or more parameters.You can have default values for parameters as well.
  3. Tell Your MonsterMachine What to Do: Use Python code blocks to instruct your function what to accomplish with the inputs (or without them if there are none). Indentation is crucial here!
  4. Optional Output: If your function needs to return a value, use the return statement. This is like the cooked meal your machine produces.

Let’s Code a Greeter Machine!

Here’s how we can create a function called greet that takes a name as input and prints a greeting:

Python

def sayhello(name):
  """Prints a greeting message to the user."""
  print("Hello,", name + "!")

# Now let's use our greeter machine!
sayhello("Alice")  # Output: Hello, Alice!

Experimenting with Your Machine

We can call the greet function multiple times with different names to see it work its magic:

Python

sayhello("Bob")  # Output: Hello, Bob!
sayhello("Charlie")  # Output: Hello, Charlie!

Challenge: Build a Pizza Order Machine!

Can you create a function called order_pizza that takes the size (small, medium, large) and the number of toppings (as an integer) as inputs, and then prints the pizza order details?

Here’s a hint:

def order_pizza(size, num_toppings):
  # ... your code here ...

# Test your order_pizza function!
order_pizza("medium", 2)  # Output: You ordered a medium pizza with 2 toppings.

Parameters & Return Statement

Great! Let’s break down Parameters and Return Statements in Python — both are essential for writing clean, reusable, and modular code.


🧩 1. Function Parameters in Python

✅ What Are Parameters?

Parameters are placeholders used in a function definition.
When calling the function, you provide arguments (real values) to those parameters.

def greet(name):  # ← 'name' is a parameter
    print(f"Hello, {name}")

greet("Alice")    # ← "Alice" is an argument

✅ Types of Parameters in Python

TypeSyntax ExampleNotes
Positionaldef add(a, b)Order matters when calling
Keywordadd(a=1, b=2)Order doesn’t matter
Defaultdef greet(name="User")Uses default if not provided
Variable Positionaldef fun(*args)Packs extra positional args into a tuple
Variable Keyworddef fun(**kwargs)Packs extra keyword args into a dictionary
Keyword-onlydef fun(*, x, y)Must be passed as named parameters

✅ Examples:

1. Positional and Keyword

def add(a, b):
    return a + b

add(2, 3)          # 5
add(a=2, b=3)      # 5
add(b=3, a=2)      # 5

2. Default Parameters

def greet(name="Guest"):
    print("Hello", name)

greet()            # Hello Guest
greet("Alice")     # Hello Alice

3. *args (Variable Positional Arguments)

def total(*nums):
    return sum(nums)

total(1, 2, 3, 4)  # 10

4. **kwargs (Variable Keyword Arguments)

def print_info(**data):
    for key, value in data.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=30)

5. Keyword-only Parameters

def connect(*, host, port):
    print(f"Connecting to {host}:{port}")

connect(host="localhost", port=3306)  # ✅

🧩 2. Return Statement in Python

✅ What is return?

  • Used to send data back to the caller
  • Ends the function execution
  • You can return any Python object (int, str, list, tuple, dict, function, even another function)

✅ Basic Return Example:

def square(x):
    return x * x

result = square(4)
print(result)  # 16

✅ Returning Multiple Values (Tuple)

def stats(x, y):
    return x + y, x * y

s, p = stats(3, 4)  # s = 7, p = 12

✅ Return None by Default

def say_hello():
    print("Hello")

result = say_hello()  # prints "Hello"
print(result)         # None

🧠 BONUS: Return vs Print

returnprint()
Sends value back to callerJust displays text on screen
Useful in computationFor user interaction/logging
Can be captured/storedCannot be used in logic flow

✅ Summary: Parameters & Return
  • Parameters define what a function needs to run.
  • Arguments are what you pass when calling the function.
  • Return sends data back and ends the function.

Returning Values with Conditions:-

Magic8Ball Problem in Python

import random

def magic_8_ball_response(number):
    if number == 0:
        return "It is certain."
    elif number == 1:
        return "It is decidedly so."
    elif number == 2:
        return "Without a doubt."
    elif number == 3:
        return "Yes – definitely."
    elif number == 4:
        return "You may rely on it."
    elif number == 5:
        return "As I see it, yes."
    elif number == 6:
        return "Most likely."
    elif number == 7:
        return "Outlook good."
    elif number == 8:
        return "Yes."
    elif number == 9:
        return "Signs point to yes."
    elif number == 10:
        return "Reply hazy, try again."
    elif number == 11:
        return "Ask again later."
    elif number == 12:
        return "Better not tell you now."
    elif number == 13:
        return "Cannot predict now."
    elif number == 14:
        return "Concentrate and ask again."
    elif number == 15:
        return "Don't count on it."
    elif number == 16:
        return "My reply is no."
    elif number == 17:
        return "My sources say no."
    elif number == 18:
        return "Outlook not so good."
    elif number == 19:
        return "Very doubtful."
    else:
        return "Error: Invalid number."

def magic_8_ball():
    print("Welcome to the Magic 8 Ball!")
    question = input("Ask a yes or no question (or type 'quit' to exit): ")

    if question.lower() == 'quit':
        print("Goodbye!")
    elif question.strip() == "":
        print("You didn't ask a question!")
    else:
        number = random.randint(0, 19)
        response = magic_8_ball_response(number)
        print("Magic 8 Ball says: " + response)

if __name__ == "__main__":
    magic_8_ball()
import random

def magic_8_ball():
    answers = [
        "It is certain.",
        "It is decidedly so.",
        "Without a doubt.",
        "Yes – definitely.",
        "You may rely on it.",
        "As I see it, yes.",
        "Most likely.",
        "Outlook good.",
        "Yes.",
        "Signs point to yes.",
        "Reply hazy, try again.",
        "Ask again later.",
        "Better not tell you now.",
        "Cannot predict now.",
        "Concentrate and ask again.",
        "Don't count on it.",
        "My reply is no.",
        "My sources say no.",
        "Outlook not so good.",
        "Very doubtful."
    ]

    print("Welcome to the Magic 8 Ball!")
    question = input("Ask a yes or no question (or type 'quit' to exit): ")

    if question.lower() == 'quit':
        print("Goodbye!")
    elif question.strip() == "":
        print("You didn't ask a question!")
    else:
        response = random.choice(answers)
        print("Magic 8 Ball says: " + response)

if __name__ == "__main__":
    magic_8_ball()
import random

def magic_8_ball():
    answers = [
        "It is certain.",
        "It is decidedly so.",
        "Without a doubt.",
        "Yes – definitely.",
        "You may rely on it.",
        "As I see it, yes.",
        "Most likely.",
        "Outlook good.",
        "Yes.",
        "Signs point to yes.",
        "Reply hazy, try again.",
        "Ask again later.",
        "Better not tell you now.",
        "Cannot predict now.",
        "Concentrate and ask again.",
        "Don't count on it.",
        "My reply is no.",
        "My sources say no.",
        "Outlook not so good.",
        "Very doubtful."
    ]

    print("Welcome to the Magic 8 Ball!")
    while True:
        question = input("Ask a yes or no question (or type 'quit' to exit): ")
        if question.lower() == 'quit':
            print("Goodbye!")
            break
        response = random.choice(answers)
        print("Magic 8 Ball says: " + response)

if __name__ == "__main__":
    magic_8_ball()

Introduction to Logic with Python Functions

In this lecture, we explore how to combine logic statements in Python with functions, focusing on checking for even numbers using the modulo operator and implementing this logic in functions.

Understanding the Modulo Operator

The modulo operator returns the remainder after a division. If the result of a number modulo another is zero, then the number is evenly divisible by that value. For example, 2mod  2=02mod2=0 because two divided by two is one with a remainder of zero. Similarly, 3mod  2=13mod2=1 because two goes once into three with a remainder of one. The modulo operator simply returns the remainder after division.

Checking If a Number Is Even

If a number is even, such as 20, then 20mod  2=020mod2=0. Any number modulo two that equals zero is even. If not, then it is not even. For example, 20mod  2==020mod2==0 returns true, while 21mod  2==021mod2==0 returns false.

def even_check(number):
    result = (number % 2 == 0)
    return result

Simplifying the Function

For beginners, it is common to separate logic into multiple lines, but you can directly return the Boolean check. The following function achieves the same result in a more concise way.

def even_check(number):
    return number % 2 == 0

Checking for Even Numbers in a List

Next, we create a function that returns true if any number in a list is even. The function loops through each number in the list and returns true as soon as it finds an even number. If no even number is found, it returns nothing.

def check_even_list(num_list):
    for number in num_list:
        if number % 2 == 0:
            return True
        else:
            pass

Improving the Function to Return False When No Even Number Exists

Currently, the function does not return anything if there is no even number in the list. To fix this, we move the return False statement outside the for loop so that it only returns false after checking all numbers.

def check_even_list(num_list):
    for number in num_list:
        if number % 2 == 0:
            return True
    return False

Returning All Even Numbers in a List

To further expand the function, we can return a list of all even numbers found in the input list. If there are no even numbers, the function returns an empty list. We use a placeholder list at the top of the function to collect even numbers.

def check_even_list(num_list):
    even_numbers = []
    for number in num_list:
        if number % 2 == 0:
            even_numbers.append(number)
    return even_numbers

Conclusion

In this lecture, we learned how to use the modulo operator to check for even numbers, how to encapsulate this logic in functions, and how to handle lists to check for or collect even numbers. We also discussed the importance of correct return statement placement and the use of placeholder variables.

Key Takeaways

  • The modulo operator returns the remainder after division and is useful for checking if a number is even.
  • Functions can be used to encapsulate logic for checking even numbers, both for single values and lists.
  • Proper placement of return statements is crucial for correct function logic, especially when looping through lists.
  • Placeholder variables and lists are commonly used at the start of functions to collect results for later return.

Scope in Function @python

In Python, the scope of a variable refers to the region of the program where that variable is recognized. Variables can be defined in different parts of a program, and their scope determines where they can be accessed. There are four types of variable scopes in Python:

  1. Local Scope
  2. Enclosing (or nonlocal) Scope
  3. Global Scope
  4. Built-in Scope

1. Local Scope

Variables defined within a function have a local scope and are only accessible within that function.

def my_function():
    local_var = 10  # Local variable
    print(local_var)

my_function()  # Output: 10
print(local_var)  # NameError: name 'local_var' is not defined

2. Enclosing (or nonlocal) Scope

This scope is relevant for nested functions. The enclosing scope refers to the scope of the outer function in which a nested function is defined.

def outer_function():
    enclosing_var = 20

    def inner_function():
        print(enclosing_var)  # Accesses enclosing variable

    inner_function()

outer_function()  # Output: 20

To modify an enclosing variable from within a nested function, you can use the nonlocal keyword.

def outer_function():
    enclosing_var = 20

    def inner_function():
        nonlocal enclosing_var
        enclosing_var = 30
        print(enclosing_var)

    inner_function()  # Output: 30
    print(enclosing_var)  # Output: 30

outer_function()

3. Global Scope

Variables defined at the top level of a script or module are in the global scope. They are accessible from any part of the code, including within functions (unless shadowed by a local variable).

global_var = 40  # Global variable

def my_function():
print(global_var) # Accesses global variable

my_function() # Output: 40
print(global_var) # Output: 40

To modify a global variable within a function, you can use the global keyword.

global_var = 50

def my_function():
global global_var
global_var = 60
print(global_var)

my_function() # Output: 60
print(global_var) # Output: 60

4. Built-in Scope

This is the scope for built-in names like lenprint, etc. These are always available in any part of the code.

print(len([1, 2, 3]))  # len is a built-in function

Scope Resolution (LEGB Rule)

Python resolves variable names using the LEGB rule, which stands for Local, Enclosing, Global, Built-in.

  1. Local: Names defined within a function.
  2. Enclosing: Names defined in the enclosing function(s) for nested functions.
  3. Global: Names defined at the top level of a script or module.
  4. Built-in: Names preassigned in the built-in names module.
Example of LEGB Rule
# Built-in scope
def min():
return "This is the built-in min function."

def outer_function():
# Global scope
global_var = "I am in the global scope."

# Enclosing scope
enclosing_var = "I am in the enclosing scope."

def inner_function():
# Local scope
local_var = "I am in the local scope."

print(local_var) # Accessing local variable
print(enclosing_var) # Accessing enclosing variable
print(global_var) # Accessing global variable
print(min()) # Accessing built-in function

inner_function()

outer_function()

Key Points to Remember

  • Local variables are only accessible within the function they are defined in.
  • Enclosing variables are accessible within nested functions and can be modified using the nonlocal keyword.
  • Global variables are accessible throughout the module and can be modified using the global keyword.
  • Built-in names are always available and can be overridden (though not recommended).

What happen behind the scene in Python when a function gets called?

When a function gets called in Python, a series of steps occur behind the scenes. These steps manage the execution of the function, handle its local environment, and ensure the proper flow of control. Here’s a detailed breakdown of what happens:

1. Function Call

When a function is called, Python interprets the call and prepares to execute the function’s code.

def my_function():
print("Hello, world!")

my_function() # Function call

2. Stack Frame Creation

A new stack frame (also known as an activation record) is created for the function call. This stack frame contains:

  • Local variables and arguments: Storage for the function’s local variables and parameters.
  • Return address: Information on where to return after the function execution completes.
  • Instruction pointer: Keeps track of the current position in the function’s code.

3. Argument Passing

The arguments provided to the function call are evaluated and passed to the function. These arguments are then stored in the new stack frame.

def add(a, b):
return a + b

result = add(2, 3) # Arguments 2 and 3 are evaluated and passed to `a` and `b`

4. Local Scope and Environment Setup

The function’s local scope and environment are set up. This includes:

  • Initializing local variables: Variables declared inside the function.
  • Binding arguments to parameters: The passed arguments are bound to the function’s parameters.
  • Setting up the local namespace: A dictionary that holds the function’s local variables.

5. Code Execution

The function’s code is executed line by line. The instruction pointer within the stack frame keeps track of the current line being executed.

def my_function():
x = 10 # Local variable initialization
y = 20 # Local variable initialization
return x + y # Code execution

result = my_function() # Function execution

6. Function Return

When the function execution completes, it returns a value (if any). The return value is passed back to the calling location.

def add(a, b):
return a + b

result = add(2, 3) # `result` receives the value 5

7. Stack Frame Cleanup

After the function returns, its stack frame is destroyed, and the local variables and parameters go out of scope. The return address in the calling function is used to continue execution from where the function was called.

8. Back to Caller

Control returns to the point in the code where the function was called. The function’s return value can be used in subsequent operations.

def multiply(a, b):
return a * b

result = multiply(4, 5) # Control returns here with the result 20
print(result) # Output: 20

Example Walkthrough

Let’s go through a more detailed example:

def greet(name):
message = f"Hello, {name}!"
return message

print(greet("Alice"))
  1. Function Callgreet("Alice") is called.
  2. Stack Frame Creation: A new stack frame is created for greet.
  3. Argument Passing: The argument "Alice" is passed and bound to the parameter name.
  4. Local Scope and Environment Setup: The local variable message is initialized.
  5. Code Execution:
    • message = f"Hello, {name}!" is executed, resulting in message being "Hello, Alice!".
    • return message is executed, returning "Hello, Alice!".
  6. Function Return: The function returns the string "Hello, Alice!".
  7. Stack Frame Cleanup: The stack frame for greet is destroyed.
  8. Back to Caller: Control returns to the print statement, which outputs "Hello, Alice!".

Behind the Scenes

  • Namespace Management: Each function call has its own local namespace, separate from the global namespace.
  • Garbage Collection: Local variables are cleaned up once they go out of scope, freeing memory.
  • Call Stack: The call stack manages function calls, with each call creating a new stack frame.

Pages: 1 2 3 4


Discover more from HintsToday

Subscribe to get the latest posts sent to your email.

Posted in

Leave a Reply

Discover more from HintsToday

Subscribe now to keep reading and get access to the full archive.

Continue reading