from <package> import *#

Individual .py files in Python are modules. But a folder containing a bunch of .py files is a package. This section shows the behaviour of the program when you use the from <package name> import * syntax.

from importlib import reload

Creating package#

Consider package with two modules. It is created in the following cells.

%%writefile from_package_import_all_files/package/__init__.py
# this is __init__.py - it's not necessary
# but generally better to add it to packages
Overwriting from_package_import_all_files/package/__init__.py
%%writefile from_package_import_all_files/package/square.py
square = """
+----+
|    |
|    |
|    |
+----+
"""

def draw_square():
    print(square)
Overwriting from_package_import_all_files/package/square.py
%%writefile from_package_import_all_files/package/triangle.py
triangle = """
   *
  * *
 *   *
*******
"""

def draw_triangle():
    print(triangle)
Overwriting from_package_import_all_files/package/triangle.py

Entry script#

Here is script that trying to import everything from package created before and shows dir() output. dir() returns current namespace - names that can be accessed in a current interpreter run:

%%bash
cd from_package_import_all_files
python3
from package import *
dir_result = dir()
print("Namesapce -", dir_result)
Namesapce - ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

The result is a bit counterintuitive - none of the modules in the package appear in the namespace. To get python to load modules from the package in such a case, you need to specify them in the __all__ dunder of the modules __init__.py. Read more in the following section.

Load modules (__all__)#

In __all__ dunder list you can describe modules that need to be imported to namespace when outer script tries to import everything from module.

The following cell modify __init__.py:

%%writefile from_package_import_all_files/package/__init__.py
__all__=["square"]
from .triangle import draw_triangle
Overwriting from_package_import_all_files/package/__init__.py

Let’s now try to check what we have in such case:

%%bash
cd from_package_import_all_files
python3
from package import *
dir_result = dir()
print("Namesapce -", dir_result)
square.draw_square()
Namesapce - ['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'square']

+----+
|    |
|    |
|    |
+----+

The results are worthy of detailed consideration:

  • We finally have square in the namespace and you can use its functions accordingly;

  • But triangle.draw_triangle that was defined in conventional way still doesn’t appear in the namespace.

Add object to __all__#

Note that it’s not possible to add specific obejects from within the module.

The following example attempts to add the triangle.draw_triangle function to the __all__ dunder.

%%writefile from_package_import_all_files/package/__init__.py
__all__=[
    "square",
    "triangle.draw_triangle"
]
Overwriting from_package_import_all_files/package/__init__.py

But if you try to run such an option, you’ll get an error:

%%bash
cd from_package_import_all_files
python3
try:
    from package import *
except Exception as e:
    print(e)
module 'package' has no attribute 'triangle.draw_triangle'