Use lazy imports on Python 3.15 to improve startup speed - #9733
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
|
I think the import should also belong in |
|
It's certainly a bigger and unrelated change, but looks like |
|
I made the olefile import eager again: it's an optional dependency and lazy imports affect how its related plugins get registered. I'll have a look at logging. Unfortunately it's not straightforward to
|
|
@hugovk That'd work -- but I'm also thinking... do we need the 4 |
|
@radarhere Do you think we should keep those four log lines? |
|
I'm inclined not to. The debug message before the import seems unnecessary, as 99% of the time, the import will succeed, and it's not part of an overall consistent use of As for the one on error… I'm not sure under what circumstances it would run for any of our internal plugins. From a big picture perspective though, PIL |
|
|
||
| import re | ||
|
|
||
| from . import Image, ImageFile, ImagePalette |
There was a problem hiding this comment.
Am I correct in thinking that's there no particular reason why _binary should be lazy, but ImagePalette, isn't? I'm guessing you ran some performance tests, figured out which modules to import lazily based on that, and then applied that list throughout src?
There was a problem hiding this comment.
Am I correct in thinking that's there no particular reason why
_binaryshould be lazy, butImagePalette, isn't?
With from ._binary import o8, the module being imported is PIL._binary.
With from . import ImagePalette, the module being imported is the PIL package.
I'm guessing you ran some performance tests, figured out which modules to import lazily based on that, and then applied that list throughout src?
I used https://github.com/henryiii/flake8-lazy and ran something like flake8-lazy src/PIL --apply set (set being faster than list: henryiii/flake8-lazy#50).
Although that does spells it like:
__lazy_modules__ = {f"{__spec__.parent}._binary"}See henryiii/flake8-lazy#41 for the explanation. I decided to replace the f-strings in this PR.
But perhaps we should go for the f-strings and add flake8-lazy to pre-commit? (There's no Ruff rule yet.)
|
Updated: re-ran |







Re: #9330
Defer
The first commit here defers the import of
tempfilein four files to the place where it's actually used, so we don't need to pay the import time if we're not using it. This helps for all Python versions.So for example, only importing
PIL.Imageon Python 3.14:Lazy
Python 3.15 introduces lazy imports:
If you put the new
lazykeyword before an import, it won't be actually imported until first use. Butlazyis only for 3.15+, it's a syntax error in 3.10-3.14.So the second commit introduces
__lazy_modules__.We can only put top-level imports here, and not those from function or in
try/except. And we don't need to put any that used right away at the top-level, likelogginginImage.py, but it's not a big deal if we do.Repeating with 3.15: