See: https://docs.python.org/3/tutorial/modules.html

Scripts

A script is what you create when you use a text editor and write some code in a .py file and run that file with the input instead of typing it all out inside an interactive session.

Modules

A module is a file that has some definitions and can be used in a script or an interactive instance of the interpreter. It’s useful when you want functions from one script in another. This file can be imported into other modules or into the main module. So a module is a file containing python definitions and statements. The file name is module.py and the module’s name as string is available as the value of the global variable __name__. Using a module name later and accessing functions inside it can be done as module.function. Modules can also import other modules (ex. import os).
We can also use the keyword as after a module name to import it as something else. (For namespace internals please refer to the docs page linked.)

You can execute a module as a script using python module.py <arguments>.

The dir() function is useed to find out which names a module defines. It returns a sorted list of strings. dir() does not list names of built-in functions and variables. If you want a list of those, they are defined in the standard module builtins.

ex., try this out in an interactive session for example:

import builtins
dir(builtins)

Packages

Packages are a way of structuring Python’s module namespace by using dotted module names. The module name A.B designates a submodule named B in a package named A. The use of dotted module names saves the authors of multi-module packages like numpy or pillow from hacing to worry about each other’s module names.

Suppose a collection of modules need to be designed for the uniform handling of sound files and sound data. There are many different sound formats so you may need to create and maintain a growing collection of modules for the conversion between different formats. There are also many different operations to be performed on sound data. Here’s a possible structure of your package in the form of a heirarchal filesystem:

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py

The __init__.py files are required to make python treat directories containing the file as packages. This prevents directories with a common name, such as string from unintentionally hiding valid modules that occur later on the module search path (python searches through the directoriess on sys.path looking for the package subdirectory). In the simplest case, __init__.py can be an empty file. but it can also contain initialization code for the package or set the __all__ variable (see docs, in short it controls how import * is performed).

Use of the package can import individual modules from the package:

import sound.effects.echo
# or
from sound.effects import echo