Skip to main content

Inappropriate coding practices - Wildcard export

Need

Enforce explicit exports in code modules

Context

  • Usage of Python for general-purpose programming and scripting
  • Usage of my_module for custom functionality or feature implementation

Description

Non compliant code

# my_module.py

def function_one():
pass

def function_two():
pass

def function_three():
pass

# __init__.py

from .my_module import *

In the above code snippet, the developer uses the wildcard operator (*) to import all functions from the my_module.py file into the __init__.py file. This is done in the line from .my_module import *.

Using the wildcard operator in this way is known as a wildcard import. It's a convenient way to import all functions, classes, and variables from a module without having to specify them individually. However, this practice can lead to problems.

Firstly, it can make the code harder to understand and maintain. If there are many functions in my_module.py, it's not immediately clear which ones are being used in __init__.py. A developer would have to open my_module.py and look through all the functions to figure this out.

Secondly, it can lead to namespace conflicts. If my_module.py and __init__.py both have a function with the same name, the one in __init__.py will be overwritten by the one in my_module.py. This can lead to unexpected behavior and bugs that are hard to track down.

Lastly, it can make the code less efficient. If my_module.py has many functions but only a few are used in __init__.py, importing all of them wastes memory and slows down the program.

Therefore, it's recommended to avoid wildcard imports and instead import only the functions that are actually needed.

Steps

  • Identify the specific functions that need to be exported from the module.
  • Instead of using the wildcard operator (*), explicitly list out the functions to be exported in the import statement.
  • This way, only the necessary functions are exposed, reducing the risk of misuse and making the module easier to maintain.

Compliant code

# my_module.py

def function_one():
pass

def function_two():
pass

def function_three():
pass

# __init__.py

from .my_module import function_one, function_two

In the original code, the wildcard operator (*) was used to import all functions from my_module. This is a bad practice as it exposes all functions, even those that are not necessary for the module's operation, which can lead to misuse and make the module harder to maintain.

In the fixed code, instead of using the wildcard operator, we explicitly list out the functions to be imported from my_module in the import statement. Here, only function_one and function_two are imported, and function_three is not, as it's assumed not to be necessary for the module's operation.

This way, we are only exposing the necessary functions, reducing the risk of misuse and making the module easier to maintain. This is a better coding practice as it promotes clarity about which functions are being used and avoids potential naming conflicts.

References