When you import from within the scope of a function, that import is only defined from within that function, and not in the scope that the function is called in.
I'd recommend looking at this question for a good explanation for scope rules in python.
To fix this, you can use python's star import.
imports.py:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
__all__ = [
'pd',
'np',
'sns',
'plt'
]
train.py:
from imports import *
...
The syntax from module import *
imports all variables defined in the __all__
list from within that module.
Edit
I strongly discourage the use of this code, because has the opposite effect you intend it to have. This will remove the "clutter" of redundant import statements, at the cost of something much worse: confusing code, and a hidden bug waiting to come to the surface (explained below).
Alas, the solution:
import inspect
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
CODE_CONTEXT = ['from imports import *\n']
__all__ = [
'pd',
'np',
'sns',
'plt'
]
def _get_filename():
frame, *_ = filter(
lambda frame: getattr(frame, 'code_context', None) == CODE_CONTEXT,
inspect.stack()
)
return frame.filename
imported_from = _get_filename()
if imported_from == 'train.py':
import sklearn
__all__.append('sklearn')
elif imported_from == 'eda.py':
...
To understand how a bug might come from this code, consider this example:
imports.py:
import inspect
CODE_CONTEXT = ['from imports import *\n']
__all__ = []
def _get_filename():
frame, *_ = filter(
lambda frame: getattr(frame, 'code_context', None) == CODE_CONTEXT,
inspect.stack()
)
return frame.filename
imported_from = _get_filename()
print(imported_from)
a.py:
from imports import *
b.py:
from imports import *
main.py:
import a
import b
When you run python3 main.py
what will print to the console?
a.py
Why isn't b.py
printed? Because modules are only executed once, during their first import. Since a.py
imported the module first, each subsequent import of imports.py
won't re-execute the module, they will reuse the code that was built during its initial execution.
TLDR;
Any alterations made to __all__
will only apply to the first import of the module, and subsequent imports might be missing the modules that are needed.