DEV Community

Cover image for Write Unbreakable Python

Write Unbreakable Python

Jesse Warden on March 17, 2020

In this article, I’ll show you how to write Python with no runtime exceptions. This’ll get you partway to writing code that never breaks and mostly...
Collapse
 
sobolevn profile image
Nikita Sobolev • Edited

Thanks a lot for this article!

Consider using returns library. It has several most useful monads like Maybe, Result, IO, IOResult, Reader, and their combinations.

The main feature of this library is that it is fully typed with mypy. So, mypy will check that you are writing correct code before even running it.

We also have beginner-friendly docs, so it would easy to teach your team to use it.

GitHub logo dry-python / returns

Make your functions return something meaningful, typed, and safe!

Returns logo


Build Status Coverage Status Documentation Status Python Version wemake-python-styleguide Checked with mypy


Make your functions return something meaningful, typed, and safe!

Features

  • Provides a bunch of primitives to write declarative business logic
  • Enforces better architecture
  • Fully typed with annotations and checked with mypy, PEP561 compatible
  • Has a bunch of helpers for better composition
  • Pythonic and pleasant to write and to read 🐍
  • Support functions and coroutines, framework agnostic
  • Easy to start: has lots of docs, tests, and tutorials

Installation

pip install returns

You might also want to configure mypy correctly and install our plugin to fix this existing issue:

# In setup.cfg or mypy.ini:
[mypy]
plugins =
  returns.contrib.mypy.decorator_plugin

We also recommend to use the same mypy settings we use.

Make sure you know how to get started, check out our docs!

Contents

Collapse
 
jesterxl profile image
Jesse Warden

Dude, that library is awesome. The annotations + automatic lifting of types is great!
I'll never be a fan of Python's TypeScript/Java inline typing style, ML/Haskell made me a fan of their way, but overall, I'm loving what I'm seeing in returns, thanks a lot for the share.

Collapse
 
sobolevn profile image
Nikita Sobolev

Thanks! I am open for any feedback from your side.

Thread Thread
 
jesterxl profile image
Jesse Warden

Keep creating stuff like that? Save the planet?

Collapse
 
uweschmitt profile image
Uwe Schmitt

Nice work, but I would not consider a function which relies on a network connection to be pure. Same output for same input? Disconnect from the internet and the function will return a different result.

Collapse
 
jesterxl profile image
Jesse Warden

Yup. Once you get into Effects/Promises (or Python's awaitables), you start getting into what's really pure.

I call the function, I get back an awaitable, every time. Soo... it's pure.
... but, each of those effects is eager, and runs... so...it's not pure?
So if I start using the Effect pattern instead of Dependency Injection, and defer all actual awaitables from running, then I just get functions back. So...that's pure... until I run it.

At some point, you have to make a call:

  • I'm using DI, and will inject my dependencies, specifically the ones that actually do the side effects
  • I'm using the Effect pattern, and will defer all actual side effects until I call a run method
  • 90% of my code is pure, and the side effects are handled at some root level where we know the impurity badness exists

... otherwise, you'll have to either use a different programming language, or build a managed effect system like Elm has.

Collapse
 
uweschmitt profile image
Uwe Schmitt

So as soon as you have IO you will not get "purity" on a higher level.

I just found it a it a bit weird to explain functional concepts on an IO based example and readers who read about this the first time could be mislead about the concept of pure functions. The whole monads machinery in Haskell is to separate actions and pure functions and IO is the standard example for "non pure" actions which can not be expresses as pure functions.

Thread Thread
 
jesterxl profile image
Jesse Warden

Yeah, agree. The challenges I have with teaching Functional Programming:

  • many don't use it
  • many don't know it's a different "thing"
  • many are forced to use non-functional languages
  • most non-FP languages have no good way to handle side effects in a pure way
  • using FP could still help them in non-FP languages

That last point is what I'm trying to help people with. They don't need to be 100% pure to glean benefits of code that is more deterministic.

Even using the pain of Dependency Injection still massively benefits unit testing by removing their need of mocks. Stubs are big, no doubt, but Mocks are larger and harder to reason about.

Completely removing Exceptions allows all their functions to break more predictably in a very imperative way. Some people coding, or learning, still think and code in this way. Go's way of error handling is exactly this. We can give people the Algebraic Data Types of Result and Maybe, allow them to use those FP concepts, yet they still use them in an imperative way. So they don't have to change much about their style, yet they reap benefits.

Even something as simple as using PyDash over Python's native loops has huge determinism benefits.

Until managed effects like Elm has get ported to things like Python/Ruby/Lua, et. all, you basically have the same 3 choices:

  • give up and learn a pure FP language
  • use the Effect pattern
  • use DI

There IS hope, too, as I've seen some Effect style patterns implemented in JavaScript to make things like Promises (wanna be Monads) easier to use and not eager. People aren't going to leave Python. It's our job as FP lovers to help bring the awesome, and "make it work" in their world. I get being pragmatic technically breaks all the math... but I feel it's worth it.

Thread Thread
 
uweschmitt profile image
Uwe Schmitt

Hi, good point. What about summarising this as an extra paragraph, and also comment that the way you use "pure" might not be the exact definition?

Collapse
 
zeljkobekcic profile image
TheRealZeljko • Edited

Thank you for the article!

Got a question for you: Are you using PyMonad in production code? Or is anyone using it in production code?
If yes, how is your experience with it and how do other people react to it?
If no, why not?

Collapse
 
jesterxl profile image
Jesse Warden • Edited

No, but I bet many are.
My experience is positive (excluding Either name... )
Other people react to PyMonad the same way they react to FP: If they like FP, they love it. If they don't, they're like "No thanks, I'll go back to my OOP/Imperative."

Why not

... because I mainly put JavaScript in prod, not Python. The Python I did 4 years ago in prod, I didn't know PyMonad existed, just PyDash, heh!

Collapse
 
jcoelho profile image
José Coelho • Edited

Writing pure functions is not as simple as you make it be, otherwise we could write code without bugs.
For example your function ´get_last_name(object)´ which you claim to be pure, is actually not.
And it will fail very easily, if object is not of type Iterable.

Still I found this article very interesting and made me think a lot about how I code. Thanks ;)