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 🙂