Python Course
Functions in Python
In this lesson you will learn about Functions — one of the most important concepts in all of programming. Functions let you write a block of code once and use it as many times as you need. By the end of this lesson you will be writing clean, reusable, professional-quality code using functions.
1. What is a Function?
A function is a named block of code that performs a specific task. Instead of writing the same logic over and over in different places, you write it once inside a function and simply call the function by name whenever you need it.
Think of a function like a coffee machine. You press a button (call the function), the machine does its job, and you get coffee (the result). You do not need to understand every internal step — you just use it. And you can press the button as many times as you want.
Why do functions exist?
- Reusability — write once, use anywhere in your program
- Readability — code with functions is easier to read and understand
- Organisation — break a big program into small, manageable pieces
- Easy to fix — if there is a bug, you fix it in one place, not in 10 places
Where are functions used? Every real Python program uses functions. Web frameworks, data science scripts, automation tools, games — all of them are built from functions. From Lesson 16 onwards, every program you write will use functions.
2. Defining and Calling a Function
You define a function using the def keyword, followed by the function name, parentheses, and a colon. The code inside the function is indented. To run the function, you call it by writing its name followed by parentheses.
# DEFINE the function — this is the blueprint
def greet():
print("Hello! Welcome to Python.")
print("Functions make code reusable.")
# CALL the function — this runs the code inside it
greet()
# You can call the same function multiple times
greet()
greet()
Functions make code reusable.
Hello! Welcome to Python.
Functions make code reusable.
Hello! Welcome to Python.
Functions make code reusable.
What just happened?
- The
def greet():line defines the function — it tells Python "remember this block of code under the namegreet". - The function does not run when it is defined. It only runs when you call it with
greet(). - Calling it three times prints the output three times — the same two lines repeated. This is the core power of functions.
3. Functions with Parameters
A parameter is a variable you place inside the parentheses when defining a function. It lets you pass information into the function so it can work with different data each time it is called. The value you pass when calling the function is called an argument.
# "name" is the parameter — it receives the value when the function is called
def greet_user(name):
print(f"Hello, {name}! Good to see you.")
# "Priya", "Kiran", "Arjun" are the arguments — the actual values passed in
greet_user("Priya")
greet_user("Kiran")
greet_user("Arjun")
# Function with two parameters
def add_numbers(a, b):
print(f"{a} + {b} = {a + b}")
add_numbers(10, 5)
add_numbers(100, 250)
Hello, Kiran! Good to see you.
Hello, Arjun! Good to see you.
10 + 5 = 15
100 + 250 = 350
What just happened?
- Each time
greet_user()is called, the argument replaces the parameternameinside the function — so"Priya","Kiran", and"Arjun"each get their own personalised message. add_numbers(a, b)takes two parameters — both are used in the calculation. The order matters: the first argument goes toa, the second tob.- Parameter = the placeholder in the definition. Argument = the real value you pass when calling.
4. Returning Values from a Function
So far our functions only print results. But in real programs, you usually want a function to calculate something and give the result back so you can use it elsewhere. This is done with the return statement. Once Python hits return, it exits the function and sends the value back to wherever the function was called.
# This function RETURNS the result instead of printing it
def multiply(a, b):
result = a * b
return result # send the value back to the caller
# The returned value is stored in a variable
answer = multiply(6, 7)
print("6 x 7 =", answer)
# You can also use the returned value directly
print("3 x 9 =", multiply(3, 9))
# Practical example — calculate the final price after discount
def final_price(price, discount_percent):
discount = price * discount_percent / 100
return price - discount
cost = final_price(2000, 15) # 15% off ₹2000
print("Final price after 15% off:", cost)
3 x 9 = 27
Final price after 15% off: 1700.0
What just happened?
return resultsends the value42back to the lineanswer = multiply(6, 7)— the variableanswernow holds42.- You can also use a returned value directly inside
print()without storing it —print(multiply(3, 9))calls the function and prints what it returns. - The
final_pricefunction is a real-world example — it takes a price and discount, calculates, and returns the result. This kind of function is used in every shopping or billing application.
5. Default Parameter Values
You can give a parameter a default value so that the function still works even if the caller does not provide that argument. If an argument is passed, it overrides the default. If not, the default is used.
# "country" has a default value of "India"
def register_user(name, country="India"):
print(f"Name: {name} | Country: {country}")
# Called with both arguments — default is overridden
register_user("Priya", "USA")
# Called with only one argument — default is used for country
register_user("Kiran")
register_user("Arjun", "Canada")
Name: Kiran | Country: India
Name: Arjun | Country: Canada
What just happened?
- When
register_user("Kiran")is called with only one argument, Python uses"India"as the default value forcountry. - When two arguments are provided, the default is completely replaced by the actual argument.
- Default parameters must always come after non-default parameters in the function definition —
def f(a, b="x")is valid, butdef f(a="x", b)is not.
6. Keyword Arguments
Normally you pass arguments in the same order as the parameters. But with keyword arguments, you can pass them in any order by specifying the parameter name. This makes function calls much clearer, especially when a function has many parameters.
def create_profile(name, age, city):
print(f"Name: {name} | Age: {age} | City: {city}")
# Normal way — order must match exactly
create_profile("Sneha", 25, "Mumbai")
# Keyword arguments — order does not matter
create_profile(age=30, city="Delhi", name="Rahul")
# Mix: positional first, then keyword
create_profile("Meera", city="Pune", age=22)
Name: Rahul | Age: 30 | City: Delhi
Name: Meera | Age: 22 | City: Pune
What just happened?
- In the second call, the arguments are in a completely different order but Python matches them correctly because each one is labelled with the parameter name.
- In the third call,
"Meera"is positional (goes toname) and the remaining two use keyword style. Positional arguments must always come before keyword arguments. - Keyword arguments make code more readable — when you see
city="Pune"in a function call, it is instantly clear what that value is for.
7. *args — Accepting Any Number of Arguments
Sometimes you do not know in advance how many arguments will be passed to a function. Using *args lets a function accept any number of positional arguments. All the values are collected into a tuple inside the function.
# *args collects all extra arguments into a tuple
def add_all(*numbers):
total = 0
for n in numbers:
total += n
return total
# Call with any number of arguments
print(add_all(5, 10))
print(add_all(1, 2, 3, 4, 5))
print(add_all(100, 200, 300, 400))
# Another example — greet multiple people at once
def greet_all(*names):
for name in names:
print(f"Hello, {name}!")
greet_all("Priya", "Kiran", "Arjun")
15
1000
Hello, Priya!
Hello, Kiran!
Hello, Arjun!
What just happened?
*numberscollects all passed arguments into a tuple — soadd_all(1, 2, 3, 4, 5)givesnumbers = (1, 2, 3, 4, 5)inside the function.- The loop then adds them all up. This works whether you pass 2 arguments or 20.
- The name
argsis just a convention — you can write*valuesor*items, but*argsis the standard style everyone recognises.
8. **kwargs — Accepting Any Number of Keyword Arguments
**kwargs lets a function accept any number of keyword arguments. All the name-value pairs are collected into a dictionary inside the function. This is very useful when building flexible functions that handle optional or variable configuration data.
# **kwargs collects all keyword arguments into a dictionary
def show_details(**info):
for key, value in info.items():
print(f" {key}: {value}")
# Call with any keyword arguments you want
print("--- User 1 ---")
show_details(name="Priya", age=25, city="Mumbai")
print("--- User 2 ---")
show_details(name="Kiran", country="India", plan="Premium", active=True)
name: Priya
age: 25
city: Mumbai
--- User 2 ---
name: Kiran
country: India
plan: Premium
active: True
What just happened?
**infocollects every keyword argument into a dictionary — soname="Priya", age=25becomes{"name": "Priya", "age": 25}inside the function.- The two calls pass completely different keyword arguments — different keys, different number of keys. The function handles both perfectly.
**kwargsis used heavily in real frameworks like Django and Flask to handle flexible configuration and form data.
9. Returning Multiple Values
A Python function can return more than one value at the same time. The values are returned as a tuple and can be unpacked into separate variables on the same line. This is something many other programming languages cannot do as cleanly.
# Function that returns three values at once
def get_stats(numbers):
total = sum(numbers)
average = total / len(numbers)
highest = max(numbers)
return total, average, highest # returns a tuple of three values
marks = [72, 85, 90, 60, 88]
# Unpack all three returned values into separate variables
total, avg, top = get_stats(marks)
print("Total :", total)
print("Average :", avg)
print("Highest :", top)
Average : 79.0
Highest : 90
What just happened?
return total, average, highestpacks three values into a tuple and sends them all back at once.total, avg, top = get_stats(marks)unpacks that tuple into three separate variables in one line.- This is cleaner than writing three separate functions or using a dictionary — it is the standard Python pattern for functions that produce multiple related results.
10. Variable Scope — Local vs Global
Scope means where in your code a variable can be accessed. A variable created inside a function is called a local variable — it only exists while the function is running. A variable created outside all functions is a global variable — it can be accessed anywhere.
app_name = "DataPlexa" # global variable — lives outside any function
def show_info():
version = "2.0" # local variable — only exists inside this function
print("App :", app_name) # can access global variable ✓
print("Version:", version) # can access local variable ✓
show_info()
# Global variable is accessible here
print("App name outside function:", app_name)
# Local variable is NOT accessible outside the function
try:
print(version) # this will fail
except NameError as e:
print("Error:", e)
Version: 2.0
App name outside function: DataPlexa
Error: name 'version' is not defined
What just happened?
app_nameis global — it is visible both inside and outside the function.versionis local toshow_info()— once the function finishes,versionno longer exists. Trying to access it outside raises aNameError.- This is an important safety feature — local variables cannot accidentally interfere with the rest of your program. Always prefer local variables inside functions unless you specifically need a global one.
11. Documenting Functions with Docstrings
A docstring is a short description written right inside a function to explain what it does. It is placed as the very first line inside the function, using triple quotes. Docstrings are best practice in professional Python — they make your functions self-explanatory for other developers (and future you).
def calculate_tax(income, rate):
"""
Calculates the tax amount for a given income and tax rate.
income : the total income (float or int)
rate : the tax rate as a percentage (e.g. 20 for 20%)
Returns: the tax amount as a float
"""
return income * rate / 100
# You can read the docstring using help() or __doc__
print(calculate_tax.__doc__)
# Using the function
tax = calculate_tax(50000, 20)
print("Tax owed:", tax)
Calculates the tax amount for a given income and tax rate.
income : the total income (float or int)
rate : the tax rate as a percentage (e.g. 20 for 20%)
Returns: the tax amount as a float
Tax owed: 10000.0
What just happened?
- The triple-quoted string right after the
defline is the docstring — Python stores it as__doc__on the function. calculate_tax.__doc__prints the full docstring — this is how tools like VS Code, Jupyter Notebook, and Python'shelp()system display function documentation.- Always write a docstring for any function someone else might use — it takes 30 seconds and saves hours of confusion.
12. Real-World Example — Invoice Generator
This program uses multiple functions together to build a simple invoice calculator. Each function does one job — this is the correct way to structure real programs.
# --- Individual functions, each doing one job ---
def calculate_subtotal(price, quantity):
"""Returns the subtotal before tax."""
return price * quantity
def calculate_tax(subtotal, rate=18):
"""Returns the tax amount. Default rate is 18%."""
return subtotal * rate / 100
def calculate_total(subtotal, tax):
"""Returns the final total."""
return subtotal + tax
def print_invoice(item, price, quantity):
"""Prints a full invoice for an item."""
subtotal = calculate_subtotal(price, quantity)
tax = calculate_tax(subtotal)
total = calculate_total(subtotal, tax)
print(f" Item : {item}")
print(f" Price : {price}")
print(f" Quantity : {quantity}")
print(f" Subtotal : {subtotal}")
print(f" Tax (18%): {tax}")
print(f" Total : {total}")
# --- Call the main function ---
print("===== INVOICE =====")
print_invoice("Wireless Mouse", 799, 3)
print("===================")
Item : Wireless Mouse
Price : 799
Quantity : 3
Subtotal : 2397
Tax (18%): 431.46
Total : 2828.46
===================
What just happened?
- Each small function does exactly one calculation — this is called the single responsibility principle and it is the foundation of professional coding.
print_invoice()calls the three helper functions and combines their results — functions calling other functions is very normal and powerful.- If the tax rate ever changes, you only update it in
calculate_tax()— one place, not throughout the whole program. This is why functions save so much time in real projects.
13. Lesson Summary
| Concept | Syntax / Example | What It Does |
|---|---|---|
| Define a function | def greet(): | Creates a reusable block of code |
| Call a function | greet() | Runs the code inside the function |
| Parameters | def greet(name): | Accepts input values into the function |
| Return value | return result | Sends a value back to the caller |
| Default parameter | def f(x, y=10): | Used when argument is not provided |
| Keyword argument | f(y=5, x=2) | Pass arguments in any order by name |
| *args | def f(*args): | Accepts any number of positional args as a tuple |
| **kwargs | def f(**kwargs): | Accepts any number of keyword args as a dict |
| Multiple return | return a, b, c | Returns multiple values as a tuple |
| Local variable | x = 5 (inside function) | Only exists inside that function |
| Global variable | x = 5 (outside function) | Accessible everywhere in the file |
| Docstring | """description""" | Documents what the function does |
🧪 Practice Questions
Answer based on what you learned in this lesson.
1. What keyword is used to define a function in Python?
2. Which keyword sends a value back from a function to the caller?
3. When you use *args, all the extra positional arguments are collected into a __________.
4. What error is raised when you try to access a local variable outside its function?
5. When you use **kwargs, all the keyword arguments are collected into a __________.
🎯 Quiz — Test Your Understanding
Q1. When does the code inside a function actually run?
Q2. What happens when you call a function without providing a value for a default parameter?
Q3. How do you return two values a and b from a function?
Q4. What is a local variable?
Q5. Which syntax collects any number of keyword arguments into a dictionary?