Search code examples
pythondjangopython-3.8python-3.9

What is the difference between cached_property in Django vs. Python's functools?


Django has a decorator called cached_property which can be imported from django.utils.functional. On the other hand, Python 3.8 added cached_property to the standard library which can be imported from functools.

Are both equivalent, i.e., are they interchangeable? or what is the difference between both? Are there any best practices when to use one or the other?


Solution

  • After some research both basically work the same way and the only difference you would see would be in the error handling and performance. There is a ticket #30949 on Django's issue tracker to use functools.cached_property instead of django.utils.functional.cached_property.

    You can see the source code [GitHub] for functools.cached_property and also for django's version [GitHub]. The basic difference is functool's version does a little bit more error handling and the main difference is that functool (pre Python 3.12) uses locking mechanism for thread safety, this causes a performance dip compared to Django's version. From some benchmarking done in the ticket linked above it seems Django's version is much more efficient in terms of performance:

    % python benchmark.py
    .....................
    Django Cache: Mean +- std dev: 12.8 ms +- 0.2 ms
    .....................
    Python Cache: Mean +- std dev: 113 ms +- 2 ms
    

    There is also an issue 43468 on Python's bug tracker regarding this. Note that this locking behavior is removed in Python version 3.12 onwards and the performance should be mostly similar now.

    In summary if you are using Python 3.12+ prefer functools version otherwise use Django's version if thread safety is not an issue otherwise you might want to use the functools version.