Python

Summary

Main page for all things Python. Other pages cover specific topics, such as:

Installation

Anaconda

An option to install Python is to use Anaconda1. Download the appropriate installation file from https://www.anaconda.com/products/individual. And then run the installer with, e.g., sh ./Anaconda3-2021.11-Linux-x86_64.sh. The installation would typically be under $HOME/anaconda3. There is a page dedicated to configuring and using [Anaconda].

Language changes

In 2021, the Python steering council accepted the proposal to add a pattern-matching primitive to the language. The proposal consists of PEP634 along with PEP635 and PEP636.

pip

No binary install

To install a package from source with pip specify

pip install --no-binary $PACKAGE

Since requirements files are passed as command-line options to pip, you can also specify it as

some-package
--no-binary
another-package

Additionaly this will also work on setup.py’s install_requires. For instance:

setup(
    install_requires=[
        "some-package==0.0.1 --no-binary"
])

Modules

Problems

Missing __init__.py

In versions of Python before 3.3, an __init__.py file was mandatory in order for the interpreter to treat a directory, whether on the filesystem or inside a zipfile, as a Python package directory. This file served as a marker, indicating the presence of importable modules or subpackages, even if it was completely empty and didn’t actually run any code during the package import process.

Starting with Python 3.3, this requirement was relaxed. The interpreter now recognizes any directory on sys.path whose name matches the desired package name as a valid package, regardless of the presence of an __init__.py file. The directory’s modules and subpackages are treated as part of the package namespace.

To illustrate this difference, let’s look at a simple project structure:

project/
    example/
        foo.py

Assume that foo.py has the following content:

print("Hello from ", __name__)

Now, if we set project as the current working directory and try to import example.foo using Python 2.7, we’ll encounter an error:

$ python2 -c "import example.foo" 
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named example.foo

However, Python 3.3 and later versions can import the submodule seamlessly:

$ python3 -c "import example.foo"
Hello from  example.foo

Relative import in Python 3

If a relative import is present inside a Python 3 file (e.g. file1) inside a module (e.g. mymod), say

from .foo import bar   

We will encounter the error

ImportError: attempted relative import with no known parent package

A possible solution is to include the following in your module’s __init__.py:

import os, sys

sys.path.append(os.path.dirname(os.path.realpath(__file__)))

Operators

Ternary operator

Ternary operators help reduce the amount of very small if-else blocks. Python does not have a ternary operator like other languages. However, conditionals can be used to the same effect:

y = 7
x = 0 if (y == 1) else 1
print(x)
1

for … else

for-else blocks allow to capture if a condition was met inside a for-loop. For instance, consider the following for-loop:

locations = ['a', 'b', 'c', 'd', 'f']
treasure = False
for location in locations:
   if location == 'x':
       treasure = True
       break
if not treasure:
   print("X marks the spot, but not found")
X marks the spot, but not found

We can simplify the above logic using a for-else loop:

for location in locations:
   if location == 'x':
       break
else:
   print("X marks the spot, but not found")
X marks the spot, but not found

Boolean unravelling

and

unravelling the and boolean operator. The operation can be rewritten as the function u_and:

def u_and(a, b):
   result = a
   if a:
      result = b
   return result

For instance:

a = True ; b = None
print(a and b, u_and(a, b))
a = True ; b = True
print(a and b, u_and(a, b))
a = False ; b = True
print(a and b, u_and(a, b))
None None
True True
False False

or

On the other hand, or cand be unravelled as:

def u_or(a, b):
   result = a
   if not a:
      result = b
   return result

As an example:

a = True ; b = None
print(a or b, u_or(a, b))
a = True ; b = True
print(a or b, u_or(a, b))
a = False ; b = True
print(a or b, u_or(a, b))
True True
True True
True True

The many faces of print

Concatenating arguments

var1 = "Foo"
var2 = "Bar"
print("I am ", var1, " not ", var2)
I am  Foo  not  Bar

It is also possible to use separators by using the sep argument:

var1 = "Foo"
var2 = "Bar"
print("I am", var1, "not", var2, sep="!")
I am!Foo!not!Bar

String termination

The end argument allows to specify the suffix of the whole string.

print("This is on radio", end=" (over)")
This is on radio (over)

Filesystem operations

Get home directory

For Python +3.5:

from pathlib import Path

home = str(Path.home())
print(home)
/Users/rui

List files recursively

For Python +3.5, use glob:

import glob

# root_dir with trailing slash (i.e. /root/dir/)
root_dir = "./"
for filename in glob.iglob(root_dir + '**/*.md', recursive=True):
     print(filename[:-3])
./Python
./Python code style
./Python Abstract classes
./New Features in Python 3.9
./Understanding Decorators in Python

Date operations

Offset-aware operations

Let’s say you have a date without timezone (offset naive), for instance:

from datetime import datetime, timezone

ts = datetime.now().replace(tzinfo=None)
print(ts)
2022-08-07 14:08:13.498348

And you want to calculate the $\delta$ with a datetime which has a time (offset aware). We’ll get an error.

try:
   delta = datetime.now(timezone.utc) - ts
except TypeError as error:
   print(error)
can't subtract offset-naive and offset-aware datetimes

The solution is to add a timezone to the offset naive date. For instance:

ts = datetime.now(timezone.utc)

delta = datetime.now(timezone.utc) - ts
delta
datetime.timedelta(microseconds=55)

Strings

Packaging

PyOxidizer

An alternative to package Python applications is PyOxidizer.

PyOxidizer is often used to generate binaries embedding a Python interpreter and a custom Python application. However, its configuration files support additional functionality, such as the ability to produce Windows