Pragmatic Zen of Python

Shantanu C

19-08-2023

Created: 2023-08-19 Sat 09:04

Zen of Python

>>> 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!

Explicit is better than implicit.

What does this function do?

void fn(int *a, int *b) {
  int temp;
  temp = *a;
  *a = *b;
  *b = temp;
}

Supplementary questions:

  • How would you implement it without using a temp variable?
  • How would you implement it without using pointers?

Swapping values of variable in Python

a, b = b, a

That's not just succinct, it also:

Takes care of any _type of variable

This is how Python is introduced

These kind of small comparisons are often used to teach versatility of Python

What doesn't it tell?

This is objectively bad programming

You don't want to mix up variable names. Specially when they are of different _types.

In C or other statically typed languages, compiler is making sure that if you pass a variable that is not of type int, it will FAIL. In Python, good luck doing strict type checks.

Python has typing

It is called "type hints" and

Note: The Python runtime does not enforce function and variable type annotations.

Reference: Python Docs

Solutions

  1. mypy: optional static type checker for Python
  2. Pydantic: data validation library
  3. Ruff: Python linter

Handling Exceptions

In the face of ambiguity, refuse the temptation to guess.

Recommended approach of handling exceptions

Never do this

try:
    # logic
except Exception as e:
    pass

it is good practice to be as specific as possible with the types of exceptions that we intend to handle, and to allow any unexpected exceptions to propagate on.

Recommended approach of handling exceptions

Handle exception close to where they originate

Lets list all possible exceptions:

requests.get("https://raw.githubusercontent.com/pandas-dev/pandas/main/pandas/tests/io/data/csv/tips.csv")

try:
    response = requests.get(
        "https://raw.githubusercontent.com/pandas-dev/pandas/main/pandas/tests/io/data/csv/tips.csv",
        timeout=2,
    )
except (OSError, ConnectionError):
    print("Not able to connect to the remote server")
except requests.exceptions.HTTPError:
    print("Handle unsuccessful status code")
except TimeoutError:
    print("Handle unresponsive server")
else:
    print("Proceed with the logic of working with response")

Beware of Timeouts

If no timeout is specified explicitly, requests do not time out.

Errors should never pass silently.

Unless explicitly silenced.

What is the nature of assert statement?

Assert statements are a convenient way to insert debugging assertions into a program:

From Python 3 Documentation

What else can assert do?

An assertion is simply a statement that something must be true at a certain point in a program. When Python sees one, it evaluates the assertion’s condition. If it’s true, Python does nothing, but if it’s false, Python halts the program immediately and prints the error message if one is provided.

Can I use assertions for data validations?

NO

python -o

you shouldn’t use assertions for data processing or data validation, because you can disable assertions in your production code, which ends up removing all your assertion-based processing and validation code.

Lets look again at Python docs:

Assert statements are a convenient way to insert debugging assertions into a program:

debug is the keyword

Python interpreter can ignore your logic of using assert for data validation or processing.

How to do data validations?

  1. Use library specific solutions
  2. Avoid using assertions, conditional logic
  3. Pydantic also offers data validation

References

  1. Assertions in geo-python library
  2. Software Carpentry chapter on Defensive Programming
  3. Python Cookbook
  4. Requests Errors and Exceptions

Questions?