11% of Python files are not closed! Affecting Google, Python.org, Ansible, Tensorflow ...
Tags: python, codequality, programming, webdev
Published: 2022-01-31 20:30:51

It’s a problem that 11% of files are not closed properly as leaving files open degrades application performance and increases the risk of unexpected side effects.

It's not just a mistake that rookies make. Many of the offenders are big names:

- [python.org](https://github.com/python/pythondotorg/blob/4ad9d4083290cb063d074a02e41cf9ef6e0e0c73/pages/parser.py#L18)
- [Google](https://github.com/googleapis/google-api-python-client/blob/4e0aa62ae80e56036d9a3435d15b7263575b3609/samples/compute/create_instance.py#L48)
- [Ansible](https://github.com/ansible/ansible/blob/bc5672d9ba2d30f8f96e135079f412659350c574/lib/ansible/modules/service.py#L1381)
- [Tensorflow](https://github.com/tensorflow/tensorflow/blob/ad77ca7d07ee05d9f656edcf082d39d4bbd78114/tensorflow/lite/experimental/acceleration/mini_benchmark/metrics/blazeface_metrics.py#L115)	

Those are just 4 of the >500 examples we found in the 5409 `open(…)` calls we analyzed over 666 repositories.

How did we find this statistic? At [CodeReview.doctor](CodeReview.doctor) we run static analysis checks on codebases, and we collect stats on the public repos. We tracked every line we could find where developers opened files via `open(...)` but never closed them and compared that with every line we could find where developers "did it right” (either explicitly calling `close()` or implicitly via context manager usage).

At the end of this article is a link and embed of the stats.

### The problem

To recap: leaving files open results in degradation of application performance and increases the risk of unexpected side effects.

Computers have finite resources, including limits on how many files can be simultaneously open. Therefore leaving files open consumes more finite file handles than necessary. Under extreme conditions this could exhaust the number of allowed open files causing an “IOError: Too many open files" exception to be raised. Additionally, leaving files open consumes finite memory for longer than is necessary. Therefore for performance of the application it is preferable to closing file after finished with them.

Python’s [garbage collection](https://stackify.com/python-garbage-collection/) will eventually close dangling unclosed files, but "eventually" should raise a red flag if the goal is to write predictable software. Indeed, Python3 and Cpython might implicitly close the file the instant they’re no longer being used, while others might not for a long time. Under some conditions it might not happen at all. When pairing this problem with the zen of Python's _Explicit is better than implicit_, it’s clear that it’s better to not leave files open.

Python can also be fuzzy around exactly when file changes are committed to disk: the data may not be written to disk until the file is closed:

```py
# bad: maybe not written to disk yet as the file was not closed
open('foo.txt', 'w').write('foo')
# also bad: maybe not written to disk as the file was not closed
f = open('bar.txt', 'w')
f.write('bar')
# better: written to disk when the file closed
f = open('baz.txt', 'w')
f.write('baz')
f.close()
# good: written to disk when the file closed and code is neater
with open('qux.txt', 'w') as f:
    f.write('qux')
```

Windows (the Operating System) locks files opened by Python. This could mean leaving files open is not thread safe as one thread will lock the file preventing other threads from opening it — even if the other thread just wants to read from it.
That’s why we give this advice:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nxk6jdkhi9k40l05wmeu.png)
 

### The stats
[Here’s](https://gist.github.com/code-review-doctor/6d2ff4ab5cd29c387c14596a7ee7d92a) a link to the 4812 examples of "doing it right": all the files were closed either by explicitly calling `close()` or by opening the file using the context manager approach.

[Here's](https://gist.github.com/code-review-doctor/526e267138b79e16069def68d2bb5422) a link to the 597 examples of not “doing it right”: the files were opened and read from but never closed.

### Check your repo

Check your repo for tech debt like this at [codereview.doctor](codereview.doctor), or even [review your GitHub PRs](https://github.com/marketplace/django-doctor/).