11

I know how to use both, but I'm curious why the decision was made to make one a statement and the other a function.

user2229219
  • 342
  • 4
  • 16

1 Answers1

8

First of all you can import using a function, from importlib's documentation:

The __import__() function
The import statement is syntactic sugar for this function.

for instance both of these statements are equivalent:

from random import randint as random_int

random_int = __import__("random").randint

Reload only makes sense as an operation applied to a module object where as importing benefits from alternative syntax to avoid repetition, especially if you are importing several names from a module

 from foo import a,b,c 
 # vs
 a = __import__("foo").a; b = __import__("foo").b; c = __import__("foo").c
 # or maybe:
 _foo = __import__("foo")
 a,b,c = _foo.a, _foo.b, _foo.c
 del _foo

It is also highly desirable for the mechanism to load submodules to run on the same step as the import and not when an attribute is attempted to be loaded, so this is also much easier with the syntax sugar:

# from http import HTTPStatus
HTTPStatus = __import__("http").HTTPStatus # works

# try to load a submodule, but only reference the submodule on attribute lookup not as part of the import
server = __import__("http").server 
# ^ AttributeError: module 'http' has no attribute 'server'

from http import server # this works because the import mechanism tries to load submodule

assert not hasattr(http, "client") # is another submodule that is not loaded automatically

thingy = __import__("http.client")
# what would you expect `thingy` to be?
# remember that doing `import http.client` loads the submodule but only 
# puts `http` in the global scope so you still refer to the submodule as 
# `http.client` so here thingy is actually `http`
assert thingy is __import__("http") # passes

As for reload, if it was a statement I can imagine a lot of beginner programmers making this mistake:

from random import randint as r1
reload random # reload(__import__("random"))
from random import randint as r2
assert r1 is r2, "reloading a module only updates the namespace of the module itself, not any directly imported members"
# ^ will fail

the reload function can't possibly update fields that were imported by name, only updating the fields on the module object itself. related to this answer

Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59