Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Importing "*" From a Package

In this lesson, you’ll learn about importing * from a package. For the purposes of the following discussion, the previously defined package is expanded to contain some additional modules:

Illustration of hierarchical file structure of Python packages

There are now four modules defined in the pkg directory. Their contents are as shown below.

mod1.py:

Python
def load_data():
    print('loading data using mod1.load_data()')

class Customer:
    pass

mod2.py:

Python
def clean_data():
    print('cleaning data using mod2.clean_data()')

class Location:
    pass

mod3.py:

Python
def merge_data():
    print('merging data using mod3.merge_data()')

class Message:
    pass

mod4.py:

Python
def send_mail():
    print('sending mail using mod4.send_mail()')

class Winner:
    pass

You have already seen that when import * is used for a module, then all objects from the module are imported into the local symbol table, except those whose names begin with an underscore, as usual:

Python
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help']
>>> from pkg.mod3 import *
>>> dir()
['Message', '__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'merge_data']
>>> merge_data()
merging data using mod3.merge_data()
>>> Message
<class 'pkg.mod3.Message'>

The analogous statement for a package is this:

Python
from <package_name> import *

Here’s what it does:

Python
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help']
>>> from pkg import *
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help']

Hmph. Not much. You might have expected (assuming you had any expectations at all) that Python would dive down into the package directory, find all the modules it could, and then import them all. But as you can see, by default that is not what happens.

Instead, Python follows this convention: if the __init__.py file in the package directory contains a list named __all__, then it is taken to be a list of modules that should be imported when the statement from <package_name> import * is encountered.

For the present example, suppose you create an __init__.py in the pkg directory like this:

Python
__all__ = [
        'mod1',
        'mod2',
        'mod3',
        'mod4'
        ]

Now from pkg import * imports all four modules:

Python
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help']
>>> from pkg import *
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help', 'mod1', 'mod2', 'mod3', 'mod4']
>>> mod1.load_data()
loading data using mod1.load_data()
>>> mod4.Winner
<class 'pkg.mod4.Winner'>

Using import * still isn’t considered terrific form, any more for packages than it is for modules. But this facility at least gives the creator of the package some control over what happens when import * is specified. (In fact, it provides the capability to disallow it entirely, simply by declining to define __all__ at all. As you have seen, the default behavior for packages is to import nothing.)

By the way, __all__ can be defined in a module as well and serves the same purpose, which is to control what is imported with import *. For example, modify mod1.py as follows:

Python
__all__ = ['load_data']

def load_data():
    print('loading data using mod1.load_data()')

class Customer:
    pass

Now, an import * statement from pkg.mod1 will only import what is contained in __all__:

Python
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help']
>>> from pkg.mod1 import *
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help', 'load_data']
>>> load_data()
loading data using mod1.load_data()
>>> Customer
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    Customer
NameError: name 'Customer' is not defined

load_data() is now defined in the local namespace, but Customer is not, because the latter is not in __all__. In summary, __all__ is used by both packages and modules to control what is imported when import * is specified. But the default behavior is different:

  • For a package, when __all__ is not defined, then import * does not import anything.
  • For a module, when __all__ is not defined, then import * imports everything (except—you guessed it—names starting with an underscore).

00:00 In this video, you’ll learn more about importing using the asterisk (*) from a package. To delve in a little deeper about using that wildcard, you’re going to need to expand the current package a bit.

00:11 So, here’s the pkg/ directory. Right now, your package contains mod1 and mod2, but I’m going to have you add additional modules mod3 and mod4 to help illustrate the wildcard importing. Let me have you take a look.

00:26 Inside that pkg/ folder, go ahead and delete the file __init__.py,

00:33 and then create the two other mod files, mod3.py and mod4.py.

00:49 Make sure that they’re within the pkg/ directory. Okay, so mod1 has a function named load_data() that prints out 'loading data', and a class called Customer.

01:01 mod2 has a clean_data() function that prints out 'cleaning data', and it has a class called Location. mod3—inside of mod3 define a new function called merge_data(). For this example, make a print() statement, 'merging data using merge_data()'.

01:24 It doesn’t need to be an f-string.

01:28 And for a class, create a class called Message. And save. mod4—you’re going to have another function called send_mail(),

01:48 and a class called Winner. Okay, so mod3, make sure you’ve saved. mod4, make sure you saved. mod2 and mod1great. Okay. Back here, go ahead and restart your REPL session.

02:04 You may remember the dir() function that shows the local symbol table.

02:10 Again, it returns the names and the current scope. So right now, here are all the names that are available. If you were to use from pkg.mod3, for example, and import everything using import *, what did that add?

02:25 Well, that added the two objects—the class Message and the function merge_data(). So again, merge_data() is available. If you were to type Message, you can see that it’s coming from pkg.mod3the class Message. Go ahead and exit and restart the REPL one more time. Take a look at dir().

02:50 What if you went from pkg and tried to import everything using import *? What’s going to happen? Well, it doesn’t import anything.

03:00 There’s a convention that import * uses inside of Python, where it looks for something called an __all__ list, or the dunder __all__ attribute.

03:11 Let me have you create one.

03:16 A little bit ago, I had you delete the __init__.py file, but now I’d like you to recreate that file. And inside of it, add a list and its name will be __all__. So again, it would look like this, re-adding the __init__.py file.

03:32 Now let me show you the rest of it in the code. Exit the REPL, and here inside of pkg/, make a new file creating a __init__ file again.

03:43 And in that __init__ file, you’re going to create a single variable, a single object that will be __all__, and it’s going to be a list.

03:55 __all__ =, and here I’ll have you create this list of the modules. In fact, they need to be text strings, and you don’t need the '.py' at the end.

04:11 Okay. So here you go. The __all__ list for __init__.py is going to include 'mod1', 'mod2', 'mod3', and 'mod4' in the square brackets of a list, and save.

04:20 So that’s the only thing that’s in __init__.py.

04:24 Now back here, make sure that you’ve saved. The current directory shows this. Now if you use from pkg import the wildcard, asterisk (*), what did that do? That actually imported all of the modules.

04:41 So now mod1.load_data() is available. Even mod4—that class mod4.Winner is available.

04:53 This form of wild import using the star (*)–is it considered a good development practice? Whether for packages or modules, it is a feature that gives the creator of the package the control over what happens when import * is specified, meaning that if you have an __all__ list inside your __init__.py file, you can determine what happens when a user of your package does this command.

05:21 And similarly, you can actually do that same thing for modules. You can actually specify an __all__ list inside of a module in case there are certain things that you don’t want to be imported when using a wildcard. What does that look like? Open up mod1

05:39 exiting the REPL again—and inside mod1 at the top, specify a __all__ list and inside of it include just 'load_data'.

05:51 So now, if you were to go back into the REPL—again, make sure that you’ve saved mod1, having this new __all__ list inside of it.

06:02 Type dir() to see the current scope, the local symbol table, and then try out using pkg.mod1, importing via the wildcard, asterisk (*).

06:13 What did that do? That put 'load_data' into the local symbol table. load_data(), that function, can be called and used. Well, what about Customer? Customer isn’t defined, it did not get imported even though it’s part of the package mod1. Using this __all__ method allowed you to specify as a wildcard what gets imported. And more importantly, with a module, it can be what doesn’t get imported, which is pretty cool.

06:40 Let me review that with you. The __all__ list controls what is imported when import * is specified. For a package, when the __all__ list is not defined, using import * doesn’t import anything.

06:56 But for a module, when the __all__ is not defined, import * imports everything—and this is a review—except names that are starting with an underscore (_).

07:06 Hence, why you may want to define one. In the next video, I’ll show you about subpackages.

Avatar image for Jakob Fredriksson

Jakob Fredriksson on July 28, 2020

I’ve been grinding Python for a couple of months by now but I’ve been cheating and “skipped” some basics. Basics like this. Great teaching throughout this course, much desired and much needed basics fell in place.

Your color-theme btw? It’s awesome!

Become a Member to join the conversation.