Is It Pythonic to Import Inside Functions

In Python, what happens when you import inside of a function?

Does it re-import every time the function is run?

No; or rather, Python modules are essentially cached every time they are imported, so importing a second (or third, or fourth...) time doesn't actually force them to go through the whole import process again. 1

Does it import once at the beginning whether or not the function is run?

No, it is only imported if and when the function is executed. 2, 3

As for the benefits: it depends, I guess. If you may only run a function very rarely and don't need the module imported anywhere else, it may be beneficial to only import it in that function. Or if there is a name clash or other reason you don't want the module or symbols from the module available everywhere, you may only want to import it in a specific function. (Of course, there's always from my_module import my_function as f for those cases.)

In general practice, it's probably not that beneficial. In fact, most Python style guides encourage programmers to place all imports at the beginning of the module file.

Is it pythonic to import inside functions?

In the long run I think you'll appreciate having most of your imports at the top of the file, that way you can tell at a glance how complicated your module is by what it needs to import.

If I'm adding new code to an existing file I'll usually do the import where it's needed and then if the code stays I'll make things more permanent by moving the import line to the top of the file.

One other point, I prefer to get an ImportError exception before any code is run -- as a sanity check, so that's another reason to import at the top.

I use pyChecker to check for unused modules.

Should import statements always be at the top of a module?

Module importing is quite fast, but not instant. This means that:

  • Putting the imports at the top of the module is fine, because it's a trivial cost that's only paid once.
  • Putting the imports within a function will cause calls to that function to take longer.

So if you care about efficiency, put the imports at the top. Only move them into a function if your profiling shows that would help (you did profile to see where best to improve performance, right??)


The best reasons I've seen to perform lazy imports are:

  • Optional library support. If your code has multiple paths that use different libraries, don't break if an optional library is not installed.
  • In the __init__.py of a plugin, which might be imported but not actually used. Examples are Bazaar plugins, which use bzrlib's lazy-loading framework.

If I import a module inside a function, will the variables be local?

Yes, the module will be local to the function, at least in the example above(I am using Python 3.6).

Example:

Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
def test():
... import math
... s = math.cos(1)
...
g = math.cos(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'math' is not defined

Advantage of importing libraries inside function?

Actually, importing the modules locally inside a function would improve efficiency (slightly). Looking up local names is always faster than looking up globals because the global namespace is one of the last that Python checks when searching for a name.

That said, I wouldn't recommend doing this for three reasons:

  1. It wastes lines of code. Every function which needs a particular module will have to import it. This means that you will have a lot of repeated import statements.

  2. It makes the dependencies of your code hard to find. One of the main reasons that you import at the top of a file is so that the imports are easily visible.

  3. It goes against PEP 0008, which specifically says:

    Imports are always put at the top of the file, just after any module
    comments and docstrings, and before module globals and constants.

Is there a performance cost putting python imports inside functions?

The point at which you import a module is not expected to cause a performance penalty, if that's what you're worried about. Modules are singletons and will not be imported every single time an import statement is encountered. However, how you do the import, and subsequent attribute lookups, does have an impact.

For example, if you import math and then every time you need to use the sin(...) function you have to do math.sin(...), this will generally be slower than doing from math import sin and using sin(...) directly as the system does not have to keep looking up the function name within the module.

This lookup-penalty applies to anything that is accessed using the dot . and will be particularly noticeable in a loop. It's therefore advisable to get a local reference to something you might need to use/invoke frequently in a performance critical loop/section.

For example, using the original import math example, right before a critical loop, you could do something like this:

# ... within some function
sin = math.sin
for i in range(0, REALLY_BIG_NUMBER):
x = sin(i) # faster than: x = math.sin(x)
# ...

This is a trivial example, but note that you could do something similar with methods on other objects (e.g. lists, dictionaries, etc).

I'm probably a bit more concerned about the circular imports you mention. If your intention is to "fix" circular imports by moving the import statements into more "local" places (e.g. within a specific function, or block of code, etc) you probably have a deeper issue that you need to address.

Personally, I'd keep the imports at the top of the module as it's normally done. Straying away from that pattern for no good reason is likely to make your code more difficult to go through because the dependencies of your module will not be immediately apparent (i.e. there're import statements scattered throughout the code instead of in a single location).

It might also make the circular dependency issue you seem to be having more difficult to debug and easier to fall into. After all, if the module is not listed above, someone might happily think your module A has no dependency on module B and then up adding an import A in B when A already has import B hidden in some deep dark corner.



Benchmark Sample

Here's a benchmark using the lookup notation:

>>> timeit('for i in range(0, 10000): x = math.sin(i)', setup='import math', number=50000)
89.7203312900001

And another benchmark not using the lookup notation:

>>> timeit('for i in range(0, 10000): x = sin(i)', setup='from math import sin', number=50000)
78.27029322999988

Here there's a 10+ second difference.

Note that your gain depends on how much time the program spends running this code --i.e. a performance critical section instead of sporadic function calls.

import inside a function: is memory reclaimed upon function exit?

The first import executes the code in the module. It creates the module object's attributes. Each subsequent import just references the module object created by the first import.

Module objects in Python are effectively singletons. For this to work, the Python implementation has to keep the one and only module instance around after the first import, regardless of the name the module was bound to. If it was bound to a name anyway, as there are also imports of the form from some_module import some_name.

So no, the memory isn't reclaimed.

No idea about Micropython, but I would be surprised if it changes semantics here that drastically. You can simply test this yourself:

some_module.py:

value = 0

some_other_module.py:

def f():
import some_module
some_module.value += 1
print(some_module.value)

f()
f()

This should print the numbers 1 and 2.

Is it okay to import sys inside a function to check if a module has been imported?

You appear to be confused between a library being installed versus a library having been imported.

Your use-case seems to be concerned with Pandas not being installed. You can't test for this possibility with sys.modules. Just have your code import Pandas, and handle the ImportError thrown if it is not available:

try:
import pandas as pd

def is_dataframe(obj):
return isinstance(obj, pd.DataFrame)
except ImportError:
def is_dataframe(obj):
return False

The above code codifies the test for the dataframe type that will continue to work if Pandas is not installed.

If your code needs to take into account the possibility that some third-party library returns a dataframe, just use the above code to test for that contingency (but only if you can't make your code work in some other way, like just catching the exception if something is not the type you expected to handle). Don't try to second-guess if Pandas is actually being used somewhere. Either you handle dataframes or you don't, there is no need to make this dynamic. It's not as if the isinstance(obj, pd.DataFrame) test will throw an exception if obj is not a dataframe, there is no risk here.

Note that if you do try to test for the module being imported, detect that it wasn't, and only then another module imports Pandas, you made the wrong call and your code breaks. Python is a dynamic language and imports can be done at any time during the runtime of the program.

Otherwise, if Pandas is installed, and some third-party module imports Pandas to do their work and you are worried that they might, there is no need for your code to worry about this. There is no need for you to see if a third-party module is using Pandas or not, it won't make a difference to your code. Pandas is then just an implementation detail of another module.

Lastly, if a third-party module imports Pandas, your own module won't also see it. You need to use import statements for all dependencies for that module, it doesn't matter what another module has imported here, as each module is a separate namespace. You can't just use pd.DataFrame without an import statement (or other means of binding the name pd to the module object), regardless of other modules having imported it.

Should import be inside or outside a Python class?

Usually all imports go at the top of the module. That makes it easy to see the dependencies of a module at a glance, either by visual inspection or in a code checker like pyflakes. Your assumption that "importing Bar also requires you to manually import foo" is false.

The only times you would imports inside functions or methods are when the imports are very resource-intenstive (e.g., slow) or unreliable (e.g., optional dependencies that may not be installed, platform-specific modules or modules that tend to break), and client code is not expected to always call the functions in question.



Related Topics



Leave a reply



Submit