python - Why does "from [Module] import [Something]" takes more time than "import [Module" -
this question has answer here:
i used python -mtimeit
test , found out takes more time from module import sth
comparing import module
e.g.
$ python -mtimeit "import math; math.sqrt(4)" 1000000 loops, best of 3: 0.618 usec per loop $ python -mtimeit "from math import sqrt; sqrt(4)" 1000000 loops, best of 3: 1.11 usec per loop
same other case. please explain rationale behind? thank you!
there 2 issues here. first step figure out part faster: import statement, or call.
so, let's that:
$ python -mtimeit 'import math' 1000000 loops, best of 3: 0.555 usec per loop $ python -mtimeit 'from math import sqrt' 1000000 loops, best of 3: 1.22 usec per loop $ python -mtimeit -s 'from math import sqrt' 'sqrt(10)' 10000000 loops, best of 3: 0.0879 usec per loop $ python -mtimeit -s 'import math' 'math.sqrt(10)' 10000000 loops, best of 3: 0.122 usec per loop
(that's apple cpython 2.7.2 64-bit on os x 10.6.4 on laptop. python.org 3.4 dev on same laptop , 3.3.1 on linux box give similar results. pypy, smarter caching makes impossible test, since finishes in 1ns… anyway, think these results portable microbenchmarks ever can be.)
so turns out import
statement more twice fast; after that, calling function little slower, not enough make cheaper import
. (keep in mind test doing import
each call. in real-life code, of course, tend call things lot more once per import
. so, we're looking @ edge case affect real code. long keep in mind, proceed.)
conceptually, can understand why from … import
statement takes longer: has more work do. first version has find module, compile if necessary, , execute it. second version has of that, , also extract sqrt
, insert current module's globals. so, has @ least little slower.
if @ bytecode (e.g., using dis
module , calling dis.dis('import math')
), difference. compare:
0 load_const 0 (0) 3 load_const 1 (none) 6 import_name 0 (math) 9 store_name 0 (math) 12 load_const 1 (none) 15 return_value
… to:
0 load_const 0 (0) 3 load_const 1 (('sqrt',)) 6 import_name 0 (math) 9 import_from 1 (sqrt) 12 store_name 1 (sqrt) 15 pop_top 16 load_const 2 (none) 19 return_value
the stack manipulation (the load_const
, pop_top
) doesn't make difference, , using different argument store_name
unlikely matter @ all… import_from
significant step.
surprisingly, quick&dirty attempt profile import_from
code shows majority of cost looking appropriate globals import into. i'm not sure why, but… that implies importing whole slew of names should not slower importing one. and, pointed out in comment, that's see. (but don't read that. there many reasons import_from
might have large constant factor , small linear one, , we're not throwing huge number of names @ it.)
one last thing: if ever matter in real code, , want best of both worlds, import math; sqrt = math.sqrt
faster from math import sqrt
, gives same small speedup lookup/call time. (but again, can't imagine real code matter. time you'll ever care how long sqrt
takes when you're calling billion times, @ point won't care how long import takes. plus, if need optimize that, create local scope , bind sqrt
there avoid global lookup entirely.)
Comments
Post a Comment