A mechanism for importing modules or packages using statements in Python

  • 2020-04-02 14:45:01
  • OfStack

This article discusses Python's from < The module > The import * and the from < package > Import *, how they execute, and why using this syntax is (perhaps) a bad idea.
Import them all from one module

The from < The module > Import * means, "I want access < The module > I have permission to access all the names ". For example, the following code is something.py:
 


# something.py
 
public_variable = 42
_private_variable = 141
 
def public_function():
  print("I'm a public function! yay!")
 
def _private_function():
  print("Ain't nobody accessing me from another module...usually")
 
class PublicClass(object):
  pass
 
class _WeirdClass(object):
  pass

In the Python interpreter, we can execute from something import * and see the following:
 


>>> from something import *
>>> public_variable
42
>>> _private_variable
...
NameError: name '_private_variable' is not defined
>>> public_function()
"I'm a public function! yay!"
>>> _private_function()
...
NameError: name '_private_function' is not defined
>>> c = PublicClass()
>>> c
<something.PublicClass object at ...>
>>> c = _WeirdClass()
...
NameError: name '_WeirdClass' is not defined

From something import * imports all names from something except those beginning with _, which are private and therefore not imported by the specification.
Well, not too bad! What else?

It doesn't say anything about 's s. S is a list of strings, specifying when from < The module > When import * is used, which symbols in the module (or package, as mentioned later) are exported. If we don't define __all__ (we are in the above something. Py is no definition), import * default import way is to import in addition to the underline (_) at the beginning of all names. Again, the programming convention for an underscore indicates that a symbol is private and that it is reasonable not to import it. Let's see what happens with defining our own s/s in something.py.
 


# something.py
 
__all__ = ['_private_variable', 'PublicClass']
 
# The rest is the same as before
 
public_variable = 42
_private_variable = 141
 
def public_function():
  print("I'm a public function! yay!")
 
def _private_function():
  print("Ain't nobody accessing me from another module...usually")
 
class PublicClass(object):
  pass
 
class _WeirdClass(object):
  pass

Now, we expect only _private_variable and PublicClass to be imported from something import * :
 


>>> from something import *
>>> public_variable
42
>>> _private_variable
...
NameError: name '_private_variable' is not defined
>>> public_function()
"I'm a public function! yay!"
>>> _private_function()
...
NameError: name '_private_function' is not defined
>>> c = PublicClass()
>>> c
<something.PublicClass object at ...>
>>> c = _WeirdClass()
...
NameError: name '_WeirdClass' is not defined

What does the bag look like?

When importing all of them from a package, you can do essentially the same thing as the module, except that it deals with the modules in the package (instead of importing all the names in the module). So when we use from < package > Import *. S/s illustrates all modules that need to be imported into the current namespace.

The difference is that if you do not declare arbitration, from, within a package of s/s. Py < package > The import * statement won't import anything (that is not all right, the correct statement (link: https://docs.python.org/3.4/tutorial/modules.html#importing-from-a-package)
But what's so bad about that?

Continue to read before, in your Python interpreter, perform the import this, read it again (link: http://legacy.python.org/dev/peps/pep-0020/) (in your children every night before going to bed to also want to read to them).

      Clarity is better than ambiguity.

The from < The module > Import * is ambiguous. It doesn't tell us what we're importing or what we're bringing into the current namespace. It is better to explicitly import all the names we need. This way, the reader (and most likely your future self) won't be confused about where a variable/method/class/other thing in your code came from, which tells us something else:

      Readability is important

Even if you need to import a lot of things, it's clearer to import them one by one explicitly. Use (link: http://legacy.python.org/dev/peps/pep-0328/) :
 


from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
  LEFT, DISABLED, NORMAL, RIDGE, END)

You now know exactly what's in your namespace, and using CTRL +f quickly tells you where it came from.

At the same time, you are always at risk of the module/package author changing the contents of the list (plus/minus things). Which is one of the following:

      The author deleted a string from arbitration. If your code USES that name, your code will report a NameError and it's hard to see why.
      The author has added a lot of things in arbitration. You probably don't need these additions, so you just let the stuff you don't care about fill up your namespace. They can even replace other content with the same name when you're not looking.

Of course, sometimes it's useful to import everything from a module or package. But think before you do that. In my experience, it's usually just laziness.


Related articles: