Quick Answer

A function is a reusable block of code you define once with the def keyword and call as many times as you need. You pass in data through parameters, do the work inside, and usually send a result back with return. Functions keep your code DRY (Don't Repeat Yourself), easier to read, and simpler to fix.

What are Python functions?

A function is a named block of code that does one job. You write it once, give it a name, and then call it whenever you need that job done. That is the whole idea behind Python functions: write logic in one place, reuse it everywhere.

You already use functions without thinking about it. When you write print("Hello") or len("Priodemy"), you are calling built-in functions that Python ships with. In this tutorial you will learn to build your own with the def keyword, pass data into them, and get results back.

Here is the smallest useful example:

def greet():
    print("Hello, welcome to Priodemy!")

greet()
greet()

The def line defines the function. The indented line below is its body — the code that runs. Nothing happens until you call it by writing its name followed by parentheses: greet(). Here we call it twice, so the message prints twice.

Why Python functions matter: a before-and-after

The best way to feel the value of functions is to see code without them. Imagine calculating a final price with 18% GST for three items:

# Before: the same formula copied three times
price1 = 500
total1 = price1 + (price1 * 18 / 100)
print("Item 1 total:", total1)

price2 = 1200
total2 = price2 + (price2 * 18 / 100)
print("Item 2 total:", total2)

price3 = 750
total3 = price3 + (price3 * 18 / 100)
print("Item 3 total:", total3)

The GST formula is repeated three times. If the rate changes to 12%, you must edit it in three places — and it is easy to miss one. Now the same thing with a function:

# After: one formula, reused
def price_with_gst(price, rate=18):
    return price + (price * rate / 100)

print("Item 1 total:", price_with_gst(500))
print("Item 2 total:", price_with_gst(1200))
print("Item 3 total:", price_with_gst(750))

The formula lives in exactly one spot. Change it once and every call updates. This principle has a name: DRY — Don't Repeat Yourself. Functions make your code shorter, easier to read, and far safer to change. That is the real reason they matter.

Defining a function with def

Every Python function follows the same shape:

def function_name(parameters):
    # body: the code that runs
    return value   # optional

Breaking it down:

  • def — the keyword that starts a function definition.
  • function_name — a clear, lowercase name, usually with underscores (like price_with_gst). Pick names that say what the function does.
  • parameters — the input slots, inside the parentheses. A function can have zero, one, or many.
  • colon and indentation — the body must be indented (4 spaces is standard). Indentation is how Python knows which lines belong to the function.

A quick gotcha: writing greet without parentheses does not run the function — it just refers to it. You must write greet() to actually call it.

Parameters vs arguments

Beginners mix up these two words all the time, so let's make it simple. A parameter is the name you write in the definition. An argument is the real value you pass in when you call the function.

def greet(name):        # 'name' is a parameter
    print("Hello,", name)

greet("Aarav")          # "Aarav" is an argument
greet("Priya")          # "Priya" is an argument

Think of the parameter as an empty box labelled name, and the argument as whatever you drop into that box for a particular call. The same function works for any name you give it.

You can have several parameters. When you call the function, the arguments line up with the parameters by position, left to right:

def full_name(first, last):
    return first + " " + last

print(full_name("Aarav", "Sharma"))   # Aarav Sharma

Here "Aarav" goes into first and "Sharma" goes into last because that is the order you passed them. These are called positional arguments.

Returning values with return

So far some functions print and some return. The difference is important. print() just shows text on screen. return hands a value back to your program so you can store it, do maths with it, or pass it on.

def square(n):
    return n * n

result = square(5)
print(result)          # 25
print(square(3) + square(4))   # 9 + 16 = 25

Because square returns a value, you can use its result in bigger expressions. A function that only prints cannot do that.

A common surprise: if a function has no return, Python automatically returns the special value None.

def greet(name):
    print("Hi", name)

x = greet("Meera")
print(x)      # None

Also remember that return ends the function immediately — any code written after a return that runs will not execute. And yes, a function can return more than one value at once; Python bundles them into a tuple:

def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 9, 1, 7])
print(low, high)     # 1 9

Default and keyword arguments

Sometimes you want a parameter to have a sensible fallback so callers can skip it. That is a default argument — you assign a value right in the definition:

def make_tea(sugar=1, milk=True):
    print("Sugar spoons:", sugar, "| Milk:", milk)

make_tea()          # Sugar spoons: 1 | Milk: True
make_tea(2)         # Sugar spoons: 2 | Milk: True

