Stop Copy-Pasting Your Code: Python Functions Explained
Write it once, name it, and use it anywhere. This is where your code starts to feel like real software.
Hey again! 👋
Did you spot the sneaky thing I slipped into the last post?
In Number Guessing Game 2.0, there was this line near the top:
def play_round():And later, inside it, return attempts. I didn't explain either of them. I just used them, and the game worked. Some of you noticed .
That def was a function. It let us pack an entire round of the game into one named block, then run it again and again with a single line: play_round().
Today we’re going to properly understand functions. Honestly, this is the post where your code stops being “a long list of instructions” and starts looking like something a real developer would write.
Here’s the problem functions solve. Imagine you wrote 15 lines of code to calculate a bill with tax and tip. Now you need it in three different places. Copy-paste it three times? Fine… until you find a bug. Now you have to fix it in three places. And you will forget one.
Functions fix that. Write it once. Give it a name. Use it everywhere.
What You’ll Master Today
By the end of this post, you’ll be able to:
✅ Create your own functions with def
✅ Pass information into functions using parameters
✅ Get results back out with return, and understand why it's NOT the same as print
✅ Use default values and keyword arguments
✅ Understand scope (why variables inside a function “disappear”)
✅ Build a menu-driven calculator app from small, clean functions
Prerequisites: Variables & Data Types, Operators, Control Flow, and Loops. We’ll use all of them today.
Part 1: Your First Function
Think of a function like a recipe card. Writing the recipe doesn’t cook anything. It just saves the steps under a name. The cooking happens when you use the recipe.
def greet():
print("Hello! Welcome to Python.")
greet()
greet()
# Output:
# Hello! Welcome to Python.
# Hello! Welcome to Python.Let’s break that down:
deftells Python "I'm defining a function"greetis the name we chose (same naming rules as variables)()is where inputs go (empty for now):and the indented block below it are the function's bodygreet()calls the function, which is the moment the code actually runs
Here’s the part that confuses beginners: if you only write the def part and never call it, nothing happens. You wrote the recipe, but nobody cooked.
Part 2: Parameters — Giving Your Function Information
A function that always does the exact same thing is a bit boring. Let’s make it flexible:
def greet(name):
print(f"Hello, {name}! Welcome to Python.")
greet("Ajay")
greet("Priya")
# Output:
# Hello, Ajay! Welcome to Python.
# Hello, Priya! Welcome to Python.name is a parameter, a placeholder variable that only exists inside the function. "Ajay" and "Priya" are arguments, the actual values you pass in when calling it.
Quick way to remember it: parameters are the empty boxes, arguments are what you put in them.
You can have as many parameters as you need:
def introduce(name, age, city):
print(f"{name} is {age} years old and lives in {city}.")
introduce("Priya", 24, "Kochi")
# Output:
# Priya is 24 years old and lives in Kochi.Order matters here. The first argument goes into the first parameter, the second into the second, and so on. Mix them up and you get “24 is Priya years old.” Python won’t complain, but your users will laugh at you.
Part 3: return — Getting Answers Back
So far our functions only print things. But most of the time, you want a function to calculate something and hand the result back so you can use it.
That’s what return does.
def add(a, b):
return a + b
result = add(5, 3)
print(result)
print(add(10, 20) * 2)
# Output:
# 8
# 60When Python hits return, the function sends that value back to wherever it was called. add(5, 3) literally becomes 8, so you can store it, print it, or do more math with it.
The #1 beginner trap: print vs return
This one catches almost everybody, so let’s look at it closely:
def add_with_print(a, b):
print(a + b)
def add_with_return(a, b):
return a + b
x = add_with_print(5, 3)
y = add_with_return(5, 3)
print(f"x is {x}")
print(f"y is {y}")
# Output:
# 8
# x is None
# y is 8Wait, x is None?!
Yep. print only shows a value on the screen. It doesn't give anything back. A function with no return automatically returns None, Python's way of saying "nothing."
Get Ajay Narayan’s stories in your inbox
Join Medium for free to get updates from this writer.
The rule: use print when you want a human to see something. Use return when you want your code to use the result.
return also ends the function immediately
def check_age(age):
if age >= 18:
return "Adult"
return "Minor"
print(check_age(25))
print(check_age(15))
# Output:
# Adult
# MinorNotice there’s no else. We don't need it! If age >= 18, the function returns "Adult" and stops right there. The second return only runs if the first one didn't. You'll see this pattern everywhere in real code.
Part 4: Default Values and Keyword Arguments
Default values
Sometimes a parameter usually has the same value. You can set a default:
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Ajay")
greet("Ajay", "Good morning")
# Output:
# Hello, Ajay!
# Good morning, Ajay!If you don’t pass a greeting, Python uses "Hello". If you do, yours wins.
One rule: parameters with defaults must come after the ones without. def greet(greeting="Hello", name): will give you an error.
Keyword arguments
When a function has lots of parameters, remembering the order gets painful. So you can name them when you call the function:
def make_coffee(size, milk, sugar):
print(f"A {size} coffee with {milk} milk and {sugar} sugar(s).")
make_coffee(sugar=2, size="large", milk="oat")
# Output:
# A large coffee with oat milk and 2 sugar(s).Order doesn’t matter anymore, because each value is labelled. Bonus: your code becomes much easier to read. make_coffee("large", "oat", 2) makes you guess; the keyword version doesn't.
Part 5: Scope — Where Variables Live
Try this:
def set_score():
score = 100
print(f"Inside the function: {score}")
set_score()
print(score)
# Output:
# Inside the function: 100
# NameError: name 'score' is not definedWhat happened? Variables created inside a function are local. They exist only while the function is running, and then they’re gone. The outside world can’t see them.
Think of it like a hotel room. Whatever you leave in the room stays in the room. Once you check out, housekeeping clears it.
So how do you get data out of a function? You already know: return it.
def add_points(score, points):
return score + points
score = 0
score = add_points(score, 10)
score = add_points(score, 25)
print(score)
# Output:
# 35Pass data in with parameters, send data out with return. Stick to that and your functions will be predictable, easy to test, and easy to reuse.
💡 You might see the
globalkeyword online as a way around this. Avoid it for now. It makes code much harder to follow. "In through parameters, out through return" will take you very far.
Part 6: Real-World Functions
Bill Splitter with Tip
Functions can call other functions. That’s how you build bigger programs out of small, simple pieces:
def calculate_tip(bill, tip_percent=10):
"""Return the tip amount for a bill."""
return bill * tip_percent / 100
def split_bill(bill, people, tip_percent=10):
"""Return how much each person pays, tip included."""
tip = calculate_tip(bill, tip_percent)
return (bill + tip) / people
print("Bill Splitter")
print("-" * 40)
bill = float(input("Total bill (₹): "))
people = int(input("Number of people: "))
tip_percent = int(input("Tip %: "))
each = split_bill(bill, people, tip_percent)
print(f"Each person pays: ₹{each:.2f}")
# Example run:
# Total bill (₹): 1200
# Number of people: 4
# Tip %: 10
# Each person pays: ₹330.00See those lines in triple quotes right under def? Those are docstrings, short descriptions of what the function does. They're optional, but they're a great habit. Future-you will thank present-you.
Password Strength Checker
def is_strong_password(password):
"""A strong password has 8+ characters, a digit, and an uppercase letter."""
if len(password) < 8:
return False
has_digit = False
has_upper = False
for char in password:
if char.isdigit():
has_digit = True
if char.isupper():
has_upper = True
return has_digit and has_upper
print(is_strong_password("hello"))
print(is_strong_password("helloworld"))
print(is_strong_password("HelloWorld7"))
# Output:
# False
# False
# TrueLook how much from previous posts is packed in here: a loop, conditions, booleans, and, and an early return. The function hides all that detail behind one clear question: is this password strong?
That’s the real superpower of functions. They let you give a name to an idea.
Mini Project: Python Calculator App
Let’s build a proper menu-driven calculator, made entirely of small functions, each doing one job.
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
return None
return a / b
def show_menu():
print("\n1. Add")
print("2. Subtract")
print("3. Multiply")
print("4. Divide")
print("5. Quit")
def get_number(prompt):
return float(input(prompt))
def calculate(choice, a, b):
if choice == "1":
return add(a, b)
elif choice == "2":
return subtract(a, b)
elif choice == "3":
return multiply(a, b)
else:
return divide(a, b)
def main():
print("=" * 50)
print("PYTHON CALCULATOR")
print("=" * 50)
while True:
show_menu()
choice = input("Choose an option (1-5): ")
if choice == "5":
print("Goodbye! 👋")
break
if choice not in ["1", "2", "3", "4"]:
print("Invalid option. Try again.")
continue
a = get_number("First number: ")
b = get_number("Second number: ")
result = calculate(choice, a, b)
if result is None:
print("Error: you can't divide by zero!")
else:
print(f"Result: {result}")
main()Read main() out loud. It almost sounds like English: show the menu, get a choice, quit if they chose 5, get two numbers, calculate, show the result. That's the goal. Each function is small and boring on its own, and together they make a clean, readable program.
Also notice the while True + break pattern from the loops post, and continue to skip invalid input. Everything you've learned is starting to stack. 🧱
Practice Challenges
Beginner Level
- Square It: Write a function
square(n)that returnsnsquared. Printsquare(4)andsquare(9). - Even or Odd: Write
is_even(n)that returnsTrueif a number is even andFalseotherwise.
Intermediate Level
- Temperature Converter: Write
celsius_to_fahrenheit(c)andfahrenheit_to_celsius(f). Then build a small menu that lets the user pick which one to use. - Vowel Counter, Upgraded: Take your vowel counter from the loops post and turn it into a function
count_vowels(word)that returns the count.
Advanced Level
- Prime Toolkit: Write
is_prime(n)that returnsTrueorFalse. Then writeprint_primes(limit)that usesis_primeto print every prime up tolimit. (This is functions calling functions, exactly like the bill splitter.)
Before You Go
Did functions finally make sense? Hit that 👏 clap button.
Built the calculator? Add a fifth operation (power, maybe?) and share your version in the comments. I’d love to see it.
Coming up next: Lists, where we finally give your programs a way to store many values at once. Hit Follow so you don’t miss it.
See you in the next post! 🐍✨
Enjoying this series? Share it with a friend learning Python. Let’s all grow faster, together.
Check out the series so far:
- Python in 2025: Why This Language Still Dominates
- Variables and Data Types
- Python Operators Decoded
- Control Flow Mastery
- Why Write Code Once When It Can Just… Repeat? (Loops)








