Python Functions
Master the concept step by step with clear explanations, examples, and code you can run.
Mastering Python Functions: Your First Step to Reusable Code
Hello there! Grab a seat and welcome back to our Python journey;
in our last chat, we explored how to build highly optimized data containers using Python Dictionaries. But at the end about that lesson I left you of an important thought. Look by all amazing code we've written so far—calculating bakery change, organizing student grades, or checking VIP access. Right now, every time we write script, it just runs once, and if we want towards use our grade-checking logic again tomorrow, we have to rewrite or copy-paste the exact same code from scratch.
That sounds exhausting, right?
What if we could package our code up into a reusable mini-program? What if we could create tiny machine that we feed data into, and it automatically spits an answer out whenever we need it?
Today, we're basically going towards unlock this massive superpower by learning about Python Functions.
No special installation is required today. Just open up your Python editor, and let's build some machines!
The "Why" Before the "How"
Let's think about a real-world analogy; imagine you're basically baking a cake.
You have a recipe card. The recipe tells you exactly what towards do: mix the flour, crack the eggs and bake for 30 minutes. You don't have to invent a new way to bake a cake every single time you enter the kitchen; you just follow a recipe!
In programming, a Function is exactly like the recipe. It is actually block about code that you write once. You give it a name, and then, anytime you need towards do that specific task, you just "call" its name and Python runs the recipe for you;
here is a visual map of how the computer's brain processes a function:
graph TD
A[Input: Ingredients] --> B[Function: The Baking Recipe]
B --> C[Output: A Delicious Cake]
style B fill:#87CEFA,stroke:#333,stroke-width:2px
Building Your First Function
To build a function in Python we use the def keyword. This stands of "define". We're basically defining a new recipe.
Let's write the simple machine that says hello.
def say_hello():
print("Hello there! Welcome to the class.")
That's it! Notice the colon (:) at the end of the first line. The indentation on the next line? Just like our if statements and for loops, Python uses indentation (usually four spaces) to know exactly which code belongs inside the function, while
but if you run this code right now nothing happens. Why? Because we only wrote the recipe. We haven't actually cooked yet! To make it run we have to "call" the function by typing its name with parentheses:
say_hello()
When you type that, Python prints your message. You can type say_hello() a hundred times, and it'll run a code a hundred times, saving you from writing the print statement over and over.
Adding Ingredients: Arguments
A machine that only does one exact thing is a bit boring. What if we want our machine to greet a specific person; we can pass data into our function. We call these pieces of data arguments.
def greet_student(name):
print(f"Hello {name}, your code is looking great!")
greet_student("Alice")
greet_student("Marcus")
Now, our function acts like a smart template, while we hand it the string "Alice", it stores it temporarily in the name variable and our modern f-string formats the message perfectly.
A Next Level: Flexible Inputs with *args and **kwargs
Here is where we transition from a beginner into a true developer.
What if you don't know how many ingredients someone is going to hand you; let's say you want towards build a function that adds up the bunch about numbers, but the user might give you two numbers or they might give you fifty!
Python has a brilliant flexible solution for this. You can design functions that handle a varying number of inputs. We do this using two special tools: *args and **kwargs.
1. Gathering Items by *args
When you put the single asterisk (*) in front of word (like *args), it tells Python to collect all an extra positional arguments and pack them neatly into tuple. Do just you remember tuples from our previous chapters? They are basically perfectly locked immutable sequences!
Let's look by an example highlighted by the GeeksforGeeks Python tutorial upon args:
def add_numbers(*args):
return sum(args)
print(add_numbers(5, 10, 15))
When we pass 5, 10, 15 into a function Python magically packs them into a tuple (5, 10, 15). Then, it safely adds them together.
2. Naming Your Data with **kwargs
Sometimes you want to give your data specific names when you pass it on, like age=25 or city="Oslo", and to catch all for these named items, we use a double asterisk (**), usually written as **kwargs (which stands for keyword arguments).
Instead of packing the data into a tuple, **kwargs collects keyword arguments into a highly optimized dictionary.
def user_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
user_info(name="Emil", age=25, city="Oslo")
Because data is safely stored on a dictionary, you can easily use the .items() method to glide through the keys and values just like we learned in our dictionary lesson.
The Magic of Unpacking Data
You can also use these operators in reverse!
If you already have a list of numbers, you can use the * operator when calling a function to instantly unpack (expand) that list into separate arguments.
def my_function(a, b, c):
return a + b + c
numbers =
result = my_function(*numbers)
print(result)
By adding that tiny star, Python breaks list apart and drops 1 2 and 3 perfectly into an a, b, and c slots. This technique is beautifully clean and widely used by industry professionals.
Trustworthiness: When Should basically We Use These Tools?
As you grow your skills, you might wonder when exactly you will need such advanced flexibility, and
it really depends on your specific project needs, but there are some highly advanced industry use cases to this. For instance, *args and **kwargs are basically the absolute secret behind making "function decorators"—a powerful tool we will explore later.
And these flexible tools allow developers to perform something called monkey patching. Monkey patching simply means modifying some code at runtime, and imagine you have a class with a function that calls the online API; using these flexible arguments, developers can temporarily patch or modify that behavior on fly while a program is already running! It's an advanced trick but a great example with why Python is trusted worldwide to complex software engineering.
What's Next?
Congratulations! You've just taken the massive leap forward. You now know how to package your code into reusable recipes using functions. You also know how to dynamically accept any amount of data using *args (which creates Tuples) and **kwargs (which creates Dictionaries).
But what if we need to write the tiny, throwaway function just for a single quick calculation? Writing out a full def block with indents might feel like too much work for a simple one-line math problem.
Is there the way to write a function on a single line without even giving it the name? Yes, there is! In our next chapter, we'll just cover Python Lambda Functions, and we'll cover it next. Get ready to write some ultra-fast invisible code. I'll see you there!