views:

148

answers:

3

I'm just wondering - if there is a library from which I'm going to use at least 2 methods, is there any difference in performance or ram usage between: from X import method1, method2 and this import X I know about namespaces and stuff, but I'm just wondering if python is smart enough to know that I'll use only 2 methods.

+5  A: 

There is no memory or speed difference (the whole module has to be evaluated either way, because the last line could be Y = something_else). Unless your computer is from the 1980s it doesn't matter anyways.

THC4k
+4  A: 

I don't believe there's any real difference, and generally worrying about that little amount of memory isn't typically worth it. If you're going to be pressing memory considerations, it will far more likely be in your code.

heckj
+10  A: 

There is a difference, because in the import x version there are two name lookups: one for the module name, and the second for the function name; on the other hand, using from x import y, you have only one lookup.

You can see this quite well, using the dis module:

import random
def f_1():
    random.seed()

dis.dis(f_1)
     0 LOAD_GLOBAL              0 (random)
     3 LOAD_ATTR                0 (seed)
     6 CALL_FUNCTION            0
     9 POP_TOP
    10 LOAD_CONST               0 (None)
    13 RETURN_VALUE

from random import seed

def f_2():
    seed()

dis.dis(f_2)
     0 LOAD_GLOBAL              0 (seed)
     3 CALL_FUNCTION            0
     6 POP_TOP
     7 LOAD_CONST               0 (None)
    10 RETURN_VALUE

As you can see, using the form from x import y is a bit faster.

On the other hand, import x is less expensive than from x import y, because there's a name lookup less; let's look at the disassembled code:

def f_3():
    import random

dis.dis(f_3)
     0 LOAD_CONST               1 (-1)
     3 LOAD_CONST               0 (None)
     6 IMPORT_NAME              0 (random)
     9 STORE_FAST               0 (random)
    12 LOAD_CONST               0 (None)
    15 RETURN_VALUE

def f_4():
    from random import seed

dis.dis(f_4)
     0 LOAD_CONST               1 (-1)
     3 LOAD_CONST               2 (('seed',))
     6 IMPORT_NAME              0 (random)
     9 IMPORT_FROM              1 (seed)
    12 STORE_FAST               0 (seed)
    15 POP_TOP
    16 LOAD_CONST               0 (None)
    19 RETURN_VALUE

I do not know the reason, but it seems the form from x import y looks like a function call, and therefore is even more expensive than anticipated; for this reason, if the imported function is used only once, it means it would be faster to use import x, while if it is being used more than once, it becomes then faster to use from x import y.

That said, as usual, I would suggest you not following this knowledge for your decision on how to import modules and functions, because this is just some premature optimization.
Personally, I think in a lot of cases, explicit namespaces are much more readable, and I would suggest you doing the same: use your own sense of esthetic :-)

Roberto Liffredo
@sdolan: Your timeit results seem to suggest `import x` is faster than `from x import y`, which seems to run contrary to what you might expect after viewing `dis.dis`. Rather curious.
unutbu
@~unutbu. I think the difference is that for `from x import y`, python must do extra work to locate `y` in `x`. When this is repeated once for every call to `y`, as it was in sdolans test, It probably becomes more expensive than just a plain `import` statement.
aaronasterling
**Update:** Here's some timeit results proving to the **contrary** that `from x import y` is faster (p is aliased to python2.6): p -m timeit "import random; random.seed()" 10000 loops, best of 3: 27.7 usec per loop p -m timeit "from random import seed; seed()" 10000 loops, best of 3: 29.2 usec per loop The same tests in 3.1 had the similar results.
sdolan
@~unutbu: Good catch... amazing what the power of suggestion/lack of cofee can do :) I've deleted my old post and updated it with the correct assessment. Very interesting indeed.. I've always assumed that `from...` would be faster.
sdolan
It's one opcode on the virtual machine. Let that take 10 cycles and that is **5 nanoseconds** on a 2 Ghz machine. Just reading this sentence takes more time than the program could save in your lifetime.
THC4k
I've added the analysis on the reasons for the findings from sdolan.
Roberto Liffredo
@THC4k: I don't think any of us are disagreeing with you, I certainly agree with the "use whatever makes sense". @Roberto: I did some more timeit tests with multiple calls... the `from ...` statement starts to get slightly faster after ~8 function calls. It's interesting, but not important... we're dealing with microseconds of difference here.
sdolan
Would a C module and a pure python module make a difference?
OTZ