Functions in Python: writing organised, reusable code
Defining and calling functions, parameters, defaults and return values, variable scope, and splitting a big problem into small clear functions.
- 9 min read
Imagine you have written a program that calculates a student’s average mark, and then you need the same calculation for twenty students in different parts of the program. Will you copy the same lines twenty times? And if you discover a small mistake in the calculation, will you fix it in twenty places? This is where functions come in: a named block of code that you write once and call whenever you need it. Functions are among the most important ideas in all of programming, because they turn code from a pile of lines into organised, clear parts that can be understood, tested and reused. In this article we explain functions in Python from the beginning, with examples that build from simple to practical.
What you will learn
- Why we need functions, and how to define and call them.
- Parameters, default values and keyword arguments.
- The difference between printing and returning a value, and why it matters.
- Variable scope, and how to split a big problem into small functions.
Why do we need functions?
There is a well-known rule among programmers called “Don’t Repeat Yourself”. Every repetition in code is a chance for a new bug and an extra burden when you make changes. Functions solve that problem, and they bring three other important benefits:
- Clarity: a name such as
calculate_averageexplains what happens without your reading the details. - Testing: you can test each function on its own and make sure it is correct before using it in the larger program.
- Teamwork: each team member can write different functions, which are then brought together.
In fact, you have been using functions since day one: print(), len() and input() are all ready-made functions written by Python’s developers. Now it is time to write your own.
Defining and calling a function
We define a function with the keyword def, followed by its name, parentheses and a colon. The lines that belong to the function are indented:
def greet():
print("Welcome to Badr Academy Education!")
greet()
greet()
Writing def does not run anything; it only “defines” the function. It runs when we “call” it by writing its name followed by parentheses. In the example above, the message is printed twice.
Parameters: giving a function information
The function above always prints the same message. Let us make it smarter by giving it a parameter – a variable that receives a value when the function is called:
def greet(name, course="Python"):
print(f"Hello {name}, welcome to the {course} course")
greet("Mariam")
greet("Youssef", "Robotics")
greet(course="SEO", name="Sara")
There are three important ideas in this example. First, the name parameter is required. Second, the course parameter has a default value: if we do not give it one, the function uses “Python”. Third, we can pass values by name, as in the last call; then the order does not matter, and the code is clearer to the reader.
Returning a value: the difference that confuses beginners
One of the most confusing points is the difference between a function printing a result and returning it with return. Printing only shows the result on screen, and then it is gone. Returning hands the result to whoever called the function, so it can be stored in a variable or used in another calculation:
def average(scores):
if not scores:
return 0
return sum(scores) / len(scores)
math_avg = average([90, 80, 70])
science_avg = average([85, 95])
print("Average of both subjects:", (math_avg + science_avg) / 2)
Notice that we used the function’s result in a new calculation, which would be impossible if the function only printed. Notice too that we handled the empty-list case, because dividing by zero causes an error. Thinking about these “edge cases” is a sign of a good programmer. And when execution reaches return, the function ends immediately; any line after it inside the function will not run.
| Comparison | print() | return |
|---|---|---|
| What does it do? | Shows a value on screen | Hands a value to whoever called the function |
| Can the result be stored in a variable? | No – the result is None | Yes |
| Does it end the function? | No | Yes, immediately |
| When do you use it? | To show the user a message | When you need the result in a later step |
Other forms you will meet
Functions that take any number of values
Sometimes you do not know in advance how many values will reach a function. In that case you put an asterisk before the parameter name, as in def total(*numbers), and the function receives all the values in one tuple you can loop over. In the same way, a double asterisk, **options, receives any number of named values in a dictionary. You will see both often in Python libraries; you do not need them in your first programs, but it helps to recognise them when you read them.
Short functions (lambda)
For very short operations there are nameless functions written on one line, such as lambda x: x * 2. Their best-known use is setting a sort order, such as sorting a list of students by their marks. The rule: if the operation needs more than one simple expression, write an ordinary function with a clear name.
Variable scope
A variable you create inside a function lives only inside it and is called a local variable. When the function ends, it disappears. A variable you create outside all functions is called a global variable, and it can be read from inside functions. The practical rule: let a function receive what it needs through its parameters and give back its result through return, and avoid relying on or changing global variables from inside functions. That keeps each function independent, easy to understand, test and move to another program.
How do you split a big problem into functions?
The real skill is not writing a function but knowing how to split a program into suitable functions. Take an example: a program that reads students’ marks, calculates each student’s average, decides their grade and prints a report.
def grade(avg):
if avg >= 90:
return "Excellent"
elif avg >= 75:
return "Very good"
elif avg >= 50:
return "Pass"
return "Needs support"
students = {"Mariam": [95, 88, 92], "Youssef": [70, 65, 80]}
for name, scores in students.items():
avg = average(scores)
print(f"{name}: {avg:.1f} – {grade(avg)}")
Notice that each function does one clear job, and its name explains that job. If you later want to change the grade boundaries, you will edit the grade function alone without touching the rest of the program.
In the following video Corey Schafer explains functions with clear, graded examples:
How do you make sure your function works?
One of the best things about functions is that you can test each one on its own. The simplest way is Python’s assert statement: after the function, write a line saying the result of a particular call must equal a value you already know; if it does not, the program stops with a clear error message. Test the average function, for example, with an ordinary list, a list with one item and an empty list. When you change the function later, run these tests again to make sure you have not broken something that worked. This small habit is the beginning of what professionals call “automated testing”, and you will find advanced tools for it as your projects grow.
Tips for writing good functions
- One function, one job: if you need the word “and” to describe what a function does, consider splitting it.
- Names with verbs:
calculate_totalandsend_reportare clearer thantotalandreport. - Short functions: if a function runs past one screen, it can usually be split.
- Document it: under the definition line, write a short text between triple quotes explaining what it takes and what it returns. This is called a docstring, and Python shows it when you use
help(). - Test it with different cases: a normal value, an edge value and an empty value.
Exercises to practise
- Write a function that takes a rectangle’s length and width and returns its area, then another that returns its perimeter.
- Write a function
is_eventhat returnsTrueif a number is even. - Write a function that takes a text and returns the number of words in it.
- Write a temperature-conversion function from Celsius to Fahrenheit, with an optional parameter that sets the direction of conversion.
After functions, the natural next step is object-oriented programming, which brings data and functions together in one unit. To review the basics, go back to variables and data types. In the Python course at Badr Academy Education we apply functions in real projects with code review. For further resources visit the learning library, and for a complete plan try the Find your path tool.
The takeaway
A function is a named block of code that receives information through parameters and gives back a result with return. Use functions to avoid repetition and to split a program into small, clear tasks that are easy to test and change. Remember: one job per function, and a name that says what it does.
© 2026 Badr Academy Education – this content is exclusive to Badr Academy Education. Short quotations are welcome with the source and a link to this page.
Category: Programming
Comments (0)
You can comment without an account; your comment appears after review, and the academy may edit it before publishing.
No comments yet – be the first to join in.


Add a comment