Search code examples
pythonpython-importpython-module

Do packages at the top of a module get imported when we are only calling a function from that module


I have a module foo.py, which I am importing in my file main.py, I have imports at the top of foo.py such as import numpy as np, etc. Now, if I'm only calling a certain function fun(arg1, arg2, arg3), do the imports at the top of foo.py take place or do I have to add the imports inside the function definition of fun?

Also, does from foo import fun make a difference then import foo in this regard?

File foo.py (to be imported)

import numpy as np

def fun(arg1, arg2, arg3):
    x = np.argsort(arg1)
    return x

File main.py

import foo

call = fun([2, 34, 0, -1], 4, 5])

Or should I go with this in foo.py?

def fun(arg1, arg2, arg3):
   import numpy as np
   x = np.argsort(arg1)
   return x

Solution

  • When the module is loaded for the first time, all the lines in it are run. imports, defs, regular assignments, etc. All these lines initialize a namespace that is the module object. The namespace of foo will have a variable np that points to the loaded numpy module, and a variable fun that points to your function object.

    Functions are first class objects in python. In particular, they have a __globals__ (look under "Callable Types" in the linked docs) attribute, which points to the namespace of the module they were defined in. No matter what you do to the reference of foo.fun, the namenp will be available in the function until you delete it from foo itself.

    It is not recommended that you import anything inside your function, unless you have good reason to do so, like avoiding a global name. When you import a module, the interpreter will first look into sys.modules. If it is found, the import will not take much longer than a lookup into the global dictionary. However, if the module hasn't been loaded yet, it will be right there and then. You may not want to incur that overhead at an arbitrary point in your program, especially one that may be time-sensitive.

    As far as import form, the differences are mostly aesthetic, but they do have practical consequences as well. from foo import fun creates a name fun in your namespace, referring directly to the function object of interest. It contaminates your local namespace with an extra name, but saves you a lookup through foo's namespace dictionary every time you access the function. import foo, on the other hand, keeps everything bundled nicely since you have to call foo.fun, but that requires an extra lookup.

    TL;DR

    You should put all your imports at the top of your file. It doesn't really matter how you do it.