On 3 November 2017 at 03:00, Brett Cannon <br...@python.org> wrote: > The cost of constructing some of the objects used as type hints can be very > expensive and make importing really expensive (this has been pointed out by > Lukasz previously as well as Inada-san). By making Python itself not have to > construct objects from e.g. the 'typing' module at runtime, you then don't > pay a runtime penalty for something you're almost never going to use at > runtime anyway.
Another point worth noting is that merely importing the typing module is expensive: $ python -m perf timeit -s "from importlib import reload; import typing" "reload(typing)" ..................... Mean +- std dev: 10.6 ms +- 0.6 ms 10 ms is a *big* chunk out of a CLI application's startup time budget. So I think to be truly effective in achieving its goals, the PEP will also need to promote TYPE_CHECKING to a builtin, such that folks can write: from __future__ import lazy_annotations # More self-explanatory name if TYPE_CHECKING: import typing and be able to express their type annotations in a way that a static type checker will understand, while incurring near-zero runtime overhead. [snip] Regarding the thunk idea: the compiler can pretty easily rewrite all annotations from being "<expr>" to "lambda: <expr>". This has a couple of very nice properties: * rendering them later is purely a matter of calling them, since the compiler will take care of capturing all the right namespaces and name references (including references from method declarations to the type defining them) * quoted and unquoted annotations will reliably render differently (since one will return a string when called, and the other won't) The big downside to this approach is that it makes simple annotations *more* expensive rather than less expensive. Baseline (mentioning a builtin): $ python -m perf timeit "str" ..................... Mean +- std dev: 27.1 ns +- 1.4 ns String constant (~4x speedup): $ python -m perf timeit "'str'" ..................... Mean +- std dev: 7.84 ns +- 0.22 ns Lambda expression (~2x slowdown): $ python -m perf timeit "lambda: str" ..................... Mean +- std dev: 62.3 ns +- 1.4 ns That said, I'll also point out the following: * for application startup purposes, if you save 10 ms by not importing the typing module, then that buys you time for around 285 *thousand* implicit lambda declarations before your startup actually gets slower (assuming the relative timings on my machine are typical) * for nested functions, the overhead of the function call is enough that the dramatic 4x speedup vs 2x slowdown ratio disappears (see P.S. for numbers) * I don't believe we've really invested much time in optimising the creation of zero-argument lambdas yet, so there may be options for bringing the numbers down for the lambda based approach The other key downside to the lambda based approach is that it hits the same backwards compatibility problem we hit when list comprehensions were given their own nested scope: if we push annotations down into a new scope, they won't be able to see class level attributes any more. For comprehensions, we could partially mitigate that by evaluating the outermost iterable expression in the class scope, but there's no equivalent to that available for annotations (since the annotation's lambda expression may never be called at all). Cheers, Nick. P.S. Relative performance of the annotation styles in a nested function definition Baseline: $ python -m perf timeit -s "def f(): str" "f()" ..................... Mean +- std dev: 103 ns +- 3 ns String constant (~1.25x speedup): $ python -m perf timeit -s "def f(): 'str'" "f()" ..................... Mean +- std dev: 77.0 ns +- 1.7 ns Lambda expression (~1.5x slowdown): $ python -m perf timeit -s "def f(): (lambda: str)" "f()" ..................... Mean +- std dev: 149 ns +- 6 ns -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com