6 ms·
Mostly, it's Java written with Python syntax, specially the gang-of-four patterns. I recall it being even more java-like, so, progress? The stuff that is actua
by tonnydourado 4y ago
Mostly, it's Java written with Python syntax, specially the gang-of-four patterns. I recall it being even more java-like, so, progress?
The stuff that is actually idiomatic python is either too convoluted or rather obvious.
I know this comes across rather mean, but this is just not a good resource, for either beginners (not very idiomatic) or experienced developers (trivial patterns with trivial examples). There's maybe 2 or 3 good ideas in there, but even those I might be hard pressed to find a real usecase for.
- htlion 4y agoI wholefully agree, the problem with this kind of repos is that Python already makes most patterns trivial. So you either create a trivial example that does not bring value or you introduce unnecessary abstractions for the sake of them. I am always looking into these repos though because I am still interested in learning new Python tricks. One of the repos that I found interesting recently is https://github.com/dry-python/returns https://github.com/dry-python/returns
- tonnydourado 4y agoI like the Maybe part, everything else feels like hitting my head against a wall, every time I try to understand it. But that's likely a me problem, I assume that for people more familiar with monads and all that jazz, it's easier to understand.
- d0mine 4y agoAll these lambdas seem excessive. "Maybe"-like pattern in Python can look like (None is falsy and custom objects are true): # note: `None and f()` returns None without calling f balance = user and user.get_balance() credit = balance and balance.credit_amount() discount_program = choose_discount(credit) if credit and credit > 0 else None https://stackoverflow.com/questions/8507200/maybe-kind-of-monad-in-python https://stackoverflow.com/questions/8507200/maybe-kind-of-mo...
- kortex 4y agoNullable (Optional[Foo] / Union[Foo, None]) and Maybe[Foo] are similar but not quite the same thing. The difference is quite subtle. Optional[Foo] is same as Foo | None, meaning you can operate on foo with Foo's methods, except that if it's None, you get NoneType errors. Maybe[Foo] is an actual container. You have to map over or unwrap it to operate on Foo. The big difference is ergonomics/opinion. You can't actually map over Optional, so every time you wanna use it, you have to manually check if foo is not None. Whereas Maybe, you can operate generically over it. Some folks think "is not None" is better. Personally I hate NoneType errors in prod and find that much more painful than a bit of indirection.
- d0mine 4y agoIt looks like a distinction without a difference. We can consider `None and f()` pattern as explicit syntax that unwraps objects as necessary without infecting other code. Background: an object that either None or true in a boolean context (true unless overriden for custom objects). Given such object, we can consider it in a virtual Maybe container/box. When we want to use it, we have to unwrap it using `obj and obj.method()` syntax. Then `obj.method()` is ordinary "unwrapped" call. Just to remind you. Here's how "ergonomic" Maybe variant from the article look like: # Type hint here is optional, it only helps the reader here: discount_program: Maybe['DiscountProgram'] = Maybe.from_optional( user, ).bind_optional( # This won't be called if `user is None` lambda real_user: real_user.get_balance(), ).bind_optional( # This won't be called if `real_user.get_balance()` is None lambda balance: balance.credit_amount(), ).bind_optional( # And so on! lambda credit: choose_discount(credit) if credit > 0 else None, ) https://github.com/dry-python/returns#maybe-container https://github.com/dry-python/returns#maybe-container You can decide for yourself what is more readable: all these lambdas or the `None and f()` code.
- kortex 4y agoThe dry-python lambda soup is awful, I totally agree there. That's just there mostly for demonstration purposes though. Generally you'd actually use the flow construct (monads) to compose methods. But `obj and obj.method()` really is not the same thing as `obj.map(method)`. "virtual Maybe container/box" is a nice idea, and does actually type-check with mypy (mostly), but you cannot actually compose it with other functions. The problem is, each time you do `obj and obj.method()`, you end up union-ing type(obj) and type(obj.method). https://mypy-play.net/?gist=5b03d81a64453997984e448df9b889e7 https://mypy-play.net/?gist=5b03d81a64453997984e448df9b889e7 main.py:40: note: Revealed type is "Union[__main__.User, None]" main.py:41: note: Revealed type is "Union[__main__.User, None, builtins.float]" main.py:42: note: Revealed type is "Union[__main__.User, None, builtins.float]" main.py:43: note: Revealed type is "Union[__main__.User, None, builtins.float, builtins.str]" True Maybe types are more precise. Maybe if the Mypy engine could be retooled to recognise the `obj and obj.method()` idiom as tantamount to `obj.map(method)`, this could be avoided.
- haolez 4y agoThe strategy pattern was really funny for me. I'd call it a different name: "code". :)
- emehex 4y ago> Define a family of algorithms, encapsulate each one, and make them interchangeable. You weren't kidding
- jghn 4y agoThere's a sentiment that design patterns are ways to make up for missing features in a language. I think that misses the forest for the trees as when people say that they almost always mean the GoF patterns, and not the concept of patterns in general. Strategy pattern is a great example. First class functions make the GoF pattern a moot point. But it's still useful to understand that this is a useful thing to want to do, whether or not one has direct language support.
- mumblemumble 4y agoI've come to think that that perspective unnecessarily conflates the design pattern with the strategy used to implement it. Things like the GoF model for how to implement Strategy are kind of a big deal in languages that lack first class functions. But there is also universal value in the basic idea of structuring your code so that you can inject behavior from outside. It's so valuable that many languages weave it into the very fabric of their design. FP fans fixating on the complexity of things like the GoF Strategy pattern and concluding that design patterns are just a band-aid over missing language features strikes me as being like fish noticing the inconvenience of humans needing plumbing and drinking vessels to get their water, and congratulating themselves for not needing water.
- jghn 4y agoThis is exactly what I'm saying. It's often true that for the specific GoF implementations they're often a band-aid. But what you said is also true, and much more important.
- Sohcahtoa82 4y ago> I recall it being even more java-like, so, progress? I'd consider Java-like being a regression, not progress. In my experience, most of the time when people complain about medium-large Python projects being difficult to reason about, it's because they wrote Java code in Python.
- tonnydourado 4y agoI meant that I recall this repository being even more Java-like, it has a couple more idiomatic examples now, hence, progress.
- aforwardslash 4y agoIn my experience, most Python projects are quite hard to scale or maintain precisely because they weren't written with a proper domain-specific approach. You'll be pressed to find a medium size python project that uses a database and doesn't use the leaky SqlAlchemy/Django ORM abstractions where data and operations on data are "the same thing"; On the same vein, any medium sized project with dozens of, hum, "models" will lead to files with thousands of lines. And don't even get me started on using an HTTP application instance as a container for configuration, usually included in every other piece of logic under the sun. You can easily guess I'm not a huge python fan (nor java, but it so happens I work daily in medium-sized projects in python), and I do have problems with the "idiomatic/pythonic way", but lets face it - python, while very expressive, is often so convoluted that static analysis of code isn't even possible. If your IDE is not able to quickly determine a given var type, you expect the average developer to be able to do it? Python is - first and foremost - a prototyping language, and an excellent choice for glue code. For big applications, you will actually learn to enjoy the bitterness and complexity of Java over python, and small stuff like strict typing.
- autoexec 4y ago>t this is just not a good resource, for either beginners (not very idiomatic) or experienced developers (trivial patterns with trivial examples) As someone with experience (just not in Python) I don't mind if the examples are basic, as long as they're idiomatic. I'd prefer a list of very common tasks/problems solved in a pythony way vs some examples of unique and clever uses of python.
- aforwardslash 4y agoIs there a difference between a "clever one-liner that doesnt replicate well" and idiomatic in python? Just because something is idiomatic it doesnt mean its a good approach, nor a good implementation.
- deckiedan 4y ago> Is there a difference between a "clever one-liner that doesnt replicate well" and idiomatic in python? 100% yes. Idiomatic would be (to me): 1. things which python does naturally - for instance list expressions rather than manual creation: managers = [ person for person in get_all_staff() if person.has_direct_reports() ] kind of thing, rather than: managers = [] for person in get_all_staff(): if person.has_direct_reports(): managers.append(person) So that's an 'idiom'. And a common one. 2. Things that Python makes natural / or less so - by the way it works. For instance, because of the important whitespace, and no end brackets or `end` keywords or whatever at the end of `if` or function definitions, large nesting inside functions becomes very klunky to follow the logic. So idiomatic would be to use small named functions, and split things into smaller pieces once they become too nested. 3. Common patterns that many people do, or common functions. See the itertools recipies, for instance: https://docs.python.org/3.5/library/itertools.html#itertools-recipes https://docs.python.org/3.5/library/itertools.html#itertools... Of course, one has to mention this: > >>> import this > The Zen of Python, by Tim Peters > > Beautiful is better than ugly. > Explicit is better than implicit. > Simple is better than complex. > Complex is better than complicated. > Flat is better than nested. > Sparse is better than dense. > Readability counts. > Special cases aren't special enough to break the rules. > Although practicality beats purity. > Errors should never pass silently. > Unless explicitly silenced. > In the face of ambiguity, refuse the temptation to guess. > There should be one-- and preferably only one --obvious way to do it. > Although that way may not be obvious at first unless you're Dutch. > Now is better than never. > Although never is often better than right now. > If the implementation is hard to explain, it's a bad idea. > If the implementation is easy to explain, it may be a good idea. > Namespaces are one honking great idea -- let's do more of those! So things like readability beats conciseness, so a huuuuge complex list expression is less pythonic than a manual loop when it becomes too complex.