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

How I Reduced 10 Python Functions to Just 2 (Without Losing Readability)
Photo by Jonathan Petersson on Unsplash

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.

Photo by Sorasak on Unsplash