1

I have been maintaining a project. I found that someone wrote a function where he has made an import statement inside a for loop like so

for obj in obj_list:
    from Levenshtein._levenshtein import distance
    if distance(obj.title, "some string") <= 2:
        do something

I assume that importing something inside a for loop causes unnecessary instruction execution. Hence, I want to refactor the code. But to do that I need a rationale to support my assumption that importing inside a for loop is not a good practice. Is my assumption correct?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
sajid
  • 807
  • 1
  • 9
  • 23
  • 1
    Dont assume. Search SO: [Does python optimize modules when they are imported multiple times?](https://stackoverflow.com/questions/296036/does-python-optimize-modules-when-they-are-imported-multiple-times) ( I googled for `python import module multiple times` - there are a bunch of other SO hits as well... ) – Patrick Artner Jun 05 '18 at 09:18
  • Possible duplicate of [Does python optimize modules when they are imported multiple times?](https://stackoverflow.com/questions/296036/does-python-optimize-modules-when-they-are-imported-multiple-times) – Patrick Artner Jun 05 '18 at 09:18
  • 2
    Importing within a for loop is not a good practice because it makes for more confusing code, but functionally there is no impact in the behavior of the program. If you have _strong_ reasons to import only within the loop (e.g. a package which causes side effects on import or takes very long to load and you don't want to fetch unnecessarily) you may still do it, but you should avoid it whenever possible. – jdehesa Jun 05 '18 at 09:21
  • 2
    @jdehesa: it's another binding action. If other code in the loop does `distance = *something else*` then the import would re-assign the function to the same name. Which would call for some refactoring to not re-use the name, really. – Martijn Pieters Jun 05 '18 at 09:22

1 Answers1

8

Just move the import out of the loop. You are correct in that this is causing Python some extra work each iteration.

A Python import statement does two things:

  • Check if the referenced module is already loaded, and if not, load it.
  • Bind (assign) one or more names.

So each loop iteration Python checks if the module is already loaded (roughly equivalent to checking 'Levenshtein._levenshtein' in sys.modules), then sets the name distance.

Provided nothing else in the loop sets the name distance to anything else, you can safely move the import out of the loop and save yourself those checks as well. If there is such code, then refactor it to not use the same name, and move the import out of the loop.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • This is exactly what I was looking for - "If python interpreter does some extra work in each iteration". As you said "it checks if the referenced module is already loaded, and if not, load it." which answers my question. – sajid Jun 05 '18 at 09:28