The very first time you import goo
from anywhere (inside or outside a function), goo.py
(or other importable form) is loaded and sys.modules['goo']
is set to the module object thus built. Any future import within the same run of the program (again, whether inside or outside a function) just look up sys.modules['goo']
and bind it to barename goo
in the appropriate scope. The dict lookup and name binding are very fast operations.
Assuming the very first import
gets totally amortized over the program's run anyway, having the "appropriate scope" be module-level means each use of goo.this
, goo.that
, etc, is two dict lookups -- one for goo
and one for the attribute name. Having it be "function level" pays one extra local-variable setting per run of the function (even faster than the dictionary lookup part!) but saves one dict lookup (exchanging it for a local-variable lookup, blazingly fast) for each goo.this
(etc) access, basically halving the time such lookups take.
We're talking about a few nanoseconds one way or another, so it's hardly a worthwhile optimization. The one potentially substantial advantage of having the import
within a function is when that function may well not be needed at all in a given run of the program, e.g., that function deals with errors, anomalies, and rare situations in general; if that's the case, any run that does not need the functionality will not even perform the import (and that's a saving of microseconds, not just nanoseconds), only runs that do need the functionality will pay the (modest but measurable) price.
It's still an optimization that's only worthwhile in pretty extreme situations, and there are many others I would consider before trying to squeeze out microseconds in this way.