2. Defining a Function
Functions are defined using the def keyword, followed by the function name, parentheses `()`, and a colon `:`. The code block forming the function's body must be indented.
def greet(): # No parameters
"""
This function simply prints a greeting message.
"""
print("Hello from UdaanPath!")
print("Welcome to Python programming.")
# An empty function (useful as a placeholder)
def coming_soon_feature():
pass # 'pass' is a placeholder that does nothing
Docstrings: Documenting Your Functions
Immediately after the `def` line, you can add a string literal (usually triple quotes `"""Docstring"""`) called a docstring. This describes what the function does, its parameters, and what it returns. Docstrings are crucial for making your code understandable and maintainable. You can access a function's docstring using `function_name.__doc__`.
def calculate_square(number):
"""
Calculates the square of a given number.
Args:
number (int or float): The number to be squared.
Returns:
int or float: The square of the number.
"""
return number * number
print(f"Docstring for calculate_square:\n{calculate_square.__doc__}")
Docstring for calculate_square:
Calculates the square of a given number.
Args:
number (int or float): The number to be squared.
Returns:
int or float: The square of the number.
3. Calling a Function
To execute the code inside a function, you simply "call" it by its name followed by parentheses.
# Call the greet function
greet() # No arguments needed
# Call the coming_soon_feature (it does nothing)
coming_soon_feature()
Hello from UdaanPath!
Welcome to Python programming.
4. Parameters and Arguments: Passing Information
Functions can accept input data, known as arguments, through parameters defined in their signature.
-
Parameters: Names listed in the function definition (e.g., `name`, `age` in `def introduce(name, age):`).
-
Arguments: The actual values passed to the function when it's called (e.g., `"Alice"`, `30` in `introduce("Alice", 30)`).
Positional Arguments:
Arguments are passed to parameters in the order they are defined.
def display_udaan_course(course_name, instructor):
print(f"Course: {course_name}")
print(f"Instructor: {instructor}")
display_udaan_course("Data Science Mastery", "Ms. Priya Singh")
display_udaan_course("Web Development Bootcamp", "Mr. Rahul Kumar")
Course: Data Science Mastery
Instructor: Ms. Priya Singh
Course: Web Development Bootcamp
Instructor: Mr. Rahul Kumar
Keyword Arguments:
You can specify arguments by their parameter names, allowing you to pass them in any order. This improves readability.
def create_profile(name, email, age):
print(f"Creating profile for: {name}")
print(f"Email: {email}, Age: {age}")
# Using keyword arguments
create_profile(email="john@example.com", name="John Doe", age=28)
Creating profile for: John Doe
Email: john@example.com, Age: 28
Default Parameters:
You can assign a default value to a parameter in the function definition. If an argument is not provided for that parameter, the default value is used.
def send_notification(message, recipient="Admin", priority="low"):
print(f"Sending '{message}' to {recipient} with {priority} priority.")
send_notification("System update complete.") # Uses default recipient and priority
send_notification("Urgent bug fix needed!", "Developer Team", "high") # Override defaults
send_notification(recipient="User Support", message="Query resolved.") # Mix positional and keyword
Sending 'System update complete.' to Admin with low priority.
Sending 'Urgent bug fix needed!' to Developer Team with high priority.
Sending 'Query resolved.' to User Support with low priority.
5. Return Values: Sending Results Back
Functions can send data back to the caller using the return statement.
-
A function can return any type of data (number, string, list, dictionary, etc.).
-
If a function doesn't have a `return` statement, it implicitly returns `None`.
-
You can return multiple values, which Python will pack into a tuple.
def add_numbers(a, b):
"""Adds two numbers and returns the sum."""
return a + b
def get_udaan_user_status(user_id):
"""
Simulates fetching user status for a given ID.
Returns name and status.
"""
if user_id == 101:
return "Prashant", "Active"
elif user_id == 102:
return "Divya", "Inactive"
else:
return "Unknown", "N/A"
result = add_numbers(15, 7)
print(f"Sum of 15 and 7: {result}")
user_name, user_status = get_udaan_user_status(101) # Unpacking multiple return values
print(f"User 101: Name - {user_name}, Status - {user_status}")
unknown_user_name, unknown_user_status = get_udaan_user_status(999)
print(f"User 999: Name - {unknown_user_name}, Status - {unknown_user_status}")
# What if a function has no explicit return?
def do_nothing_special():
print("Just printing.")
none_return = do_nothing_special()
print(f"Return value of do_nothing_special: {none_return}")
Sum of 15 and 7: 22
User 101: Name - Prashant, Status - Active
User 999: Name - Unknown, Status - N/A
Just printing.
Return value of do_nothing_special: None
6. Scope of Variables: Local vs. Global
Where a variable is defined determines its scope, which dictates where it can be accessed in your program.
-
Local Variables: Variables defined *inside* a function are local to that function. They only exist while the function is executing and cannot be accessed from outside the function.
-
Global Variables: Variables defined *outside* any function are global. They can be accessed from anywhere in the program, including inside functions.
global_message = "This is a global message from UdaanPath!"
def my_function():
local_variable = "I am a local variable."
print(f"Inside function: {local_variable}")
print(f"Inside function (accessing global): {global_message}")
def modify_global_variable():
# Attempting to reassign a global variable without 'global' keyword
# will create a NEW local variable with the same name.
# To actually modify the global variable, you need 'global global_message'
# For now, let's just observe.
global_message = "This is a NEW local message in modify_global_variable"
print(f"Inside modify_global_variable: {global_message}")
print(f"Outside function (initial global): {global_message}")
my_function()
# print(local_variable) # This would cause a NameError!
modify_global_variable()
print(f"Outside function (after modify_global_variable call): {global_message}") # Global is unchanged!
# Correct way to modify a global variable (use with caution!)
def truly_modify_global():
global global_message
global_message = "Global message has been truly modified!"
print(f"Inside truly_modify_global: {global_message}")
truly_modify_global()
print(f"Outside function (after truly_modify_global call): {global_message}")
Outside function (initial global): This is a global message from UdaanPath!
Inside function: I am a local variable.
Inside function (accessing global): This is a global message from UdaanPath!
Inside modify_global_variable: This is a NEW local message in modify_global_variable
Outside function (after modify_global_variable call): This is a global message from UdaanPath!
Inside truly_modify_global: Global message has been truly modified!
Outside function (after truly_modify_global call): Global message has been truly modified!
Best Practice: While `global` exists, it's generally best to avoid modifying global variables directly inside functions. Instead, pass global data as arguments and return modified data. This makes functions more independent and easier to debug.