Reputation: 1892
during code implementation, I got suggestion we should import only specific feature which will reduce time but I got some different result. Am I doing some thing wrong.
python -m timeit "from subprocess import call" (suggested method which is taking more time)
1000000 loops, best of 3: 1.01 usec per loop
python -m timeit "import subprocess"
1000000 loops, best of 3: 0.525 usec per loop
Upvotes: 0
Views: 100
Reputation: 104692
The performance difference between import subprocess
and from subprocess import call
is likely to be very small (probably it will be completely dominated by the overhead involved in actually creating and running other processes). However, there are some small performance differences between them, and it might be worth seeing where they come from.
Here's the code I used to get a feel for what they do. I use the dis
module to disassemble compiled Python bytecode, so we can see what is happening:
import dis
from_import_src = """
from subprocess import call
foo = call
"""
plain_import_src = """
import subprocess
foo = subprocess.call
"""
from_bytecode = compile(from_import_src, "from_import", "exec")
plain_bytecode = compile(plain_import_src, "plain_import", "exec")
print("from ... import ...")
dis.dis(from_bytecode)
print("\nimport ...")
dis.dis(plain_bytecode)
The output:
from ... import ...
2 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (('call',))
6 IMPORT_NAME 0 (subprocess)
9 IMPORT_FROM 1 (call)
12 STORE_NAME 1 (call)
15 POP_TOP
3 16 LOAD_NAME 1 (call)
19 STORE_NAME 2 (foo)
22 LOAD_CONST 2 (None)
25 RETURN_VALUE
import ...
2 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (None)
6 IMPORT_NAME 0 (subprocess)
9 STORE_NAME 0 (subprocess)
3 12 LOAD_NAME 0 (subprocess)
15 LOAD_ATTR 1 (call)
18 STORE_NAME 2 (foo)
21 LOAD_CONST 1 (None)
24 RETURN_VALUE
If you're not familiar with the dis.dis
output, here's a brief overview: The first column is the source line (since our sources' first lines are blank, the real code is on lines 2 and 3). The third column shows the bytecode instruction that is to be run, and the last column shows the arguments it receives. The other numbers are not important.
Now, not every Python bytecode takes the same amount of time to execute, but as a first approximation, comparing the number of instructions for each line of the two codes can suggest where they differ in performance.
The first version, which uses from ... import ...
does a bunch more work during the import step. That is, it first imports the module, then loads the call
attribute from it and saves that into the local namespace. This up front cost though pays off in the second step where we access the call
function to save it into another variable. There's only one lookup required, since call
is already in the top level namespace.
The second version that uses import ...
does less up front work on the import line, but it must do two lookups to resolve subprocess.call
in the second line.
So, we can conclude that if you are accessing an attribute many times, the from ... import ...
approach will probably be faster. On the other hand, if you're only accessing the attribute once, using a plain import ...
may have lower overhead.
But really, performance of imports is probably not a very important thing. Use whatever makes your code most readable, and worry about performance only if profiling tells you that you have a significant issue.
Upvotes: 1
Reputation: 4412
This kind of profiling is not useful since you do not have any code that uses the module that is being imported.
Include code that actually uses the subprocess module. You may find that the difference between the 2 types of imports to be of marginal consequence.
Upvotes: 1
Reputation: 1302
The reason for importing particular functions from modules is more about having manageable namespaces in your functions and less about speed. It is possible, as Joachim Pileborg suggests in your comments, that actual execution of the function brought in using from ... import
is faster, but even then you may not notice the difference in the vast majority of scripts.
The best thing to do is import modules in the way that makes the code most readable and maintainable to you (for example, would you rather see call()
or subprocess.call()
in your code?) and focus on performance only in those specific instances where a small part of your code is a bottleneck, or your code is overall too slow.
Upvotes: 1
Reputation: 7799
In first place, any serious test requires more than 2 executions. But I assume you have performed many more with similar results.
What is improved is not import
's time, but general execution time. Specifically the time it takes the interpreter to resolve any kind of symbols.
I'd suggest you to take the biggest module you have in production and replace all general imports with specific ones and time this.
Another reason to prefer specific imports is documentation: having an idea of what a program does and how it does it by its imports. If the imports are specific, this information is also more specific.
Upvotes: 1