Fundamentals 12 min read

Why Some Design Patterns Should Be Forgotten When Using Python

This article explains why traditional object‑oriented design patterns such as Strategy, Factory Method, Singleton, and Iterator often become unnecessary or overly complex in Python, illustrating with concise code examples how Python’s first‑class functions, dynamic typing, and built‑in constructs can replace them for clearer, more maintainable solutions.

NetEase LeiHuo UX Big Data Technology
NetEase LeiHuo UX Big Data Technology
NetEase LeiHuo UX Big Data Technology
Why Some Design Patterns Should Be Forgotten When Using Python

Design patterns are reusable solutions to common software design problems, traditionally expressed with classes and objects in static languages.

In Python, many of these patterns become redundant because functions, closures, and dynamic typing provide simpler alternatives.

Why design patterns are needed – they capture common problem‑solving approaches, improve code readability, and aid maintenance, especially in large, complex systems.

However, Python’s features often make the same goals achievable with less boilerplate.

Strategy pattern example: a classic class‑based implementation with an abstract PackageStrategy and concrete LowValuePack / HighValuePack classes, followed by a concise function‑based version that eliminates the abstract class.

#!/usr/bin/env python3
# -*-coding:utf-8-*-
import abc
from typing import List, Dict, Any

Package = List[Dict[str, Any]]

class PackageStrategy(abc.ABC):
    @abc.abstractmethod
    def generate_pkg(self) -> Package:
        ...

class LowValuePack(PackageStrategy):
    def generate_pkg(self):
        return [{'item': 1}]

class HighValuePack(PackageStrategy):
    def generate_pkg(self):
        return [{'item': 100}]

class Recommender:
    def __init__(self, strategy: PackageStrategy):
        self.strategy = strategy
    def recommend(self):
        return self.strategy.generate_pkg()
    def change_strategy(self, strategy: PackageStrategy):
        self.strategy = strategy

def run():
    rec = Recommender(LowValuePack())
    print(rec.recommend())
    rec.change_strategy(HighValuePack())
    print(rec.recommend())

if __name__ == '__main__':
    run()

Function‑based version reduces the core logic to 13 lines, using plain functions generate_low_value_pkg and generate_high_value_pkg without any classes.

#!/usr/bin/env python3
# -*-coding:utf-8-*-
from typing import List, Dict, Any

Package = List[Dict[str, Any]]

def generate_low_value_pkg() -> Package:
    return [{'item': 1}]

def generate_high_value_pkg() -> Package:
    return [{'item': 100}]

def run():
    recommender = generate_low_value_pkg
    print(recommender())
    recommender = generate_high_value_pkg
    print(recommender())

if __name__ == '__main__':
    run()

Factory Method pattern example shows a class‑based factory that returns different filter objects, then demonstrates a dictionary‑based approach that achieves the same result with far less code.

#!/usr/bin/env python3
# -*-coding:utf-8-*-
from abc import ABC, abstractmethod
from typing import List

class Filter(ABC):
    @abstractmethod
    def filter(self, candidates: List) -> List:
        ...

class FineFilter(Filter):
    def filter(self, candidates: List) -> List:
        return candidates[::4]

class RoughFilter(Filter):
    def filter(self, candidates: List) -> List:
        return candidates[::2]

class FilterFactory:
    def get_filter(self, fineness: str) -> Filter:
        match fineness.lower():
            case 'fine':
                return FineFilter()
            case 'rough':
                return RoughFilter()

def run():
    candidates = list(range(8))
    factory = FilterFactory()
    print(factory.get_filter('fine').filter(candidates))
    print(factory.get_filter('rough').filter(candidates))

if __name__ == '__main__':
    run()
# expected output:
# [0, 4]
# [0, 2, 4, 6]

A dictionary‑based factory filter_map = {'fine': FineFilter, 'rough': RoughFilter} and a simple function filter_factory replace the class hierarchy.

Singleton pattern example shows a classic __new__ implementation and a module‑level singleton that requires no special class logic.

#!/usr/bin/env python3
# -*-coding:utf-8-*-
class Singleton:
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

if __name__ == '__main__':
    assert Singleton() is Singleton()

In Python, simply creating a single instance in a module and importing it elsewhere achieves the same effect.

#!/usr/bin/env python3
# -*-coding:utf-8-*-
class Singleton:
    ...

singleton = Singleton()
# in another module
from my_module import singleton

Iterator pattern is native to Python; the article demonstrates that the built‑in for loop, generators, and the __iter__ / __next__ protocol already provide iterator functionality without extra pattern scaffolding.

#!/usr/bin/env python3
# -*-coding:utf-8-*-
if __name__ == '__main__':
    candidates = [{'name': 'item1', 'price': 1}, {'name': 'item2', 'price': 2}, {'name': 'item3', 'price': 3}]
    for candidate in candidates:
        print(candidate)

    def show_candidates():
        for candidate in candidates:
            yield candidate['name']

    for name in show_candidates():
        print(name)

    class Package:
        candidates = candidates
        def __iter__(self):
            def iterator():
                for candidate in self.candidates:
                    yield candidate['name']
            return iterator()

    for c in Package():
        print(c)

Conclusion: Python’s dynamic features often render traditional design patterns unnecessary, allowing developers to write shorter, clearer, and more maintainable code by leveraging first‑class functions, dictionaries, and built‑in iteration constructs.

design patternsStrategy PatternPythonsoftware engineeringIteratorsingletonFactory Method
NetEase LeiHuo UX Big Data Technology
Written by

NetEase LeiHuo UX Big Data Technology

The NetEase LeiHuo UX Data Team creates practical data‑modeling solutions for gaming, offering comprehensive analysis and insights to enhance user experience and enable precise marketing for development and operations. This account shares industry trends and cutting‑edge data knowledge with students and data professionals, aiming to advance the ecosystem together with enthusiasts.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.