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

Popular posts from this blog

css - Which browser returns the correct result for getBoundingClientRect of an SVG element? -

gcc - Calling fftR4() in c from assembly -

.htaccess - Matching full URL in RewriteCond -