Is there a cost of execution that imports python inside functions?

I am creating fairly complex python applications, often with Django. To simplify inter-application interfaces, I sometimes use service.py modules, which abstract from models.

As these “aggregate functionalities”, they often receive cyclic imports, which can be easily eliminated by placing import statements inside utility functions.

Are there significant performance or memory costs associated with moving imports as close as possible to their point of use? For example, if I use only a specific imported name in one function in a file, it seems natural to place the import in that specific function, and not at the top of the file in a normal place.

This problem is slightly different from this question because each import is in the function namespace.

+5
source share
3 answers

The point at which you import the module is not expected to result in poor performance if it bothers you. Modules are single point and will not be import ed every time an import statement is encountered. However, the way you do the import and subsequent attribute checks is affected.

For example, if you import math , and then every time you need to use the sin(...) function, you must execute math.sin(...) , it will usually be slower than doing from math import sin and using sin(...) directly, as the system does not need to search for the function name in the module.

This viewing penalty applies to everything that is accessed using a period . and will be especially noticeable in the loop. Therefore, it is recommended to get a local link to something that you may need to use / call frequently in the critical loop / performance section.

For example, using the original import math example, right in front of the critical loop, you can do something like this:

 # ... within some function sin = math.sin for i in range(0, REALLY_BIG_NUMBER): x = sin(i) # faster than: x = math.sin(x) # ... 

This is a trivial example, but note that you can do something similar with methods for other objects (e.g. lists, dictionaries, etc.).

I'm probably a little more worried about the circular imports that you mention. If you intend to “commit” cyclic imports by moving import operations to more “local” places (for example, inside a specific function or code block, etc.), you probably have a deeper problem that you need to solve.

Personally, I would save the import at the top of the module, as usual. Deviating from this template without a good reason is likely to make your code more complex, because the dependencies of your module will not be immediately obvious (i.e. there are import statements scattered throughout the code, and not in one place).

It can also cause a cyclical dependency problem, which you find it harder to debug and easier to fall into. After all, if the module is not listed above, someone might be happy to think that your module A does not depend on module B , and then adds import A to B when A already has import B hidden in some deep dark the corner.


Performance example

Here, a reference using search notation is used:

 >>> timeit('for i in range(0, 10000): x = math.sin(i)', setup='import math', number=50000) 89.7203312900001 

And another test that doesn't use search notation:

 >>> timeit('for i in range(0, 10000): x = sin(i)', setup='from math import sin', number=50000) 78.27029322999988 

Here the difference is 10+ seconds.

Please note that your gain depends on how much time the program spends to execute this code --ie is a critical section of performance, not sporadic function calls.

+4
source

See this question.

Basically, whenever you import a module, if it was imported before it uses the cached value.

This means that performance will be hit the first time the module is loaded, but as soon as it is loaded, it will cache values ​​for future calls.

+2
source

As the ray said, importing certain functions (slightly faster) 1.62852311134 for sin () 1.89815092087 for math.sin () using the following code

 from time import time sin=math.sin t1=time() for i in xrange(10000000): x=sin(i) t2=time() for i in xrange(10000000): z=math.sin(i) t3=time() print (t2-t1) print (t3-t2) 
0
source

All Articles