How I Reduced 10 Python Functions to Just 2 (Without Losing Readability)
A practical journey into refactoring, cleaner abstractions, and writing fewer lines of Python code

Less Code, Same Power — Cleaner, Smarter Python Ahead.
How I Reduced 10 Python Functions to Just 2 (Without Losing Readability)
There’s a fine line between clever code and confusing code. I’ve crossed it before — and paid the price. But this time, I wanted to find a sweet spot: reduce boilerplate, keep things elegant, and still make it readable.
So I took 10 different Python functions — each solving similar problems in slightly different ways — and merged them down to just two powerful, flexible functions.
Here’s how I did it, what I learned, and how you can do the same
The Backstory: Too Many Functions, Too Much Repetition
This all started with a data-cleaning module I wrote for one of my projects.
Over time, the file ballooned into a mess of repetitive utility functions:
def clean_name(name): ...
def clean_email(email): ...
def clean_phone(phone): ...
def clean_address(address): ...
def clean_company(company): ...
# and so on...
Each function did pretty much the same thing:
- Check if the input was valid
- Strip whitespace
- Fix formatting
- Apply custom logic for each field
The result?
10+ functions with 90% duplicate code.
It worked — but it wasn’t elegant. And I dreaded maintaining it.
Step 1: Spot the Repetition (and Pattern)
The first step was obvious: audit the code.
I printed each function side-by-side and quickly saw the similarities:
- All functions took a single string input
- Most returned a cleaned-up string (or
None
) - Each had a few small differences (e.g., custom rules per field)
So I asked: Can I abstract the common parts and pass in the custom logic?
The answer: yes — with a touch of Python functional programming.
Step 2: The First Abstraction — clean_field()
I started by writing a general-purpose function:
def clean_field(value, formatter=None, validator=None):
if not value or not isinstance(value, str):
return None
value = value.strip()
if validator and not validator(value):
return None
if formatter:
value = formatter(value)
return value
Now instead of writing 10 separate functions, I could do:
clean_name = lambda val: clean_field(val, formatter=str.title)
clean_email = lambda val: clean_field(val, validator=is_valid_email)
clean_phone = lambda val: clean_field(val, formatter=format_phone, validator=is_valid_phone)
Result: 10 functions → 1 reusable function + a few one-liners
This alone cut my code in half and removed the repetition. But I wasn’t done yet.
Step 3: Take It Further — The FieldCleaner
Class
After a few more use cases popped up (like cleaning lists, or handling nested dictionaries), I needed more structure. So I created a flexible class-based approach:
class FieldCleaner:
def __init__(self, formatter=None, validator=None, default=None):
self.formatter = formatter
self.validator = validator
self.default = default
def clean(self, value):
if not value or not isinstance(value, str):
return self.default
value = value.strip()
if self.validator and not self.validator(value):
return self.default
if self.formatter:
value = self.formatter(value)
return value
Usage became delightfully clean:
cleaners = {
'name': FieldCleaner(formatter=str.title),
'email': FieldCleaner(validator=is_valid_email),
'phone': FieldCleaner(formatter=format_phone, validator=is_valid_phone),
}
# Apply cleaning
def clean_record(record):
return {
key: cleaners[key].clean(val)
for key, val in record.items()
if key in cleaners
}
Why This Worked So Well
Here’s why this refactor was a game-changer:
Less Repetition
Instead of maintaining 10 similar functions, I now only manage two: a function and a class.
Easy to Read
The logic is centralized and consistent. Once you understand how FieldCleaner
works, you understand everything.
Easy to Extend
New field? Just add another entry in the cleaners
dictionary — no need to write a new function.
Testable
I can now test the clean_field()
and FieldCleaner
logic in isolation — which made unit testing easier and more focused.
When Not to Refactor Like This
Before you get excited and start merging all your functions, here’s a quick warning:
Don’t over-abstract.
This approach works great if your functions are structurally similar.
Avoid if:
- Each function is truly unique
- Logic is too domain-specific
- Readability suffers from too many nested lambdas
As always: favor clarity over cleverness.
Bonus Tip: Use Partial Functions to Keep Things Clean
Python’s functools.partial
helped me avoid verbose lambdas:
from functools import partial
clean_name = partial(clean_field, formatter=str.title)
Cleaner, more readable — and avoids anonymous functions cluttering your codebase.
Final Thoughts: Code Less, Think More
This refactor wasn’t about showing off or reducing lines for the sake of it.
It was about:
- Spotting patterns
- Extracting what’s common
- Keeping code clean, readable, and extensible
The final codebase felt tighter, simpler, and easier to onboard new developers to.
And I didn’t sacrifice a single bit of clarity.
Sometimes, writing fewer functions makes your code more powerful.
