Packages

I have always found organizing python across functions to be a bit confusing. Luckily, this tutorial really helped me figure it out. Despite them doing a really excellent job explaining things, I am going to put this into my own words.

Let's start with the most basic of organizing principles: the module.

Modules

Modules are a single python file that can contain multiple functions (or classes). First, let's create a folder and within it, let's have two python files— one with a script called "test.py" and one with our modules called "funks.py".

Our directory should be look like this:

root
├── test.py
├── funks.py

In our funks.py file, lets add two silly little functions:

def hello():
    return "hello"

def goodbye():
    return "goodbye"

We can now import the functions in funks.py into our test.py file like so:

import funks

funks.hello()

Packages

Note: in common usage, a python package often refers to a distribution package but that's not what I am referring to here.

A python package is a directory that can have any number of .py files containing code within it (including none at all). However, all python packages must have a __init__.py file. This special file is also called a dunder init file.

Let's create our python package by creating a directory called "pack" and putting a __init__.py file within it:

pack
└── __init__.py

Next, place this in the root folder of your project:

root
├── test.py
├── funks.py
├── pack
│   └── __init__.py

So far, our package does nothing. Let's fix that.

You can put our functions from funks.py into that __init__.py file and then import them the same way as if you were just using a module.

So in __init__.py put:

def hello():
    return "hello"

def goodbye():
    return "goodbye"

And then to use those functions, you would do:

import pack

pack.hello()

Organizing a Package

Let's say that we wanted to have files specific to each function— one for goodbye and one for hello.

We are allowed to do this. You will not be arrested for any python crime. Simply move the functions from the __init__.py into their own files, creating the below directory structure:

root
├── test.py
├── funks.py
├── pack
│   └── __init__.py
│   └── hello_func.py
│   └── goodbye_func.py

If you don't add anything to __init__.py than importing the functions will be a mess. You have to do something like the following:

import pack.hello_func

pack.hello_func.hello()

This kinda sucks. Instead you can add a little convenient way to interface with your functions to the __init__.py:

from .hello_func import *
from .goodbye_func import *

Then you just have to do the following to import them:

import pack

pack.hello()