-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
Speed up importing typing just for TYPE_CHECKING
#132049
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
This makes importing anything else from typing slower, and it likely breaks |
|
It also means the A |
By the cost of a string comparison, a lookup for Before: After: While the numbers are certainly measurably different:
Which would likely be fixed by defining |
|
Can you test with This is a (rough) script I use to benchmark import time measurements: import subprocess, sys
import statistics
BASE_CMD = (sys.executable, '-Ximporttime', '-S', '-c',)
def run_importtime(mod: str) -> str:
return subprocess.run(BASE_CMD + (f'import {mod}',), check=True, capture_output=True, encoding='utf-8').stderr
for mod in sys.argv[1:]:
for _ in range(5): # warmup
lines = run_importtime(mod)
print(lines.partition('\n')[0])
own_times = []
cum_times = []
for _ in range(50):
lines = run_importtime(mod)
final_line = lines.rstrip().rpartition('\n')[-1]
# print(final_line)
# import time: {own} | {cum} | {mod}
own, cum = map(int, final_line.split()[2:5:2])
own_times.append(own)
cum_times.append(cum)
own_times.sort()
cum_times.sort()
own_times[:] = own_times[10:-10]
cum_times[:] = cum_times[10:-10]
for label, times in [('own', own_times), ('cumulative', cum_times)]:
print()
print(f'import {mod}: {label} time')
print(f'mean: {statistics.mean(times):.3f} µs')
print(f'median: {statistics.median(times):.3f} µs')
print(f'stdev: {statistics.stdev(times):.3f}')
print('min:', min(times))
print('max:', max(times)) |
(For my own edification, sorry for the noise) "the cache" here is a combo of If so, IIUC I think the numbers are precisely showing us that this change as it stands has a small-but-measurable penalty precisely because we don't use the (latter) cache. I'd venture to guess |
|
Changing the code to: import sys
__mod__ = sys.modules[__name__]
def __getattr__(name):
if name == "TYPE_CHECKING":
return False
import _typing
attr = getattr(_typing, name)
__mod__.__dict__[name] = attr
return attrbrings it down to |
(Somewhat demonstrative PR, but happy to give it the rest of "the treatment" (e.g. tests, documentation, etc...) if it seems OK)
Made in the context of https://discuss.python.org/t/pep-781-make-type-checking-a-built-in-constant/85728/122
I also think
_typing.pylikely is a bad name (undoubtedly going to collide with some user's usage of_typing.py) so happy to bikeshed on alternate names.On a fresh Ubuntu VM, I installed
uv, thenuv install 3.14) :Interpreter baseline:
Importing
typingforTYPE_CHECKINGAfter this change: