text: In this lesson, you’ll learn more about the
  import statement. Module contents are made available to the caller with the
  import statement. The
  import statement takes many different forms, as you’ll see below.
  import <module_name>
  The simplest form is the one you already saw:
  import <module_name>
  Note that this does not make the module contents directly accessible to the caller. Each module has its own private symbol table, which serves as the global symbol table for all objects defined in the module. So, a module creates a separate namespace. you’ll see below.
  After the following
  import statement,
  mod is placed into the local symbol table. So,
  mod has meaning in the caller’s local context:
  >>> import mod >>> mod <module 'mod' from '/Users/chris/ModulesAndPackages/mod.py'>
  But
  a,
  s, and
  printy() remain in the module’s private symbol table and are not meaningful in the local context:
  >>> a Traceback (most recent call last): File "<input>", line 1, in <module> a NameError: name 'a' is not defined >>> s Traceback (most recent call last): File "<input>", line 1, in <module> s NameError: name 's' is not defined >>> printy Traceback (most recent call last): File "<input>", line 1, in <module> printy NameError: name 'printy' is not defined
  To be accessed in the local context, names of objects defined in the module must be prefixed by
  mod:
  >>> mod.a [100, 200, 300] >>> mod.s 'Computers are useless. They can only give you answers.' >>> mod.printy('Hello') arg = Hello, printy >>> s 'Computers are useless. They can only give you answers.' >>> printy('Hello') arg = Hello
  Because this form of
  import places the object names directly into the caller’s symbol table, any objects that already exist with the same name will be overwritten:
  >>> a = ['abc', 'def', 'ghi'] >>> a ['abc', 'def', 'ghi'] >>> from mod import a >>> a [100, 200, 300]
  It is even possible to indiscriminately
  import everything from a module in one fell swoop:
  from <module_name> import *
  This will place the names of all objects from
  <module_name> into the local symbol table, with the exception of any that begin with the underscore (
  _) character:
  >>> from mod import * >>> s 'Computers are useless. They can only give you answers.' >>> a [100, 200, 300] >>> printy <function printy at 0x03B449C0> >>> Classy <class 'mod.Classy'>
  This isn’t necessarily recommended in large-scale production code. It’s a bit dangerous because you’re entering names into the local symbol table en masse. Unless you know them all well and can be confident there won’t be a conflict, you have a decent chance of overwriting an existing name inadvertently.
  However, this syntax is quite handy when you’re just mucking around with the interactive interpreter, for testing or discovery purposes, because it quickly gives you access to everything a module has to offer without a lot of typing.
  from <module_name> import <name> as <alt_name>
  It’s also possible to
  import individual objects but put them into the local symbol table with alternate names:
  from <module_name> import <name> as <alt_name>[, <name> as <alt_name> …]
  This makes it possible to place names directly into the local symbol table but avoid conflicts with previously existing names:
  >>> a = ['abc', 'def', 'ghi'] >>>>> from mod import s as string, a as alist >>> a ['abc', 'def', 'ghi'] >>> s 'Hello There!' >>> string 'Computers are useless. They can only give you answers.' >>> alist [100, 200, 300]
  import <module_name> as <alt_name>
  You can also import an entire module under an alternate name:
  import <module_name> as <alt_name>
  Here’s what that looks like in practice:
  >>> import mod as my_module >>> my_module.a [100, 200, 300] >>> my_module.s 'Computers are useless. They can only give you answers.'
  Module contents can be imported from within a function definition. In that case, the
  import does not occur until the function is called:
  >>> def importer(): ... from mod import printy ... printy('Hello Everyone') ... >>> mod Traceback (most recent call last): File "<input>", line 1, in <module> mod NameError: name 'mod' is not defined >>> printy Traceback (most recent call last): File "<input>", line 1, in <module> printy NameError: name 'printy' is not defined >>> importer() arg = Hello Everyone
  However, Python 3 does not allow the indiscriminate
  import * syntax from within a function:
  >>> def importer2(): ... from mod import * File "<bpython-input-11>", line 1 SyntaxError: import * only allowed at module level
  Lastly, you can use a
  try statement with an
  except ImportError to guard against unsuccessful
  import attempts:
  >>> try: ... # Non-existent module ... import foo ... except ImportError: ... print('Module not found') ... Module not found >>> try: ... # Existing module, but non-existent object ... from mod import bar ... except ImportError: ... print('Object not found in module') ... Object not found in module
  gagejesse on Jan. 30, 2020
  I dunno how you managed to provide a thorough tutorial on exactly what I needed, two days before I needed it, but I certainly appreciate it. Thank you!