In order for a module or package to be reusable, it has to meet the following requirements:
If a module or package does not meet these three requirements, it would be very hard, if not impossible, to reuse it in other programs. Let's now take a closer look at each of these requirements in turn.
Imagine that you decide to share a module named encryption
, which performs text encryption using public/private key pairs. Another programmer then copies this module into their program. When they try to use it, however, their program crashes with the following error message:
ImportError: No module named 'hash_utils'
The encryption
module may have been shared, but it was dependent on another module within the original program (hash_utils.py
) that wasn't shared, and so the encryption
module by itself is useless.
The solution to this problem is to combine the module you want to share with any other modules it may depend upon, putting the modules together into a package. You then share the package, rather than the individual module. The following illustration shows how this might be done:
In this example, we have created a new package named encryptionlib
and moved both the encryption.py
and hash_utils.py
files into this package. Of course, this requires you to refactor the rest of your program to allow for the new position of these modules, but it does then allow you to reuse your encryption logic in other programs.
Continuing with the example from the previous section, imagine that you want to use your new encryptionlib
package as part of another program, but don't want to make it publically available as a separate package. In this case, you can simply include the entire encryptionlib
directory as part of your new system's source code. When you do this, however, you can run into problems if your modules don't use relative imports. For example, if your encryption
module is dependent on the hash_utils
module, then the encryption
module is going to include an import
statement referring to the hash_utils
module. However, the resulting package cannot be reused if the encryption
module imports hash_utils
in any of the following ways:
import hash_utils from my_program.lib import hash_utils from hash_utils import *
All of these import statements will fail because they assume that the hash_utils.py
file is at a particular fixed point in your program's source code. Any assumption about the position of a dependent module within the program's source code will limit the reusability of the package as you can't then move the package to a different place and expect it to work. Given the requirements of the new project, you will often have to store packages and modules in a different place from where they were originally developed. For example, perhaps the encryptionlib
package needs to be installed in a thirdparty
package along with all the other reused libraries. Using absolute imports, your package will fail because the location of the modules within it will have changed.
To solve this problem, make sure that any import
statements within a package that refer to other modules within the same package always use a relative import. For example:
from . import hash_utils
This will allow your package to work no matter where in the Python source tree the package has been placed.
Imagine that our new encryptionlib
package makes use of the NumPy
library we encountered in the previous chapter. Perhaps hash_utils
imports some functions from NumPy and uses them to quickly calculate a binary hash of a list of numbers. Even though NumPy was installed as part of the original program, you can't assume that the same is true of the new program: if you were to install the encryptionlib
package into a new program and run it, it would eventually fail with the following error:
ImportError: No module named 'numpy'
To prevent this from happening, it is important that anyone wanting to reuse your module is aware of the dependency on a third-party module and knows exactly what needs to be installed for your module or package to function. An ideal place to include this information is in the README
file or other documentation for the module or package you are sharing.
If you are using an automated deployment system such as setuptools or pip, these tools have their own way of identifying your package's requirements. It is still a good idea, though, to list the requirements in your documentation so your users will be aware of them before the package is installed.
18.190.156.93