[HN Gopher] Design patterns you should unlearn in Python
       ___________________________________________________________________
        
       Design patterns you should unlearn in Python
        
       Author : zeitlupe
       Score  : 76 points
       Date   : 2025-08-01 16:29 UTC (6 hours ago)
        
 (HTM) web link (www.lihil.cc)
 (TXT) w3m dump (www.lihil.cc)
        
       | wodenokoto wrote:
       | I like the concept of the article but I'm not sure I've seen
       | these in the wild.
        
         | BugsJustFindMe wrote:
         | It's more like "if switching from Java to Python". I've also
         | never seen anyone writing Python do this.
        
           | citrin_ru wrote:
           | I've seen a person using in Perl Singleton classes, Factory
           | classes and other Java patterns. The app worked well but the
           | code was probably 2x large than it could be.
        
         | whilenot-dev wrote:
         | An example of the Builder pattern in the wild:
         | https://github.com/bikram990/PyScep/blob/8d80bc03368ea8dc6ea...
         | 
         | ...especially annoying if it's only used in one continuous
         | chain:
         | https://github.com/bikram990/PyScep/blob/8d80bc03368ea8dc6ea...
        
         | mrweasel wrote:
         | The singleton one is one I've attempted, and no, it doesn't
         | work well in Python. Early in my career I worked on a number of
         | projects where the architects had used a singleton pattern for
         | a number of things. The pattern sort of stuck in my head, but
         | this was in C# and I've mostly worked in Python ever since. As
         | the article points out it's designed for language like Java and
         | C++ (and C#).
         | 
         | In my opinion the singleton pattern does however not make
         | Python code harder to test. In Python it's actually extremely
         | handy, because its incredibly easy to mock out a singleton in
         | your test cases.
        
           | AtlasBarfed wrote:
           | How does Python do mocking if it doesn't use singletons?
           | 
           | Or do people just not do unit testing in Python using spock-
           | like technology? And I do use the word technology because
           | Spock is that much better than just a bunch of test scripts
        
             | mrweasel wrote:
             | You can overwrite pretty much anything in Python at
             | runtime, and the mock tooling in the standard library can
             | help you with that, if you can't straight up just override
             | a method or object.
        
               | AtlasBarfed wrote:
               | Global vars?
               | 
               | So with a Singleton what you can do at least in Java land
               | is have your service invoke the method to get the
               | Singleton semi-global object.
               | 
               | So you can mock that method invocation to return a
               | different object. So you basically have the local object
               | to play with in your test and won't be affecting any
               | actual real global state
               | 
               | But basically the article was just saying just use global
               | variables. Does python have a means for then intercepting
               | the value request and data assignments for that global
               | variable for the local scope of the testing code? Or is
               | it hardwired like a global variable, presumably is?
        
               | orwin wrote:
               | I'm tired and I'm not sure I understood your question
               | correctly, sorry if it doesn't address your point:
               | 
               | In python test library, you have something called
               | 'monkeypatch' that allows you to intercept calls to
               | specific functions or classes and set the response
               | yourself (I mostly use it to mock API responses tbh but
               | it can do a lot more, an really complex operations).
               | Monkeypatch only operate in the scope of the function or
               | file it's written in (I think. I only remember using it
               | in unit test functions).
        
               | AtlasBarfed wrote:
               | The answer if I understand correctly is if you want to
               | use testing frameworks in Python, you should probably not
               | be using global variables and you should probably
               | actually be using the Singleton pattern.
        
       | tptacek wrote:
       | Peter Norvig has a well-known piece that goes into more depth on
       | why the GoF-style patterns don't make much sense in high-level
       | languages:
       | 
       | https://www.norvig.com/design-patterns/
        
         | shawn_w wrote:
         | Those slides would be a lot more useful with a transcript of
         | the talk that went along with them. Or a video of it. Wonder if
         | anything like that still exists.
        
       | aswerty wrote:
       | The Zen of Python: there should be one obvious way to do things.
       | 
       | Python in practice: there is more ways of doing it than in any
       | other programming language.
       | 
       | Oh Python, how I love and hate you.
        
         | shlomo_z wrote:
         | > than in any other programming language After reading the
         | article, I couldn't believe anyone designs their systems like
         | that. His "solutions" seemed to be the obvious way to do
         | things.
        
         | nhumrich wrote:
         | People misunderstand the target audience and code base for the
         | zen of python
        
           | ddejohn wrote:
           | Who's it for, then?
        
         | dkarl wrote:
         | I don't think any of the examples in the article contradict the
         | Zen of Python. Even if there's one simplest and clearest way to
         | do it in Python, there's nothing stopping people from using a
         | more complicated solution that they got used to while working
         | in a different language. They might not know to look for a
         | simpler way, because they're used to working in a language
         | where their way is the simplest.
        
       | taylorallred wrote:
       | I really appreciate how this article explains why certain design
       | patterns became a thing. Usually, it was to address some very
       | practical problem or limitation. And yet, a lot of younger
       | programmers treat these patterns like a religious dogma that they
       | must follow and don't question if they really make sense for the
       | specific situation they are in.
        
         | zelphirkalt wrote:
         | Probably also a problem that exists because of how programmers
         | are taught. Using Java and being presented with the patterns as
         | solutions to what Java does.
        
         | seadan83 wrote:
         | > a lot of younger programmers treat these patterns like a
         | religious dogma
         | 
         | First you learn what the pattern is. Then you learn when to use
         | it. Then you learn when not to use it.
         | 
         | The gap between the first and third step can be many years.
        
           | arcanemachiner wrote:
           | > The gap between the first and third step can be many years.
           | 
           | I admire your optimism!
        
         | kccqzy wrote:
         | I don't however appreciate that the author doesn't actually
         | know about Java or C++ well enough such that they are spewing
         | falsehoods about Java or C++. Saying things like "There's no
         | clean way to say 'this is private to this file' (in C++)" is
         | just bonkers. The author is well intentioned, but coming up
         | with the wrong reason is worse than not offering any reason.
        
           | dgfitz wrote:
           | I had that thought too, and thought I must have misunderstood
           | something. I generally assume I'm the dummy. :)
        
         | motorest wrote:
         | > I really appreciate how this article explains why certain
         | design patterns became a thing. Usually, it was to address some
         | very practical problem or limitation.
         | 
         | I don't agree at all. I feel that those who criticise design
         | patterns as solution to practical problems are completely
         | missing the point of design patterns, and the whole reason they
         | have the name the have: design patterns. I'll explain.
         | 
         | Design patterns are solutions to common design problems, but
         | "problems" isn't the kind of problems you think it is. It's
         | "problems" in the sense that there are requirements to be met.
         | A state pattern is a way to implement a state machine, but you
         | still have a state machine and a state pattern if your state
         | classes don't handle state transitions.
         | 
         | More to the point, look at singletons. It's irrelevant if they
         | are implemented with a class or a closure or a module. What
         | makes a singleton a singleton is the fact that there is an
         | assurance that there will be a single instance of an object.
         | Does an implementation that allow multiple instances or doesn't
         | return the same instance qualifies as a singleton? Obviously
         | not.
         | 
         | Design patterns are recurring solutions to recurring problems.
         | They are so recurring that they get their name and represent a
         | high level concept. A message queue is a design pattern. An
         | exception is a design pattern. Lazy loading is a design
         | pattern. Retries and exponential backoffs are design patterns.
         | Etc. Is anyone arguing that Python has none of it?
         | 
         | So many people trying to criticise the GoF but they don't even
         | bother to be informed or form an educated opinion.
        
           | hinkley wrote:
           | I see you've been downvoted.
           | 
           | Design patterns aren't solutions to common design problems.
           | They're after the fact descriptions of solutions for design
           | problems. That's the issue. That's the beef. Everyone thought
           | of that book as a cook book instead of a naturalists' musings
           | on an ecosystem, which is what they are.
           | 
           | Those of us who designed before people discovered that stupid
           | book were constantly asked what the differences were between
           | this pattern and that. And the book just isn't thick enough
           | and Eric Gamma was just trying to complete a thesis not write
           | a book, so despite having at least 8 years in industry before
           | completing his masters he cocked it up. And ruined Java in
           | the process.
           | 
           | We had a contemporary of Vlissades teach a class at my last
           | company and he crystallized all of my suspicions about the
           | GoF book and added a whole lot more.
           | 
           | My advice for at least fifteen years is, if you think you
           | want to read GoF, read _Refactoring_ instead. If you've read
           | _Refactoring_ and still want to read GoF, read _Refactoring_
           | a second time because it didn't all sink in.
           | 
           |  _Refactoring_ is ten times the value of GoF for teaching you
           | how to do this trade and how to break up architectural
           | brambles.
        
           | orwin wrote:
           | I mean, people usually call those 'feature' when they're
           | built-in. I would never call 'lazy evaluation' in Haskell a
           | design pattern, because it's part of the language.
           | 
           | If I have to implement something similar myself in C++
           | however, I'll use a niche design pattern.
        
         | hinkley wrote:
         | I am an ex Java developer. Enterprise Fizz Buzz is highly
         | entertaining. That stupid masters thesis pretending to be a
         | design book landed right an inflection point and ruined half a
         | generation of developers.
         | 
         | What isn't entertaining is using OpenTelemetry, which takes me
         | right back to Java for over-engineering. Moving to OTEL from
         | StatsD cost us about 3% CPU per core, which on 32 core machines
         | is an entire CPU lost to telemetry. Or more accurately, an
         | entire second CPU lost to telemetry. That is not right.
         | 
         | Prometheus doesn't have these problems. And isn't trying to fix
         | quite as many problems I've never had.
        
         | AceJohnny2 wrote:
         | The explanations are great! The condescension, not so much.
         | 
         | > Simple: we just use the language _like it was meant to be
         | used._
         | 
         | > Use Default Arguments _Like a Normal Human_
         | 
         | etc
        
         | layer8 wrote:
         | The main motivation for the concept of design patterns is to
         | give unique names to existing programming patterns, so that
         | when someone says "Strategy pattern", everyone knows what
         | pattern that refers to, and vice versa that the same pattern
         | isn't called ten different things. It's to make communication
         | about program design efficient, by defining a vocabulary of
         | patterns that tend to reoccur, and a common structure for
         | describing them. Not all patterns were successful in that way,
         | but it's the main idea behind design patterns.
         | 
         | The question of when a using a given pattern is appropriate is
         | orthogonal to that. The fact that a named pattern has been
         | defined doesn't imply a recommendation to use it across the
         | board. It depends on the context and on design forces, and
         | those change with time and circumstances. Anti-patterns are
         | patterns as well.
         | 
         | It's a pity that the idea of design patterns ended up (after
         | the pattern language craze faded) being almost exclusively
         | associated with the specific patterns named and described in
         | the GoF book.
        
           | dragonwriter wrote:
           | > The main motivation for the concept of design patterns is
           | to give unique names to existing programming patterns
           | 
           | No, naming them is not the main purpose, preserving and
           | transmitting knowledge of what they are and what they are
           | useful for, so that people aren't fofced to rediscover
           | solutions to the same problems over and over again. [0]
           | Naming is obviously important for that purpose, but isn't the
           | main goal, but a means of supporting it.
           | 
           | [0] If this sounds like a subset of the purpose of a reusable
           | code library, it is, which is why in languages with
           | sufficient abstraction facilities to allow the generic
           | implementation of a pattern to be reusable, well documented
           | (for the "where and when to use this" piece) code libraries
           | replace documents that have the explanation paired with
           | implementation recipes that one can modify to one's
           | particular use.
        
           | dkarl wrote:
           | > It's a pity that the idea of design patterns ended up
           | (after the pattern language craze faded) being almost
           | exclusively associated with the specific patterns named and
           | described in the GoF book
           | 
           | That book is the closest we came to establishing a common
           | language. I remember brushing up on the names of design
           | patterns whenever I had an interview. Ultimately, though, it
           | didn't yield any benefit that the industry is missing now.
           | 
           | Like you said, the fundamental idea behind the book was that
           | consciously naming, cataloging, and studying design patterns
           | would improve communication among programmers. There was also
           | an idea that studying design patterns would give beginning
           | programmers a richer repertoire of programming techniques
           | faster than if they had to figure them out themselves.
           | 
           | Looking back with decades of hindsight, my belief is that
           | awareness and intentional use of design patterns made no
           | difference whatsoever. Some names stuck, and would have
           | anyway. Others didn't, and years of status as official
           | "design patterns" in a book widely studied across the
           | industry couldn't make them. The younger programmers I work
           | with who had no exposure to the GoF book, and for whom
           | "design patterns" is something that dusty old farts used to
           | talk about, use patterns like Flyweight, Proxy, Command,
           | Facade, Strategy, Chain of Responsibility, Decorator, etc.
           | without knowing or needing a name for them, and they
           | communicate amongst themselves just as efficiently as my
           | generation did at the height of the design pattern craze.
           | 
           | In the final analysis, I have never looked at the less
           | experienced programmers around me and thought, "This
           | situation would go faster and smoother if they had studied
           | design patterns." The generation that learned to program
           | after design patterns had faded as an idea learned just as
           | quickly and communicates just as well as the generation that
           | studied them assiduously as junior programmers like I did.
        
             | tmh88j wrote:
             | > Like you said, the fundamental idea behind the book was
             | that consciously naming, cataloging, and studying design
             | patterns would improve communication among programmers.
             | 
             | > The younger programmers I work with who had no exposure
             | to the GoF book.....and they communicate amongst themselves
             | just as efficiently as my generation
             | 
             | > The generation that learned to program after design
             | patterns had faded as an idea learned just as quickly and
             | communicates just as well as the generation that studied
             | them assiduously as junior programmers like I did.
             | 
             | I've never read GOF so I don't know if they emphasize
             | communication, but I have read and studied many other
             | programming pattern books and communication is low on the
             | list of reasons to learn them in my opinion. Their only
             | purpose for me is to organize code in a way that has been
             | proven to "scale" along with a codebase so that you don't
             | end up with a plate of spaghetti.
        
       | NeutralForest wrote:
       | I've never seen anybody do that... In Python you can use a module
       | as a singleton (mentioned in the article). Or provide some data
       | like:                 from functools import lru_cache
       | class Whatever:           pass            @lru_cache(maxsize=1)
       | def get_whatever():           return Whatever()
       | 
       | And use `get_whatever` as your interface to get the resource.
        
         | motorest wrote:
         | > I've never seen anybody do that...
         | 
         | I feel the blog post is a bunch of poorly thought through
         | strawmen. I was browsing through the singleton example and I
         | was wondering why would anyone use buggy code to implement
         | something it clearly was not designed to implement.
         | 
         | The whole article is quite subpar. I was expecting idiomatic
         | stuff that eliminated the need to implement something, like for
         | example implementing singletons with modules and even getter
         | functions, but there was none of that: just strawmen.
         | 
         | Really disappointing.
        
         | e1gen-v wrote:
         | I do this in fast api and then pass get_whatever as a
         | dependency to an endpoint
        
           | whilenot-dev wrote:
           | Alternatively you could make use of the lifespan[0] and its
           | state[1][2].
           | 
           | [0]: https://fastapi.tiangolo.com/advanced/events/#lifespan-
           | funct...
           | 
           | [1]: https://asgi.readthedocs.io/en/latest/specs/lifespan.htm
           | l#li...
           | 
           | [2]: https://www.starlette.io/lifespan/#lifespan-state
        
         | empiko wrote:
         | You can implement a singleton class that works properly quite
         | easily. The advantage is that most people are familiar with
         | singleton as a pattern, and it is a self contained chunk of
         | code. The cache solution you provided works, but its
         | functionality is not obvious and it feels very hacky to me.
         | Somebody's going to initialize Whatever in another way down the
         | line without using the cached function...
        
       | tayo42 wrote:
       | I was writing a python thing where the class was going to have
       | like at least 20 paramaters to configure it. Builder pattern was
       | kind of feeling like a good idea to keep it cleaner for the user.
       | But it is surprising to see in the python world. It felt like a
       | mess of default values though for the user to handle.
        
         | atoav wrote:
         | I like method chaining (not the same as builder patterns) for
         | code that needs to run chained operations on objects. It is not
         | exacrly the same because each chained operation usually does
         | more than just setting a variable.
         | 
         | E.g.                 signal = Sine(freq=440.0, amp=1.0)
         | .rectify()                   .gain(2.0)
         | .center()                   .clip(0.5)
         | 
         | Each of the methods may return a Signal object that can get
         | processed by the next function, allowing you to chain them
         | together to get complex results quickly. The ergonomics on this
         | are stellar and because these methods can be implemented as
         | generators, each step can yield values lazily instead of
         | building full intermediate arrays.
         | 
         | That way, you get the clean chaining style _and_ efficient,
         | streaming computation.
        
           | mystifyingpoi wrote:
           | This also greatly increases API discoverability, because I
           | can just type "." and see the IDE pop up me all the options
           | right there, no need for docs.
        
         | mrweasel wrote:
         | Rarely have I seen a class that truly needs 20 parameters,
         | that's most often a design flaw. There might be cases where
         | this isn't true, but those are edge cases, so it's probably
         | also fine to apply a special patterns, such as the builder
         | pattern.
        
           | dragonwriter wrote:
           | > Rarely have I seen a class that truly needs 20 parameters
           | 
           | If a class seems like it needs that many parameters, it is
           | very common that one or both of these is true:
           | 
           | 1. It is doing too much, or
           | 
           | 2. There are things-that-should-be-their-own-classes hiding
           | in groups of the parameters.
           | 
           | #2 is kind of a subset of #1, but the "doing too much" tends
           | to be concentrated in validating relations between parameters
           | rather than what happens after the object is constructed.
        
         | mystifyingpoi wrote:
         | Good example for Python not needing this pattern sometimes is
         | Pulumi. Check out the differences between example code in Java
         | and Python.
         | 
         | https://www.pulumi.com/docs/iac/get-started/kubernetes/revie...
         | 
         | In Java (or even Go) this pattern is required to enforce type
         | safety. In Python it seems that they ignore the typing part and
         | just pass a bunch of dicts. Looks much cleaner, even if not
         | entirely typesafe.
        
       | the__alchemist wrote:
       | All good ones. I'll add this because A: It's common in Python,
       | and B: There are suitable alternatives in the standard library:
       | 
       | Conflating key/value lookups (dicts) with structured data
       | (classes). They are both useful tools, but are for different
       | purposes. Many python programmers (Myself many years ago
       | included!) misused dicts when they should have been using
       | dataclasses.
        
         | ddejohn wrote:
         | Everything in the codebase I maintain at my job is an arbitrary
         | dict and there is no type information anywhere. It wasn't even
         | written that long ago (dataclasses were a thing long before
         | this codebase was written).
         | 
         | There's actually a place where the original authors subclassed
         | dict, and dynamically generate attributes of a "data class"
         | such that it can be used with dotted attribute access syntax or
         | dict access syntax but the `__slots__` attribute of these
         | classes is also generated dynamically so you don't have any
         | auto-complete when trying the dotted attribute access. It's
         | genuinely insane lol.
        
       | z_open wrote:
       | He didn't mention the worst pattern, the visitor pattern, which
       | has extremely few use cases.
        
       | zelphirkalt wrote:
       | I have observed these "design pattern shoehorned into Python" so
       | many times ... Great post. When you see these things done in a
       | code base, you know that you got people, who would rather want to
       | write Java working on it. Or maybe people who don't have the feel
       | for Python as a language or something.
       | 
       | First thing I looked up in the article was "singleton", as a
       | sanity check, whether the article is any good. And yes, it shows
       | module level binding as alternative, exactly what I expected,
       | because I looked into this in the past, when someone implemented
       | API client singleton, in a case of irrelevant early optimization
       | of something that was never a bottleneck.
       | 
       | Articles like this are helpful in spreading the awareness, that
       | one should not hold a Python like one holds a Java.
        
         | necovek wrote:
         | Module-level initialization has one huge problem in Python,
         | though.
         | 
         | That means that as soon as you import a module, initialization
         | happens. Ad infinitum, and you get 0.5s or more import times
         | for libraries like sqlalchemy, requests...
        
           | ddejohn wrote:
           | yep, the legacy codebase I maintain does a lot of this kind
           | of stuff and has made it difficult to write unit tests in
           | some cases due to all the code that runs at import and all
           | the state we end up with
        
             | pbh101 wrote:
             | The article addresses this.
        
               | ddejohn wrote:
               | I know, I'm just complaining about the mountain of code
               | that does this at my company. And there is no fixing it
               | using the article's approach or any other for that matter
               | due to the sheer scale of the abuse.
        
           | zelphirkalt wrote:
           | Initialization only happens once, when you import the module
           | for the first time, afaik. Unless you are running multiple
           | Python processes, that is.
        
       | AtlasBarfed wrote:
       | Builder patterns are seriously useful for high complexity state
       | construction with the ability to encore rules to prevent
       | degenerate state.
       | 
       | A good example from my experience might be connecting to a
       | Cassandra cluster it other type of database that can have
       | extremely complex distributed settings and behaviors: timeouts,
       | consistency levels, failure modes, retry behavior, seed connector
       | sets.
       | 
       | Javaland definitely had a problem with overuse of patterns, but
       | the patterns are legitimate tools even outside of Oop.
       | 
       | I haven't done much research into testing frameworks in other
       | languages, but the spock testing framework in groovy/javaland is
       | a serious piece of good software engineering that needs
       | singletons and other "non hard coded/not global" approaches to
       | work well.
       | 
       | Spring gets a ton of hate outside of jabs, and I get it, they
       | tried to subsume every aspect of programming and apis especially
       | web into their framework, but the core spring framework solved
       | complex object graph construction in a very effective way
       | 
       | Oh you hate "objects" but have thousand line struct graph
       | construction code?
       | 
       | It's kind of sad that groovy never took off. It offered all the
       | good parts of java with a ton of good python, ruby, and other
       | langs with the solid foundation of the jvm for high speed
       | execution.
       | 
       | But it's effectively dead. Kind of like Cassandra is effectively
       | dead. The tech treadmill will eventually leave you behind.
        
         | chuckadams wrote:
         | I'd say Kotlin took most good parts of Groovy syntax and put it
         | into a decent type system, then Clojure peeled off the folks
         | who still preferred a more dynamic language. Languages can't
         | all live forever, otherwise there'd be no room for new growth.
        
         | mystifyingpoi wrote:
         | In my experience everyone will hate on Spring, showing how much
         | easier other frameworks are using tiny unrealistic examples,
         | until they hit a _really_ hard architectural challenge (imagine
         | reimplementing @Transactional in pure Java) and that 's where
         | Spring shines.
         | 
         | Yeah, it's sad, I like Groovy a lot. It got relegated to a
         | second-class citizen role on Jenkins, for the most part.
        
       | Kuraj wrote:
       | Great post. Now let's do C# because if I see a repository pattern
       | doing nothing but calling Entity Framework under the hood again
       | I'm going to rip the planet in half
        
         | motorest wrote:
         | > Great post. Now let's do C# because if I see a repository
         | pattern doing nothing but calling Entity Framework under the
         | hood again I'm going to rip the planet in half
         | 
         | Your comment shows a hefty amount of ignorance. Repositories
         | wrap Entity Framework because Entity Framework's DbContext & Co
         | are notoriously complicated to mock and stub.
         | 
         | Once you wrap EF stuff with a repository that implements an
         | interface, that problem vanishes and all your code suddenly is
         | unit testable.
        
           | Kuraj wrote:
           | We don't really have this problem in .NET 8, we mock stuff
           | just fine using an in-memory database provider.
           | 
           | But I admit my tone missed the mark. It may have been much
           | harder to do in the past, or maybe I'm missing some nuance.
           | 
           | But also at this point why not just have your DbContext
           | directly implement an interface that you can mock? Surely
           | that must be more straightforward than adding an entire
           | abstraction layer, that you have to extend with each new
           | usage scenario, and without sacrificing implicit
           | transactionality.
        
             | motorest wrote:
             | > We don't really have this problem in .NET 8, we mock
             | stuff just fine using an in-memory database provider.
             | 
             | No, you don't. At best in-memory databases represent a test
             | double that you can use in integration tests.
             | 
             | If you need to write unit tests, EF leaves you no better
             | option than to add repositories to abstract out everything
             | and anything involving DbContext.
        
         | acedTrex wrote:
         | What you dont like                 public class
         | Repository<TEntity> : IRepository<TEntity> where TEntity :
         | class       {           public async Task Add(TEntity entity)
         | {               _context.Add(entity);               await
         | _context.SaveChangesAsync();           }       }
         | 
         | everywhere?
        
       | ashvardanian wrote:
       | Singletons are considered an antipattern in pretty much all PLs.
       | C++, mentioned in the article, is not an exception.
        
         | eduardofcgo wrote:
         | Singleton is the worst example of design pattern, not sure why
         | these kinds of posts always like to mention it. Singleton is
         | just a hack for avoiding OOP with OOP languages. Obviously
         | python allows non OOP code, so not surprised singleton is
         | useless there.
        
       | bitpush wrote:
       | Great post. I dont write much python these days, but I distinctly
       | remember things being suspiciously easy .. to the point where I
       | started to wonder why arent things so complicated.
        
       | acedTrex wrote:
       | I don't agree with the builder pattern. For basic objects yes its
       | a bit silly.
       | 
       | But the ACTUAL value of the builder pattern is when you want to
       | variadically construct an object. Create the base object, then
       | loop or otherwise control flow over other state to optionally add
       | stuff to the base object.
       | 
       | Then, additionally, the final "build" call can run validations
       | over the set of the complete object. This is useful in cases
       | where an intermediate state could be invalid but a subsequent
       | update will update it to a valid state. So you dont want to
       | validate on every update.
        
         | xigoi wrote:
         | > Create the base object, then loop or otherwise control flow
         | over other state to optionally add stuff to the base object.
         | 
         | That's what list comprehensions are for.
         | 
         | > Then, additionally, the final "build" call can run
         | validations over the set of the complete object.
         | 
         | The constructor function can do that too.
        
           | acedTrex wrote:
           | The constructor can not do it because the constructor does
           | not have all the data. This is lazy evaluation.
        
         | ptx wrote:
         | Couldn't you build up a dictionary of keyword arguments instead
         | and do all the validation in the __init__ method? E.g.
         | kwargs = {}       if is_full_moon() and wind_direction == EAST:
         | kwargs["baz"] = 42              thing = Thing(foo=3.14, bar=1,
         | **kwargs)
        
           | chuckadams wrote:
           | Builders have some neat properties like partial evaluation,
           | which becomes especially neat when you use stateless builders
           | that return new instances. They can also be subclassed,
           | allowing not only behavior that can be overridden at
           | individual method granularity, but able to build a different
           | subclass.
           | 
           | Obviously don't reach for a builder if you don't have these
           | use cases though.
        
         | zem wrote:
         | I've used the builder pattern in python when I wanted to have
         | the mutable and immutable version of a class be different
         | types. you do a bunch of construction on the mutable version
         | then call "freeze" which uses the final data to construct the
         | "immutable" class.
        
         | eduardofcgo wrote:
         | Could you not just use dicts and some schema validation logic
         | for this?
        
       | kamma4434 wrote:
       | I got a feeling the author has but a vague idea of what Java and
       | C++ are.
        
       | ayhanfuat wrote:
       | Brandon Rhodes has a series of talks on this topic. Here's the
       | most up to date one:
       | 
       | Classic Design Patterns: Where Are They Now - Brandon Rhodes
       | (https://www.youtube.com/watch?v=pGq7Cr2ekVM)
        
       | zem wrote:
       | I remember the fad for dependency injection frameworks in ruby,
       | and the eventual similar pushback pointing out you could just use
       | the language features for most of it
        
       | mekoka wrote:
       | If I had but one design pattern I would just LOVE to see
       | disappear from Python, it's the need for super(). Don't get me
       | wrong, super() is a clever piece of engineering, but if your code
       | actually _needs_ what it 's useful for (C3 linearization, MRO,
       | etc), then you've made things too complicated. I deplore the
       | proliferation of libraries that have embraced the seductive, but
       | ultimately deceptive ways of the mixin, because they saw all the
       | big boys reaching for it. The devil gave multiple inheritance a
       | cooler name, some new outfits, and sunglasses to confuse the
       | Pythonistas and they embraced it with open arms.
       | 
       | Refactor to favor composition over inheritance. But if you really
       | must inherit, single over multiple, and shallow over deep.
       | Eventually your code will less and less need super() and it'll
       | become pointless to use it over the more explicit mechanism,
       | which incidentally makes everything cognitively lighter.
        
       | eduardofcgo wrote:
       | The programmers that insist in using type hints in python usually
       | are the ones that makes these mistakes. I think the main reason
       | that these patterns do not make sense is because python is a
       | dynamic language. If you turn off the part of your brain that
       | thinks in types you realize that you can solve most of these in
       | plain functions and dicts. Using default args as replacement to
       | the builder pattern is just ridiculous. If you want to encode
       | rules for creating data, that screams schema validation, not
       | builder pattern.
        
         | crgwbr wrote:
         | Python type hints are hugely valuable both as a means of
         | correctness checking, but also just as a means of
         | documentation. It strikes me as incredibly shortsighted to say
         | you can forget about types just because it's a dynamic
         | language. The types are absolutely still there and need thought
         | about. They just aren't defined or used in terms of allocation
         | and management of memory.
        
           | david422 wrote:
           | > The types are absolutely still there and need thought about
           | 
           | Yes, if they aren't in the code, it just means the programmer
           | has figure out and carry that around mentally when reading or
           | writing code.
        
           | eduardofcgo wrote:
           | Usually with OOP several builders are composed together to
           | express the creation of some data. These builders have
           | functions with types, which define the rules for the creation
           | of the objects.
           | 
           | My point is that the CarBuilder is not a real type that
           | relates to the business, but something that we had to create
           | to encode some behaviour/rules.
           | 
           | Some function that validates that a dict is a valid car is
           | much more explicit that lots of different builder classes in
           | my opinion.
        
       ___________________________________________________________________
       (page generated 2025-08-01 23:01 UTC)