Lazy filling func.__doc__ has only 3~5% performance gain. And it has small backward incompatibility.
```
>>> def foo(): "foo"
...
>>> def bar(): "bar"
...
>>> bar.__code__ = foo.__code__
>>> bar.__doc__
'foo' # was 'bar'
```
Note that non-constant docstring (and PEP 649 will) have larger overhead. Some people don't write docstring for private/local functions, but write annotation for code completion and/or type checking.
```
$ load-none-remove-docstring/release/bin/pyperf timeit --duplicate=100 "def f(x: int, y: str) -> float: pass"
.....................
Mean +- std dev: 111 ns +- 2 ns
$ load-none-remove-docstring/release/bin/pyperf timeit --duplicate=100 "def f(x, y): 'doc'"
.....................
Mean +- std dev: 63.9 ns +- 2.1 ns
```
So I think 2~3ns is a "tiny fraction" here. |