[HN Gopher] Python Design Patterns (2018)
       ___________________________________________________________________
        
       Python Design Patterns (2018)
        
       Author : luu
       Score  : 219 points
       Date   : 2022-03-12 06:43 UTC (1 days ago)
        
 (HTM) web link (python-patterns.guide)
 (TXT) w3m dump (python-patterns.guide)
        
       | simulo wrote:
       | Nice! I just looked at it yesterday when I was collecting
       | resources on architecture of WebApps in python. I found that
       | Refactoring guru also has python examples for them pattern
       | section.
        
       | brumar wrote:
       | This is my favorite ressource on the subject. I recommend it as
       | often as possible.
        
       | rmbyrro wrote:
       | Some of these patterns have proved to be really powerful in real-
       | world projects.
       | 
       | One challenge is having them fresh on my mind and being able to
       | spot when it makes sense to apply them.
       | 
       | Have been thinking about using flashcards and spaced repetition
       | to achieve better retention and ability to apply in practice.
       | 
       | Anyone has experience with this?
        
         | blt wrote:
         | Use good libraries and pay attention to what makes them
         | appealing. Large programs should usually be structured as a
         | collection of libraries. When you are designing an API for your
         | own libraries, think back to how other libraries solved similar
         | problems at the API level. Many (most?) worthwhile design
         | patterns can then be derived from scratch as a way to achieve a
         | particular API structure.
        
         | brumar wrote:
         | As others wrote, in depth practice is a sensible choice. Once
         | it's done, I believe spaced repetition is a nice insurance
         | against memory fading and can be as simple as a few big cards
         | listing the concepts learned even if that's really not what
         | spaced repetition proponent would suggest.
        
         | travisjungroth wrote:
         | Insanely powerful and underutilized technique: write a list of
         | techniques you can apply (in this case, patterns). Just write
         | the names, you want this to be dense. When you have a choice to
         | make, look at the list. It doesn't take long to scan 12 names.
        
         | nerdponx wrote:
         | My experience is that worked, traditional textbook-style
         | exercises are the best way to learn and internalize this kind
         | of knowledge. A combination of shorter exercises with longer
         | open-ended tasks is good. Basically more or less what you'd get
         | on a homework problem set in a university course.
         | 
         | Maybe the fact that this kind of work ends up being "spaced
         | repetition" in some sense is part of why it's helpful.
        
         | kaycebasques wrote:
         | Maybe work from the other direction? Work through each pattern
         | and think about where they might work in your existing
         | codebases and then try implementing them just for the sake of
         | hands-on experience.
        
         | simulo wrote:
         | I made the experience that they are hard to learn and
         | understand out of context, so practicing on flashcards does not
         | make much sense for me. What I did is programming some mini
         | projects in which one or two patterns are used: Pub-sub is nice
         | in anything UI related, commands+state is great for a simple
         | undo/redo-manager etc.
        
       | ThePhysicist wrote:
       | If you're interested in Python anti-patterns instead, we wrote an
       | open-source book on them a while ago:
       | https://docs.quantifiedcode.com/python-anti-patterns/
       | 
       | Hasn't received any updates in the last years but it still holds
       | up quite well, disregarding the Python 2 specific anti-patterns
       | of course which become less and less relevant, as well as the
       | Django-specific ones, which probably are hopelessly outdated.
        
         | IshKebab wrote:
         | Not a bad list. Feels like most of them should just be linter
         | rules. I also found a few them don't really apply if you're
         | using static types (which you really really really should),
         | e.g.
         | 
         | * Returning more than one variable type from function call:
         | That's fine; the type checker will make sure you don't make a
         | mistake.
         | 
         | * Asking for permission instead of forgiveness: Makes sense for
         | the example given (`unlink`) but it is better to e.g. check
         | types explicitly with `isinstance()` than to catch `TypeError`.
        
           | ThePhysicist wrote:
           | Yes absolutely, that book was written before type annotations
           | made it into Python though.
        
       | sgt wrote:
       | Not idiomatic Python. Don't model your best practices in Python
       | based on what makes sense in e.g. C++ and Java.
        
         | munro wrote:
         | 100000%, Python is really excelling at functional programming
         | these days. With dataclasses & typing we now effectively have
         | GADTs. Every few months I'm noticing small functional
         | improvements, and I'm loving it! Even though it says `class`, I
         | use it for GADTs, Protocols, and eDSLs--and it feels very
         | idiomatic. These are the 'patterns' you see in SQLAlchemy, jax,
         | pytorch.
        
           | nuclearnice1 wrote:
           | Interesting stuff! What are the sources to learn more?
        
       | chapium wrote:
       | I feel a bit contrarian about design pattern lists. These always
       | seem to contain a list of solutions and after some fancy
       | gymnastics, a list of potential problems they might solve. I feel
       | it might be more useful to create a list of common software
       | problems and follow them with a pattern that helps solve the
       | problem. I think this would help address the issue of these
       | pattern guides being applied overzealously.
        
         | xtiansimon wrote:
         | Cookbook?
        
         | syntaxfree wrote:
         | Pattern clusters would be better. Like "... so you want to
         | design a programming language, this is the Visitor pattern, the
         | Dispatch..."
        
       | [deleted]
        
       | rochak wrote:
       | Well, this post turned out to be a gem. Loved it.
        
       | ericls wrote:
       | I don't like these content about programming. Why listing a bunch
       | possible of answers to some solved problems instead of try to
       | dive deep into the problem themselves.
       | 
       | This feels like encouraging people to buy a bunch of cameras
       | instead of teaching people how to take good photos.
       | 
       | A good solution may end up looking like some patterns, but
       | sourcing good solutions from a pool of patterns is impossible
       | unless the problem you are trying to solve is the exact same as
       | the one a pattern is solving, in the same environment and
       | context.
       | 
       | I do find the content can be very useful for many, but can we not
       | call them patterns?
        
       | nooorofe wrote:
       | > Python Design Patterns
       | 
       | My brain puts it next to: globe of China, Jewish Olympic games
       | (real thing).
        
       | rr808 wrote:
       | This is great. I always thought that GoF patterns is largely
       | obsolete in 2022, it would be nice if the author agreed and has a
       | list of GoF patterns that really dont make sense any more.
       | Builder was one I thought should be included but OP seems to
       | think its relevant (though different).
        
         | jerf wrote:
         | In terms of obsolete GoF patterns, Flyweight is my nomination.
         | It's not that it's useless, is just that in an era of 64 MB of
         | RAM, it makes sense that people might need to know about it,
         | but in an era of 64 GB of RAM the need is diminished to the
         | point that only the people who have those problems need to
         | worry about it.
         | 
         | And if you _do_ have those problems, it isn 't even necessarily
         | what you would reach for first. Though it's at least on the
         | list.
        
         | hcrisp wrote:
         | Luciano Ramalho in his book "Fluent Python" mentioned that some
         | (most?) of the GoF patterns are unneeded in a dynamic language
         | like Python. I see [0] he is favorable to this site's author,
         | so it is probably worth a look.
         | 
         | [0]
         | https://twitter.com/ramalhoorg/status/960746929025142784?s=2...
        
           | polynomial wrote:
           | How did you happen to see that? That tweet is perfectly
           | relevant, it's byond _uncanny_ that you had it at the ready.
        
             | hcrisp wrote:
             | Coincidence. I was trying to find the reference to
             | Ramalho's comment about GoF and found his comment in a
             | random search.
        
           | stingraycharles wrote:
           | Interesting, thanks for sharing. Is the opposite also true,
           | that when a language is statically typed, design patterns are
           | likely to be needed?
        
             | javcasas wrote:
             | It depends on the language expresiveness, not on it being
             | static/dynamic types. Dynamic languages tend to have less
             | limitations to expresiveness (no typechecker in the middle)
             | and then you have programming languages with static types
             | and decent typecheckers that don't require design patterns
             | because they are still very expressive.
        
           | hcrisp wrote:
           | I found the quote. He says Peter Norvig wrote that "16 out of
           | 23 patterns have qualitatively simpler implementation in Lisp
           | or Dylan than in C++ for at least some uses of each pattern"
           | and that Python shares some of the dynamic features of these
           | languages such as first-class functions. I wonder if making
           | GoF patterns simpler or even "invisible" in C++ using
           | functions or callable-objects is implicitly not allowed
           | because of the static typing of the language or if it just
           | wasn't considered by the authors.
        
           | javcasas wrote:
           | Most of the design patterns exist because of limitations in
           | programming languages, especially java/c++/c#. The strategy
           | pattern disappears when you can store functions in data
           | structures. The abstract factory pattern disappears when you
           | can pass functions as parameters. The builder pattern
           | disappears when your progamming language has named
           | parameters. The observer pattern is callbacks with additional
           | steps. The mediator pattern disappears with support on
           | variants of functional reactive programming. The iterator
           | pattern disappears by using your favourite version of
           | generators (or just go hardcore like Haskell and do
           | foldable/traversable).
           | 
           | IMO GoF has been obsolete for the last 20 years (50 years if
           | you consider that languages like ML, Lisp and friends already
           | existed then).
        
         | happymellon wrote:
         | Builder patterns work very well for generation of templates. I
         | use them a fair amount when dealing with Amazon's CDK as it
         | helps with fixing a lot of readability issues.
         | 
         | I see people claim that GoF patterns are obsolete, and that
         | builder is one of the ones that are old hat, but for making
         | configurations readable it can be the best solution.
        
           | javcasas wrote:
           | What's the advantage of:
           | 
           | t = TemplateBuilder() .withFoo(foo) .withBar(bar)
           | .excludeBaz() .build()
           | 
           | over:
           | 
           | t = Template(foo=foo, bar=bar, baz=none)
        
             | culturedsystems wrote:
             | I agree there's not much point using this kind of simple
             | builder if you have named function parameters, but the GoF
             | builder pattern has a couple of additional features which
             | can still be useful. In the GoF examples the construction
             | process is more complicated (maybe the order in which
             | construction steps take place is significant, and maybe
             | parts of the construction might be conditional), and the
             | same construction algorithm can be used to produce
             | different types of object. If I remember correctly, the
             | main example in the GoF book is a builder for creating
             | documents by adding a title, subtitle, paragraphs, etc, and
             | the document being constructed might be a UI
             | representation, an RTF file, HTML, etc.
        
       | musha68k wrote:
       | I know python (3) is an object oriented programming language by
       | design but none the less I was wondering if some "functional"
       | pythonista's had recommendations on some good "less (oop) is
       | more" patterns to share in here?
        
         | oroul wrote:
         | It's hard to completely get away from objects in Python, but I
         | don't think that needs to be an objective to get away from OOP
         | patterns. My suggestions would be:
         | 
         | - Don't use classes for information. Use regular data
         | structures (dict, list, tuple, set) and use functions to
         | manipulate them. If you really want/need something like a
         | struct, use a dataclass.
         | 
         | - The itertools module has a bunch of useful constructs for
         | creating and combining iterators. Take advantage of Python's
         | iterators and construct your own when necessary.
         | 
         | - List comprehensions and generator expressions are great for
         | clear and concise data transformations
         | 
         | - You're going to have to deal with state somewhere in your
         | program. That's fine, some state is necessary to do real work.
         | Don't feel bad about creating classes for things like context
         | managers (e.g. for a database connection) so you can use it in
         | a with statement and it will handle the setup and teardown
         | logic for you. That way your business logic stays concise and
         | Pythonic since those classes can be in separate modules and
         | imported as necessary. I've found this 'functions in the front,
         | classes in the back' approach to writing Python useful as it
         | lets me think about what my program does in a functional manner
         | without denying myself the ergonomics of Python's class-based
         | ecosystem.
        
         | javcasas wrote:
         | Scrap all the factories. The class name is also a function and
         | a constructor. Just pass it around as parameter, and bypass all
         | the factory stuff.
         | 
         | Use named parameters and bypass the builder pattern.
         | 
         | Store operations in objects/lists. Bypass the strategy patterns
         | with this knowledge. Did you know myobject.mymethod is a
         | function, and you can do x = myobject.mymethod, and then x()?
         | Store methods in lists, pass them as parameters, partially-
         | apply parameters to them.
         | 
         | Generators are more than what the iterator pattern will never
         | be.
        
         | qbasic_forever wrote:
         | Learn Go and spend some time in its world, then come back to
         | Python IMHO. You'll start to appreciate the subset of Python
         | that's just functions at the module and class level and ignore
         | all the complexities of metaprogramming, class hierarchies,
         | etc. You'll find a lot of folks using Go are coming from Python
         | and burnt out on big, complex codebases there--the simplicity
         | and "less is more" is a breath of fresh air to reapply to
         | Python.
        
         | ElevenPhonons wrote:
         | https://github.com/mpkocher/Functional-Programming-Technique...
         | 
         | I covered a few core concepts (e.g., functions as first-class
         | citizens, closures, partial application, etc...) and added a
         | few real world examples of using a functional centric design.
         | The text/format has some rough edges, but overall I think the
         | text is useful for internalizing how to leverage a functional-
         | ish approach.
         | 
         | Other resources.
         | 
         | https://github.com/sfermigier/awesome-functional-python
        
       | klysm wrote:
       | In my experience, developers that reach for design patterns
       | recently read a design patterns book and are desperate to apply
       | them to problems, instead of trying to figure out the best
       | solution to the problem. Design patterns (imo) should be used to
       | get a feel for the design space that you can choose from, but
       | it's far from a total enumeration.
        
       | MaxMoney wrote:
        
       | carapace wrote:
       | FWIW, if you really want to understand Pattern Language you
       | should go and read the source material: Christopher Alexander's
       | book of the same name and it's companion volumes. The GoF did a
       | fine job, but there's a richer and deeper constellation of ideas
       | and philosophy and design strategies in the original material.
       | 
       | - - - -
       | 
       | In re: Singleton pattern in Python: one interesting technique is
       | to use a module as a singleton. When client modules "import
       | singlefoo" the first import caches the module object (in the
       | sys.modules dict) and subsequent imports use it: presto!
       | Singleton!
        
       ___________________________________________________________________
       (page generated 2022-03-13 23:00 UTC)