Intro

First things first, actually I don’t want to remove them at all, I just want to get rid of them forever from my workflow. We will see that later.

This is a compherensive guide to deal with Python’s __pycache__ directories and .pyc files.

__pycache__ is a directory which is containing Python 3 bytecode compiled and ready to be executed.

From the official python tutorial Modules:

To speed up loading modules, Python caches the compiled version of each module in the pycache directory under the name module.version.pyc, where the version encodes the format of the compiled file; it generally contains the Python version number. For example, in CPython release 3.6 the compiled version of spam.py would be cached as pycache/spam.cpython-36.pyc.

From Python doc Programming FAQs:

When a module is imported for the first time (or when the source file has changed since the current compiled file was created) a .pyc file containing the compiled code should be created in a pycache subdirectory of the directory containing the .py file. The .pyc file will have a filename that starts with the same name as the .py file, and ends with .pyc, with a middle component that depends on the particular python binary that created it.

So they are necessary and should not be deleted usually.

Solution - Default

There are a lot elements to “remove” __pycache__ directories and .pyc files.

Git

The first and foremost thing is that we need to do ignoring them in our project’s git trees. Add them into our .gitignore file(s), locally and/or globally.

# .gitignore

# Pyhon byte-compiled / optimized files
__pycache__/
*.py[cod]
*$py.class

Editor

However this is not enough, even though we already added them into .gitignore file(s), we will still see them in our IDEs and explorers. In order to prevent that I use below configurations per editor.

VSCode

// settings.json

"files.exclude": {
     "**/__pycache__": true
}

Neovim

For nvim-tree plugin:

-- init.vim or init.lua or nvimtree.lua

local nt = lvim.builtin.nvimtree

-- Ingore/Exclude directories/files patterns
nt.setup.filters.custom = {
    "__pycache__",
}

Vim

For NERDTree plugin:

" .vimrc or nerdtree.vim

" NERDTree Plugin"

" Ingore/Exclude directories/files patterns
let NERDTreeIgnore = [
            \ '\.pyc$',
            \ '^__pycache__$',
            \]

Docker

There is a environment variable which is responsible to disable to write .pyc files named PYTHONDONTWRITEBYTECODE.

# Dockerfile

ENV PYTHONDONTWRITEBYTECODE 1

From Python’s official doc bytecode:

PYTHONDONTWRITEBYTECODE

If this is set to a non-empty string, Python won’t try to write .pyc files on the import of source modules. This is equivalent to specifying the -B option.

It’s not usually an optimum solution to set this variable in other than containers. Since you run a single python process in containers, which does not spawn other python processes during its lifetime, then there is no disadvantages in doing that.

Delete

After all of the above, we may still encounter some cases to delete all of __pycache__ directories. Here is the shell command to remove them:

In the root of your project run:

$ find . | grep -E "(/__pycache__$|\.pyc$|\.pyo$)" | xargs rm -rf

Warning

Before running above delete command test it running without xargs rm -rf -the remove part. This will simply list them:

$ find . | grep -E "(/__pycache__$|\.pyc$|\.pyo$)"

You can add this command as an alias for easy access:

alias rm-pycache='find . | grep -E "(/__pycache__$|\.pyc$|\.pyo$)" | xargs rm -rf'

Also you would like to add it as a make targets in your project’s Makefile for ci/cd pipelines.

rm-pycache:
    find . | grep -E "(/__pycache__$|\.pyc$|\.pyo$)" | xargs rm -rf

Lastly there is a python library just for this delete cause: pyclean. In my opinion it’s an overkill but you may take a look.

Solution - New

This is my current solution about the issue.

Beginning from Python 3.8 you can use PYTHONPYCACHEPREFIX environment variable to use a global cache directory to avoid them created under your projects:

$ export PYTHONPYCACHEPREFIX="$HOME/.cache/cpython/"

By this environment variable Python won’t create any __pycache__ directory in your projects, instead it will put all of them under ~/.cache/cpython/ directory.

From Python’s official doc prefix:

PYTHONPYCACHEPREFIX

If this is set, Python will write .pyc files in a mirror directory tree at this path, instead of in pycache directories within the source tree. This is equivalent to specifying the -X pycache_prefix=PATH option.

New in version 3.8.

You can add this environment variable in one of the configuration file of yours: .zshrc, .zshenv, .bashrc, .bash_profile, .profile, .zprofile etc.

At last they are out of my sight.

All done!