How to import anything

So far, we have used two different versions of the import statement:

  • Importing a module and then using the module name to access something defined within that module. For example:
    import math
    print(math.pi)
  • Importing something from a module and then using that thing directly. For example:
    from math import pi
    print(pi)

The import statement is very powerful, however, and we can do all sorts of interesting things with it. In this section, we will look at the different ways in which you can use the import statement to import modules and packages, and their contents, into your program.

What does the import statement actually do?

Whenever you create a global variable or function, the Python interpreter adds the name of that variable or function to what is called the global namespace. The global namespace holds all the names that you have defined at the global level. To see how this works, enter the following command into the Python interpreter:

>>> print(globals())

The globals() built-in function returns a dictionary with the current contents of the global namespace:

{'__package__': None, '__doc__': None, '__name__': '__main__', '__builtins__': <module 'builtins' (built-in)>, '__loader__': <class '_frozen_importlib.BuiltinImporter'>}

Tip

Don't worry about the various oddly named globals such as __package__; these are used internally by the Python interpreter.

Now, let's define a new top-level function:

>>> def test():
...     print("Hello")
...
>>>

If we now print out the dictionary of global names, our test() function will be included:

>>> print(globals())
{...'test': <function test at 0x1028225f0>...}

Note

There are several other entries in the globals() dictionary, but from now on we'll only show the items that interest us so that these examples aren't too confusing.

As you can see, the name test has been added to our global namespace.

Tip

Once again, don't worry about the value associated with the test name; this is Python's internal way of storing the functions that you define.

When something is in the global namespace, you can access it by name from anywhere in your program:

>>> test()
Hello

Note

Note that there's a second namespace, called the local namespace, that holds variables and other things defined within the current function. While the local namespace is important when it comes to variable scope, we're going to ignore it as it isn't generally involved in importing modules.

Now, when you use the import statement, you are adding entries to the global namespace:

>>> import string
>>> print(globals())
{...'string': <module 'string' from '/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/string.py'>...}

As you can see, the module that you imported has been added to the global namespace, allowing you to access that module by name, for example like this:

>>> print(string.capwords("this is a test"))
This Is A Test

In the same way, if you used the from...import version of the import statement, the item you've imported will be added directly to the global namespace:

>>> from string import capwords
>>> print(globals())
{...'capwords': <function capwords at 0x1020fb7a0>...}

So now you know what the import statement does: it adds what you're importing to the global namespace so that you can access it.

Using the import statement

Now that we've seen what the import statement does, let's take a look at the different versions of the import statement that Python provides.

We've already seen the two most common forms of the import statement:

  • import <something>
  • from <somewhere> import <something>

With the first form, you aren't limited to importing modules one at a time. If you want, you can import multiple modules at once, like this:

import string, math, datetime, random

Similarly, you can import multiple things at once from a module or package:

from math import pi, radians, sin

If you have more items to import than will fit on one line, you can either use line continuation characters () to spread the import across multiple lines, or surround the list of items that you want to import with parentheses. For example:

from math import pi, degrees, radians, sin, cos, 
                 tan, hypot, asin, acos, atan, atan2

from math import (pi, degrees, radians, sin, cos, 
                  tan, hypot, asin, acos, atan, atan2)

When you import something, you can also change the name of the imported item:

import math as math_ops

In this case, you are importing the math module under the name math_ops. The math module will be added to your global namespace using the name math_ops, and you can access the math module's contents using the math_ops name:

print(math_ops.pi)

There are two reasons why you might want to use the import...as statement to change the name of something when you import it:

  1. To make a long or unwieldy name easier to type.
  2. To avoid naming conflicts. For example, if you are using two packages that both define a module named utils, you might want to use the import...as statement so that the names are different. For example:
    from package1 import utils as utils1
    from package2 import utils as utils2

Note

Note that you should probably use the import...as statement sparingly. Every time you change the name of something, you (and anyone reading your code) will have to remember that X is another name for Y, which adds complexity and means that you have more things to remember as you write your program. There are certainly legitimate uses for the import...as statement, but don't overuse it.

You can, of course, combine the from...import statement with import...as:

from reports import customers as customer_report
from database import customers as customer_data

Finally, you can use a wildcard import to import everything from a module or package in one fell swoop:

from math import *

This adds all the items defined in the math module into the current global namespace. If you are importing from a package, then all the items defined in the package's __init__.py file will be imported.

By default, everything in the module (or package) that doesn't start with an underscore character will be imported by a wildcard import. This ensures that private variables and functions won't be imported. If you want, however, you can change what gets included in a wildcard import by using the __all__ variable; this will be discussed in the Controlling what gets imported section later in this chapter.

Relative imports

So far, whenever we've imported something, we've used the full name of the module or package that we want to import from. For simple imports such as from math import pi, this is sufficient. There are times, however, when this type of importing can be quite cumbersome.

Consider, for example, the complex tree of packages that we looked at in the Packages within packages section earlier in this chapter. Imagine that we want to import a module named slider.py from within the program.gui.widgets.editor package:

Relative imports

You could import this module using the following Python statement:

from program.gui.widgets.editor import slider

The program.gui.widgets.editor part of the import statement identifies the package where the slider module can be found.

While this works, it can be quite unwieldy, especially if you have a lot of modules to import or if one part of a package needs to import several other modules from within the same package.

To handle this type of situation, Python supports the concept of relative imports. Using relative imports, you identify what you want to import relative to the current module's position within the tree of packages. For example, imagine that the slider module wanted to import another module within the program.gui.widgets.editor package:

Relative imports

To do this, you replace the package name with a . character:

from . import slider

The . character is a shorthand for the current package.

In a similar way, imagine that you have a module within the program.gui.widgets package that wants to import the slider module from the editor sub-package:

Relative imports

In this case, your import statement would look like the following:

from .editor import slider

The . character still refers to the current location, and editor is the name of the package relative to this current location. In other words, you are telling Python to look for a package named editor in the current location, and then import the module named slider within this package.

Let's consider the opposite situation. Imagine that the slider module wants to import a module from the widgets directory:

Relative imports

In this case, you can use two . characters to mean go up one level:

from .. import controls

As you might imagine, you can use three . characters to mean go up two levels and so on. You can also combine these techniques to move through the package hierarchy in any way you like. For example, imagine that the slider module wants to import a module named errDialog from the gui.dialogs.errors package:

Relative imports

Using relative imports, the slider module could import the errDialog module in the following way:

from ...dialogs.errors import errDialog

As you can see, you can use these techniques to select any module or package anywhere in the tree of packages, relative to your current position in the tree.

There are two main reasons for using relative imports:

  1. They're a great way of making your import statements shorter and easier to read. Instead of having to type from program.gui.widgets.editor import utils in the slider module, you can simply type from . import utils.
  2. When you write a package for others to use, you can have different modules within your package refer to each other without having to worry about where the user installed the package. For example, I might take a package you've written and place it inside another package; using relative imports, your package will continue to work without having to change all the import statements to reflect the new package structure.

Like anything, relative imports can be overused. Because the meaning of the import statement depends on the position of the current module, relative imports tend to violate the explicit is better than implicit principle. You can also get into trouble if you attempt to run a module from the command line, as described in the Running modules from the command line section later in this chapter. For these reasons, you should use relative imports sparingly, and stick to fully listing out the entire package hierarchy in your import statements unless you have a good reason not to.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.237.201