DEV Community

Cover image for I Thought I Understood Python Functions — Until One Line Returned None
Emmimal Alexander
Emmimal Alexander

Posted on

I Thought I Understood Python Functions — Until One Line Returned None

I Thought I Understood Python Functions — Until One Line Returned None

I still remember the day I felt confident with Python functions.

I could write def without hesitation.
I could pass arguments.
I could even explain return to someone else.

And yet… my program was broken.

No errors.
No crashes.
Just logic that looked right and behaved wrong.

The Code That Started It All

I was writing a small script. Nothing serious.

def calculate_total(price, tax):
    print(price + tax)

total = calculate_total(100, 10)
print(total)
Enter fullscreen mode Exit fullscreen mode

When I ran it, I saw:

110
None
Enter fullscreen mode Exit fullscreen mode

My first thought was:
“Python is being weird.”

My second thought was worse:
*“Maybe I don’t actually understand functions.”
*

The Moment It Clicked

I stared at the code longer than I’d like to admit.

The function worked.
The math was correct.
The number printed.

So why was total equal to None?

Then it hit me.

The function didn’t return anything.

It only talked to me, not to the program.

print() Was Lying to Me

print() had trained me badly.

Every time I printed something, my brain thought:

“The function produced a value.”

But it didn’t.

It only showed output on the screen.

def calculate_total(price, tax):
    return price + tax
Enter fullscreen mode Exit fullscreen mode

One word changed everything.

Now the function didn’t just do work.
It communicated.

The Next Trap: “Why Didn’t My Variable Change?”

Feeling smarter, I moved on.

def increment(value):
    value += 1

count = 10
increment(count)
print(count)
Enter fullscreen mode Exit fullscreen mode

Still 10.

I felt betrayed again.

I passed the variable.
I modified it.

So why didn’t it change?

Because the function never touched count.

It received a temporary name pointing to the same value.
When execution ended, that name vanished.

No magic.
No shared memory.
Just execution boundaries.

The Mistake I Didn’t Know I Was Making

Looking back, I realized something uncomfortable.

I wasn’t treating functions as execution steps.
I was treating them like containers.

Places where I dumped logic and hoped it worked.

But Python doesn’t work that way.

A function:

Starts execution only when called

Lives briefly

Dies immediately after returning

Leaves behind only what you return

Nothing else survives.

The Day I Stopped Writing “Working” Functions

That day changed how I wrote Python.

I stopped asking:

“Does this function run?”

I started asking:

“What does this function return?”

I stopped trusting printed output.
I stopped assuming variables would change.
I stopped writing functions that felt correct but failed quietly.

What Professionals Knew All Along

Later, reading real-world code, I noticed something.

Professional functions:

  • Rarely print
  • Always return intentionally
  • Have clear inputs and outputs
  • Feel boring—and that’s the point

Boring code is predictable code.

If This Story Feels Familiar

If you’ve ever:

  • Seen None appear out of nowhere
  • Watched logic “work” but fail later
  • Printed your way through debugging
  • Felt unsure what a function actually does

You’re not alone.

I broke down this entire experience—step by step—through real mistakes developers make here:

👉 How to Define and Call Functions in Python
🔗 https://emitechlogic.com/define-and-call-functions-in-python/

The Lesson I Carry Forward

Python functions aren’t confusing.

Our mental models are.

Once you understand that:

  • Defining doesn’t execute
  • Printing doesn’t return
  • Parameters don’t modify callers
  • Execution is temporary

Functions stop surprising you.

And that’s when Python finally starts feeling calm instead of chaotic.

Top comments (0)