6 ms·
Make your Python functions return something meaningful, typed, and safe
- dr_kiszonka 4y agoI particularly like this bit: from returns.result import Result, Success, Failure def find_user(user_id: int) -> Result['User', str]: user = User.objects.filter(id=user_id) if user.exists(): return Success(user[0]) return Failure('User was not found') user_search_result = find_user(1) # => Success(User{id: 1, ...}) user_search_result = find_user(0) # id 0 does not exist! # => Failure('User was not found') https://returns.readthedocs.io/en/latest/pages/result.html https://returns.readthedocs.io/en/latest/pages/result.html
- pharmakom 4y agoPython is deeply incompatible with this style. No do-notation, crippled lambdas, slow function calls. If you want to write Rust/OCaml maybe use Rust or OCaml?
- intelVISA 4y agoHow am I going to PIP all those CVEs with dune/cargo?!
- baq 4y agoCurrent Python is. Languages evolve. Nothing wrong in importing good ideas from other languages, bonus points if long standing warts get fixed at the same time.
- Kwpolska 4y agoI don't think Python is ever going to get multi-line/fully-featured/less-ugly lambdas.
- dragonwriter 4y agoVery many languages only have single-expression lambdas, Python isn’t unusual in that, its just that nontrivial single expressions in Python are extremely ugly (to the point where most people think they are much more limited than they are.) The lambda issue in Python isn’t really about lambdas, but the readability and expressiveness of expressions.
- pharmakom 4y agoPython would be so much better if it was expression orientated. I don’t think it would even detract from Pythons design goals at all.
- dragonwriter 4y agoI agree, but given the Zen and the disruption when print moved to a function from a statement, I don’t see a good evolution path to get much closer. OTOH, small improvements in what can cleanly be expressed in an expression could still have big payoffs for Python.
- erik_seaberg 4y agoImporting from __future__ worked well to make language changes opt-in. It was a mistake to start breaking backward compatibility by default.
- Kwpolska 4y ago> Very many languages only have single-expression lambdas Which languages are those? Java, C#, C++, Rust, JS, Swift, Kotlin, Scala, Ruby, PHP, and Go all allow defining multi-line anonymous functions that can contain any statement normally allowed in a function.
- datadeft 4y agoIt was not designed to those things and there are many other languages that are way better in many aspects of software engineering than Python ever will be with type checks and other relatively minor improvements. I consider Python as the lingua francua that gets the job done, easy to train new programmers to use it and there are several C/C++/Fortran/Rust libraries written so it can do things performant enough to be relevant. There was nothing new introduced by Python that other languages took from it which shows that there is nothing groundbreaking about it. I think Python is the quick and dirty, not too smart glue languages with a mediocre module system and many footguns. I think Sussman pointed out that the world needs more library gluers than it needs very smart software engineer who create those libraries. Python is the proof of this theory.
- pphysch 4y ago> There was nothing new introduced by Python that other languages took from it which shows that there is nothing groundbreaking about it. Not strictly true, Python's approach to readability (syntax) inspired languages like Kotlin, GDScript, to name a couple. But the bigger picture is that Python has spawned prominent frameworks/DSLs in virtually every domain, so to suggest that it is a dead-end of innovation is not quite correct.
- _a_a_a_ 4y agoseems you can now sort of write Scala in Python
- esafak 4y agoThe language that's winning by setting an example. edit: I like Scala. Being emulated is a compliment. Come on guys, no need to throw a fit!
- adamckay 4y agoI really don't. Raise a `NotFound` exception in the method and catch that instead when you're calling...
- Hasnep 4y agoI prefer having failures in the type signature so the type checker makes sure they're handled, although it depends on the failure, occasionally I just raise an error like you suggest.
- chrisshroba 4y agoI too wish Python was more like Rust :)
- tmtvl 4y agoJust use SML (Standard ML)?
- tremon 4y agoIs it just me or do more people find that Python is becoming more and more illegible with these type annotations? I understand why they are introduced, but to me they cause a lot of line noise in the relatively clean signal that is Python code. To add insult to injury, type hints are not enforced nor even verified by the runtime. I find that if I want type safety, I'd rather branch out to other languages that were designed for it from the start. In particular, I find that rewriting some of my Python modules in Rust is a joy (using PyO3, but keenly following RustPython development too).
- kingofthehill98 4y agoI tend to agree, Python really shines when it's just being Python. I only typehint certain parts of the code where i find it usefull. Typehinting everything makes Python code really hard to read IMO.
- theLiminator 4y agoDefinitely disagree, especially not the case for function arguments. Having no types in the arguments makes an api incredibly hard to use.
- alanwreath 4y agoYou can slap out the POC without types for sure - but the addition of types helps - tests fail faster - code documentation - IDE’s complain better - teams collaborate better It becomes more helpful as projects and teams mature. I’d say that types aren’t the last step though, I’m starting to prefer protocols and those are proving to be even more loosely coupled and more pythonic to me. They let you “type” the behavior rather than the actual type. Say there is a case when you don’t care if it’s a set, tuple, or a list because all you’re going to do is Iterate, we’ll you’d go the behavior route and say you want an Iterator. You can create your own protocols as well and it has the effect that you document what you intend to do with the objects passed to you such that it doesn’t matter what you pass as long as it adheres to the protocol you defined. It’s documented duck typing. Here’s a great video that explains how it can simplify your code https://m.youtube.com/watch?v=xvb5hGLoK0A https://m.youtube.com/watch?v=xvb5hGLoK0A
- 63stack 4y agoI see the point in the maybe type, but trying to introduce that into a language that only allows 1 single expression in anonymous functions has to be one of the most unergonomic things I can imagine.
- maxwelljoslyn 4y agoAgreed. Can't count the num of times I've wished Python had real lambdas.
- deleted 4y ago[deleted]
- quietbritishjim 4y agodiscount_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(), ) Ugh. I don't care that this is shorter – just use a bloody if statement! Yes, even if you have to nest them sometimes (not nearly as often as this page suggests in my experience).
- greenfield1 4y agoYes, it's not pythonic. But the Maybe monad does have its beauty, which the in-built Optional doesn't really provide. If this package makes people more accepting, then let them.
- skykooler 4y agoThis feels like trying to write Haskell code in Python. If that’s how you want to code, why not just write it in Haskell?
- greenfield1 4y agoJust because somebody mentioned the term "monad" doesn't mean that suddenly the code should be written in Haskell. Python allows recursion too. Are you using recursion? Why not just write it in Haskell? Python allows function calls too. Are you using function calls? Why not just write it in a functional language like Haskell? A monad is just a general programming concept, like recursion and function calls. One particular language pioneering the concept's heavy use doesn't mean other languages can't adapt it. To the contrary, languages get influences from one another all the time. Especially Python. Do you like list comprehensions? This super-pythonic thing? Goes back to functional languages in the 70s and the name was coined by Philip Wadler, one of the main Haskell gurus. If you like list comprehensions, this feels like trying to write Haskell code in Python. Why not just write it in Haskell?
- sdfghswe 4y agoDesigning for beauty is a mistake that people keep pointing out and people keep making. Good software isn't art.
- theusus 4y agoHow about using match in Python?
- iknownothow 4y agoNo thanks. Here's why I dislike it. There's a lot of libraries out there in Python that appear to be DSLs or have custom syntaxes that heavily use decorators etc e.g. Flask or FastAPI. In exchange for learning these custom syntaxes they offer tangible value in terms of eliminating boilerplate or solving a particular use case really well. In case of Flask or FastAPI, they make writing http/rest servers a piece of cake. This library however offers not much benefit over the following example from Effective Python and in return I have to learn a whole new Python. def add_ints(a, b) -> Tuple[str, bool]: if isinstance(a, int) and isinstance(b, int): return a + b, True else: return None, False result, status = add_ints(1, 1) Basically it's is a lot of syntactic noise for very little.
- bb88 4y agoI don't even like that, since raising TypeError("args are not integers") would be easily more appropriate here, and arguably more pythonic.
- thebigspacefuck 4y agoIn your example it should be def add_ints(a: int, b: int) -> Tuple[int | None, bool]. I’m not a fan of the Tuple return type. This is how golang does things and while it works there I don’t like seeing this in Python code because the Tuple tells you nothing unless you follow this convention and you have to add the Tuple annotation on top of every return type making it harder to read. I don’t see a need for it here since you’re already returning an Optional[int] (int | None in Python 3.10+). You could also raise a TypeError. Also your type checker should catch this if a or b are not an int, so you might feel safe returning a+b at this point and having the return type be simply int.
- AlexandrB 4y agoTo me this seems like a solution in search of a problem. Checking for "None" is not that bad and doesn't require nested "if" statements if you apply this pattern instead: if user is None: return balance = user.get_balance() if balance is None: return credit = balance.credit_amount() # etc... Mypy also correctly detects that user/balance/etc. can't be null after each check. Of course it's better to design functions/methods that never return "None", but that's not always an option. This approach also has the advantage that you can easily log at what stage the sequence of method calls failed. Stuffing this into a bunch of lambdas makes that much harder.
- pphysch 4y agoImperative styles like yours are readable, and more importantly, hackable. Business processes are rarely set in stone and the above code can be easily modified, as opposed to a "beautiful" "pure" "correct" ball of functional yarn that must be carefully unwound and rearchitected.
- _v7gu 4y agoYea, because the following equivalent piece of code is much more difficult to read without returns after every statement user |> mmap(get_balance) |> mmap(get_credit_amount)
- PaulHoule 4y agoMaybe, exception wrappers, …. Nein Danke!
- FreakLegion 4y agoI see a few alternatives for the first example here already, but none that take advantage of the walrus operator: # Assuming credit can't be negative. if user and (balance := user.get_balance()) and (credit := balance.credit_amount()): discount_program = choose_discount(credit)
- cirrus3 4y agoThis seems like something that the language itself should provide, or not. I would not add a third party dependency to give me these functional programming features and then write a bunch of code tied to it. All these concepts are great and I use them all the time... but just not in Python. Every language has tradeoffs in terms of features, available libraries, existing codebases you need to work within, etc. Python has a tradeoff of not having these functional features. I appreciate the huge amount of effort this must have been, but these types of projects don't usually work out or stick.
- VulgarExigency 4y agoWhy not use a a typed language instead?