Gross Anatomy: Python's Structure

By Ryan Wiles

Files in Python

The Python Shell with its REPL Session provides a convenient way to try out code and experiment with the language. However, when you leave your shell you also will lose any code that you’ve entered in that session.

When you’re working on something more than just a quick one-off, you’ll probably want to save your work and be able to load and run it again later. You can do this by putting your Python code in a text file with a “.py” extension.

Python files can be broken down into two broad categories called Scripts and Modules. Generally speaking, a file that’s intended to be directly executed is called a script, while one that contains reusable code you want to include is called a module. We’ll clarify this distinction below.

Scripts

Let’s create a simple Python script using one of our Fibonacci examples.

  1. Create a file called fibscript.py
  2. Copy the following following code into fibscript.py

     def fib(n):
       return n if n < 2 else fib(n-1) + fib(n-2)
    
     for i in range(10):
       print("fib(" + str(i) + ") = " + str(fib(i)))
    
  3. Running the Script by calling Python

     python3 fib.py
     fib(0) = 0
     fib(1) = 1
     fib(2) = 1
     fib(3) = 2
     fib(4) = 3
     fib(5) = 5
     fib(6) = 8
     fib(7) = 13
     fib(8) = 21
     fib(9) = 34
    
  4. Making the Script Executable

    To make your Python file easily executable, there are a couple of more steps. First, we need to add a special line to the start of the file called a shebang line. This allows UNIX style operating systems to know which interpreter to use to run the file. Add the following as the first line in your fibscript.py file.

     #!/usr/bin/env python3
    

    Note: It’s considered good practice to leave a blank line after the shebang line.

    Your entire fibscript.py file should now look like this:

     #!/usr/bin/env python3
    
     def fib(n):
       return n if n < 2 else fib(n-1) + fib(n-2)
    
     for i in range(10):
       print("fib(" + str(i) + ") = " + str(fib(i)))
    

    The shebang line’s name comes from the prefix “#!” which is pronounced shebang. When you attempt to execute a file through a shell, the shell invokes one of the exec functions to attempt to execute the file. The exec functions will look for the shebang at the beginning of the file and if found will consider the rest of that line to specify the interpreter required to run the file. exec will then call the interpreter passing it the path to the file. In the example above, we’re specifying that the /usr/bin/env utility be called with the python3 as the interpreter. The env utility will then search the PATH environment variable for the first python3 executable and run it. This is comparable to us using:

     #!/usr/local/bin/python3
    

    Which would also work, but by calling the env utility the portability of the script is improved since it doesn’t presume the path location of the python3 interpreter in the environment. Since lines starting with a # are considered to be comments by Python, we can still run this file manually through Python without issue since Python will ignore the shebang line as a comment.

    Next, we need to make fibscript.py executable. To do that run the following command:

     chmod u+x fibscript.py
    

    Now, let’s try executing it.

     $ ./fibscript.py
     fib(0) = 0
     fib(1) = 1
     fib(2) = 1
     fib(3) = 2
     fib(4) = 3
     fib(5) = 5
     fib(6) = 8
     fib(7) = 13
     fib(8) = 21
     fib(9) = 34
    

Modules

Python modules are also single “.py” files, but are generally written with a different intention than scripts. While scripts are generally designed to be executed in a standalone fashion, modules are generally intended as a way to let you organize and consolidate reusable sections of code in a hopefully logical fashion. Let’s go ahead and do a quick module example using our Fibonacci method.

  1. Create a file called fibmod.py containing the following:

     def fib(n):
       return n if n < 2 else fib(n-1) + fib(n-2)
    
  2. Now we’ll create a showfib.py script with the following:

     #!/usr/bin/env python3
    
     import fibmod
    
     for i in range(10):
       print("fib(" + str(i) + ") = " + str(fibmod.fib(i)))
    
  3. Make showfib.py executable.

     chmod u+x showfib.py
    
  4. Finally, let’s run showfib.py

     $ ./showfib.py
     fib(0) = 0
     fib(1) = 1
     fib(2) = 1
     fib(3) = 2
     fib(4) = 3
     fib(5) = 5
     fib(6) = 8
     fib(7) = 13
     fib(8) = 21
     fib(9) = 34
    

Modules can also contain executable statements which are typically used for performing any necessary initialization steps needed in the module. So technically, you could run a module as a script, but it’s usually best to keep that functionality separate.

Packages

At their simplest, a Python Package is merely a directory with a one or more modules and an __init__.py file, which can be empty. The __init__.py file tells Python that the directory is a Package and can be imported. We’re going to cover creating and bundling packages in later tutorials.

Python Package Structure Image from: A Simple Guide for Python Packaging

PYTHONPATH

Showing Python’s Module Search Path:

import sys

sys.path

References

© 2018 Ryan Wiles