How should a Python module be structured?
<p>This is my first time posting on stack overflow, so I apologize if I do something wrong.</p>

<p>I am trying to understand the best way to structure a Python module. As an example, I made a backup module that syncs the source and destination, only copying files if there are differences between source and destination. The backup module contains only a class named Backup.</p>

<p>Now I was taught that OOP is the greatest thing ever, but this seems wrong. After looking through some of the standard library source, I see that most everything isn't broken out into a class. I tried to do some research on this to determine when I should use a class and when I should just have functions and I got varying info. I guess my main question is, should the following code be left as a class or should it just be a module with functions. It is very simple currently, but I may want to add more in the future.</p>

<pre><code>"""Class that represents a backup event."""

import hashlib
import os
import shutil

class Backup:
    def __init__(self, source, destination):
        self.source = source
        self.destination = destination

    def sync(self):
        """Synchronizes root of source and destination paths."""

        sroot = os.path.normpath(self.source)
        droot = os.path.normpath(self.destination) + '/' + os.path.basename(sroot)

        if os.path.isdir(sroot) and os.path.isdir(droot):
            Backup.sync_helper(sroot, droot)
        elif os.path.isfile(sroot) and os.path.isfile(droot):
            if not Backup.compare(sroot, droot):
                Backup.copy(sroot, droot)
        else:
            Backup.copy(sroot, droot)

    def sync_helper(source, destination):
        """Synchronizes source and destination."""

        slist = os.listdir(source)
        dlist = os.listdir(destination)

        for s in slist:
            scurr = source + '/' + s
            dcurr = destination + '/' + s

            if os.path.isdir(scurr) and os.path.isdir(dcurr):
                Backup.sync_helper(scurr, dcurr)
            elif os.path.isfile(scurr) and os.path.isfile(dcurr):
                if not Backup.compare(scurr, dcurr):
                    Backup.copy(scurr, dcurr)
            else:
                Backup.copy(scurr, dcurr)

        for d in dlist:
            if d not in slist:
                Backup.remove(destination + '/' + d)

    def copy(source, destination):
        """Copies source file, directory, or symlink to destination"""

        if os.path.isdir(source):
            shutil.copytree(source, destination, symlinks=True)
        else:
            shutil.copy2(source, destination)

    def remove(path):
        """Removes file, directory, or symlink located at path"""

        if os.path.isdir(path):
            shutil.rmtree(path)
        else:
            os.unlink(path)

    def compare(source, destination):
        """Compares the SHA512 hash of source and destination."""

        blocksize = 65536
        shasher = hashlib.sha512()
        dhasher = hashlib.sha512()

        while open(source, 'rb') as sfile:
            buf = sfile.read(blocksize)
            while len(buf) &gt; 0:
                shasher.update(buf)
                buf = sfile.read(blocksize)

        while open(destination, 'rb') as dfile:
            buf = dfile.read(blocksize)
            while len(buf) &gt; 0:
                dhasher.update(buf)
                buf = dfile.read(blocksize)

        if shasher.digest() == dhasher.digest():
            return True
        else:
            return False
</code></pre>

<p>I guess it doesn't really make sense as a class, since the only method is sync. On the other hand a backup is a real world object. This really confuses me.</p>

<p>As some side questions. My sync method and sync_helper function seem very similar and it is probably possible to collapse the two somehow (I will leave that as an exercise for myself), but is this generally how this is done when using a recursive function that needs a certain initial state. Meaning, is it ok to do some stuff in one function to reach a certain state and then call the recursive function that does the actual thing. This seems messy.</p>

<p>Finally, I have a bunch of utility functions that aren't actually part of the object, but are used by sync. Would it make more sense to break these out into like a utility submodule or something as to not cause confusion?</p>

<p>Structuring my programs is the most confusing thing to me right now, any help would be greatly appreciated.</p>

<p>This method (and several others) is wrong:</p>

<pre><code>def copy(source, destination):
    """Copies source file, directory, or symlink to destination"""
</code></pre>

<p>It works the way it was used (<code>Backup.copy(scurr, dcurr)</code>), but it does not work when used on an instance.</p>

<p>All methods in Python should take <code>self</code> as the first positional argument: <code>def copy(self, source, destination)</code>, or should be turned into <code>staticmethod</code> (or moved out of the class).</p>

<p>A static method is declared using the <code>staticmethod</code> decorator:</p>

<pre><code>@staticmethod
def copy(source, destination):
    """Copies source file, directory, or symlink to destination"""
</code></pre>

<p>But in this case, <code>source</code> and <code>destination</code> are actually attributes of <code>Backup</code> instances, so probably it should be modified to use attributes:</p>

<pre><code>def copy(self):
    # use self.source and self.destination
</code></pre>

python