If a caller passes nothing, the defaults kick in. This keeps common calls short while still allowing customisation.

You can also pass arguments by name instead of by position. These are keyword arguments, and they make calls much clearer:

make_tea(sugar=0, milk=False)
make_tea(milk=False, sugar=3)   # order does not matter

With keyword arguments the order no longer matters, because you are labelling each value. One rule to remember: in a call, positional arguments must come before keyword arguments. Writing make_tea(sugar=2, True) is an error; write make_tea(2, milk=True) instead.

A gentle intro to *args and **kwargs

What if you don't know how many arguments will come in? Python has two tools for that. Don't let the symbols scare you — the important part is the * and **; the names args and kwargs are just convention.

*args collects any extra positional arguments into a tuple:

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

print(total(10, 20))          # 30
print(total(1, 2, 3, 4, 5))   # 15

**kwargs collects any extra keyword arguments into a dictionary:

def show_profile(**details):
    for key, value in details.items():
        print(key, ":", value)

show_profile(name="Priya", city="Pune", course="Python")

Here is a quick side-by-side so the two stay clear in your head:

Feature*args**kwargs
CollectsExtra positional argumentsExtra keyword arguments
Stored asA tupleA dictionary
Called liketotal(1, 2, 3)show_profile(a=1, b=2)

You will not need these every day as a beginner, but you will see them in real libraries, so it helps to recognise them.

Common mistakes and gotchas

A few traps catch almost every beginner. Knowing them early saves hours of confusion.

Forgetting to return

If your function prints instead of returns, you cannot reuse its result. Ask yourself: do I need this value later? If yes, use return.

Calling without parentheses

Writing square refers to the function object; square(5) actually runs it. Missing parentheses is a silent, confusing bug.

Mutable default arguments

This one surprises even experienced coders. Never use a list or dictionary as a default value:

# Risky: the list is shared across calls
def add_item(item, cart=[]):
    cart.append(item)
    return cart

print(add_item("pen"))     # ['pen']
print(add_item("book"))    # ['pen', 'book']  <- unexpected!

The default list is created once and reused, so it keeps growing. The safe pattern uses None:

def add_item(item, cart=None):
    if cart is None:
        cart = []
    cart.append(item)
    return cart

Now each call that doesn't pass a cart gets a fresh empty list.

Practice and next steps

You now know the core of Python functions: define with def, pass data through parameters, get results with return, and use defaults, keyword arguments, and *args/**kwargs when you need flexibility.

Our clear recommendation for beginners: keep functions small and give each one a single job. If a function is doing three things, split it into three functions. Short, well-named functions are easier to read, test, and fix — that habit matters more than any fancy feature.

The fastest way to make this stick is to write your own. Try these small exercises:

  • A function is_even(n) that returns True or False.
  • A function average(*numbers) that returns the mean of any count of numbers.
  • Rewrite some copy-pasted code from an earlier program into one reusable function.

When you are ready to go deeper — loops, lists, and building real projects with functions — work through our free, structured Python course. It takes you step by step from the basics to writing programs you can be proud of.

Frequently Asked Questions

What is the difference between a parameter and an argument in Python?

A parameter is the name you write inside the parentheses when you define a function, like name in def greet(name):. An argument is the actual value you pass in when you call it, like "Aarav" in greet("Aarav"). In short: parameters are the empty slots, arguments are what you put into them.

What does a Python function return if there is no return statement?

It returns the special value None. Python adds this automatically when a function ends without an explicit return. So a function that only calls print() will show text on screen but hand back None if you try to store its result.

Can a Python function return more than one value?

Yes. Write the values separated by commas, like return low, high, and Python bundles them into a tuple. You can then unpack them into separate variables on the calling side: a, b = min_max(numbers). This is a clean, common Python pattern.

When should I use *args and **kwargs?

Use *args when you want a function to accept any number of positional arguments (they arrive as a tuple), and **kwargs when you want any number of named arguments (they arrive as a dictionary). As a beginner you will not need them often, but they are useful for flexible functions and you will spot them in many Python libraries.

Why should I avoid using a list as a default argument?

Because the default is created once and shared across every call, so a mutable default like cart=[] keeps its changes between calls and causes surprising bugs. The safe fix is to use None as the default and create a fresh list inside the function: if cart is None: cart = [].

What is the difference between print and return in a function?

print() only displays text in the terminal for a human to read; it does not give the value back to your program. return hands the result back so you can store it in a variable, use it in calculations, or pass it to another function. If you need to reuse a function's output, use return.