This makes functions like gettext_lazy, format_lazy and reverse_lazy a lot
slower than they ought to be.
Regressed in Django 1.8 (b4e76f30d12bfa8a53cc297c60055c6f4629cc4c).
Using this micro-benchmark on Python 3.7:
{{{#!python
import cProfile
from django.utils.functional import lazy
def identity(x): return x
lazy_identity = lazy(identity, int)
cProfile.run("for i in range(10000): str(lazy_identity(1))")
}}}
Before:
{{{
910049 function calls in 0.208 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.010 0.010 0.208 0.208 <string>:1(<module>)
10000 0.001 0.000 0.001 0.000 bench.py:4(identity)
10000 0.005 0.000 0.010 0.000 functional.py:105(__str__)
10000 0.004 0.000 0.188 0.000
functional.py:159(__wrapper__)
10000 0.007 0.000 0.185 0.000 functional.py:76(__init__)
10000 0.089 0.000 0.178 0.000
functional.py:83(__prepare_class__)
10000 0.004 0.000 0.005 0.000 functional.py:99(__cast)
1 0.000 0.000 0.208 0.208 {built-in method
builtins.exec}
840000 0.087 0.000 0.087 0.000 {built-in method
builtins.hasattr}
46 0.000 0.000 0.000 0.000 {built-in method
builtins.setattr}
1 0.000 0.000 0.000 0.000 {method 'disable' of
'_lsprof.Profiler' objects}
10000 0.002 0.000 0.002 0.000 {method 'mro' of 'type'
objects}
}}}
After:
{{{
50135 function calls in 0.025 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.008 0.008 0.025 0.025 <string>:1(<module>)
10000 0.001 0.000 0.001 0.000 bench.py:4(identity)
10000 0.005 0.000 0.009 0.000 functional.py:105(__str__)
10000 0.003 0.000 0.008 0.000
functional.py:159(__wrapper__)
10000 0.005 0.000 0.005 0.000 functional.py:76(__init__)
1 0.000 0.000 0.000 0.000
functional.py:83(__prepare_class__)
10000 0.004 0.000 0.005 0.000 functional.py:99(__cast)
1 0.000 0.000 0.025 0.025 {built-in method
builtins.exec}
84 0.000 0.000 0.000 0.000 {built-in method
builtins.hasattr}
46 0.000 0.000 0.000 0.000 {built-in method
builtins.setattr}
1 0.000 0.000 0.000 0.000 {method 'disable' of
'_lsprof.Profiler' objects}
1 0.000 0.000 0.000 0.000 {method 'mro' of 'type'
objects}
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30498>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* has_patch: 0 => 1
Comment:
PR: https://github.com/django/django/pull/11399
--
Ticket URL: <https://code.djangoproject.com/ticket/30498#comment:1>
* owner: nobody => Ran Benita
* status: new => assigned
* stage: Unreviewed => Accepted
Comment:
Thanks for the report! Reproduced at
888fdf182e164fa4b24aa82fa833c90a2b9bee7a.
--
Ticket URL: <https://code.djangoproject.com/ticket/30498#comment:2>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"a2c31e12da272acc76f3a3a0157fae9a7f6477ac" a2c31e12]:
{{{
#!CommitTicketReference repository=""
revision="a2c31e12da272acc76f3a3a0157fae9a7f6477ac"
Fixed #30498 -- Fixed proxy class caching in lazy().
lazy() should prepare the proxy class only once (the first time it's
used) not on every call.
Regression in b4e76f30d12bfa8a53cc297c60055c6f4629cc4c.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30498#comment:3>