Importing Dynamically
00:00 In the previous lesson, I explained how Python handles circular imports. In this lesson, I’ll introduce you to dynamically loading modules. There are times when you don’t know what module to load when writing your script, but want to figure it out at runtime instead.
00:16
For example, you might want to change an import based on some configuration data or provide a plugin mechanism to your program. The importlib
module has a tool for this, the aptly named import_module()
function.
00:30 Let’s write a simple program that uses this feature.
00:34
Well, at least this program’s a little bigger than dog.py
. What it does is prompt the user for the name of a module, then prints out the documentation for that module.
00:45
This first line is where I prompt the user, and then the import_module()
function from importlib
is what does the magic. It takes a string containing the name of a module and what it returns is a reference to that module.
00:57
If you’ve been a good little programmer and included docstrings in your module, they can be accessed using the .__doc__
attribute. In this final line of this massively epic program, I print out that said, same docstring.
01:13 Let’s run this puppy. Back to the dogs, huh?
01:20
There’s the prompt. Let’s start with the math
module.
01:25
math
contains math. Go figure. Let’s try another one.
01:33
And cmath
contains math for complex numbers. It can’t all be this terse, can they? Let’s try one more.
01:45 Ah, that’s better. Too much to fit on the screen, but you get the idea.
01:51 Sometimes, your software needs more than just the code files. Sometimes you need configuration files or assets like sounds or images for a game or just plain old data to make your code work.
02:02
If you have these things in a package, you could use the __file__
value to create a pathlib.Path
object and load them. Or you could save a few lines of code and use the tools in the importlib.resources
module.
02:15 Let me show you how that’s done.
02:18
Another lesson, another code tree. This is my game package, which contains three things, a __init__.py
file, no namespace packages here, a __main__.py
file, and a sounds.txt
file.
02:32
__main__
is special for Python and is used in conjunction with running scripts. If you create a class in the REPL, its module is __main__
.
02:41
When you run a script, that script’s __name__
value is __main__
. Or if you put a file named __main__.py
in a module, that is what gets called when you use the -m
argument to the Python interpreter.
02:55
If you ever used pip
in the form python -m pip
, well what that does is look for the __main__.py
file in the pip
package and executes it.
03:06 Let’s take a look inside.
03:09
Still keeping with that small program theme going here. I start off by importing the resources
module from importlib
. To load a file from a package, you use the files()
function of the resources
module.
03:23
This takes an argument, which is the name of the module to look inside, and it returns a pathlib.Path
object that points to the directory location of that module on your hard drive.
03:34
Since it is a pathlib.Path
, I can use the overloaded slash operator like I did before to create a new path pointing to the sounds.txt
file.
03:44
And since it’s a pathlib.Path
, I can use the read_text()
function on that object, which returns all of its contents as a single string and then pass that to print()
to display the content.
03:56
Let’s try this out using the -m
argument to Python to execute our module, that’s what the -m
is for. And there you have it. The code from games.__main__.py
file got run, which loaded sounds.txt
and printed them out.
04:13 The more manual way of doing this is only a few more lines of code, but this feels very clean to me. I like it. Next up, how to zip up your Python and still have it be runnable.
Become a Member to join the conversation.