10 Example: When objects are useful

I don't have a lesson for today -- I'm going to declare the
beginners' course officially over. But that doesn't mean we can't
still have some wrap-up discussion -- any questions you have about
writing Python programs, techniques or modules you're curious about, etc.
If we get into any in-depth continuing discussion, we can always
move it to techtalk or the programming list.

I loved seeing the practical scripts in response to last week's
homework that solved real-life problems. And last week I had one
too -- and it turned out to be a great example of when it's useful
to make a class. Funny, when I was writing the object-oriented
lesson I couldn't think of a practical example, then just a few
weeks later a perfect example appears.

What I was trying to do was list recent podcasts. I use a program
called podget that's great at deciphering podcast websites and
downloading the episodes I haven't downloaded yet. What it isn't great
at is telling me which episodes are new so I can copy them to the
mp3 player. I've been managing that by hand with ls -lt and
a lot of doubleclick-and-paste, but I wanted to automated it.

It was easy enough to get the list of all my downloaded podcasts:

cmd = "find %s -type f" % dir
fp = os.popen(cmd)
for file in fp :
file = file.strip()
if file.endswith(".mp3") :
# it's a podcast file, do something with it

But I wanted to sort them by date. Python lists have a sort()
method -- but I needed to make a list of filenames, then sort
them by date, not by filename. A great way to do that is to make
a class, PodcastFile, that has both the filename and the date.

Now, if I make a list of PodcastFile objects, I can't sort it
unless I tell Python how to compare them -- when is a PodcastFile
"less than" or "greater than" another PodcastFile?

Well, a cool thing about Python objects is that you can override
basic operators like < or >. So I made my class like this:

class PodcastFile :
"""A podcast .mp3 file with its last-modified date"""
def __init__(self, path) :
self.pathname = path
self.mtime = os.path.getmtime(path)

def __lt__(self, other) :
return self.mtime < other.mtime

def __gt__(self, other) :
return self.mtime > other.mtime

Now, if I initialize two PodcastFile objects:

file1 = PodcastFile("/home/akkana/POD/Science/Radiolab/radiolab071111.mp3")
file2 = PodcastFile("/home/akkana/POD/Humor/Wait_Wait/npr_139053390.mp3")

then whenever I say

if file1 < file2 :

it's the same as calling file1.__lt__(file2). So my __lt__ function
will compare the two files' last-modified times and tell me if file1
is older than file2.

And the sort() function calls __lt__. So now I can make a list of
podcast files and sort them:

for file in fp :
file = file.strip()
if file.endswith(".mp3") or file.endswith(".m3u") :
podcasts.append(PodcastFile(file))
fp.close()

# Now podcasts is a list of all PodcastFiles. Sort by date:
podcasts.sort()

and I have my list of podcast files sorted by date, and I can print
them out, or copy them to my mp3 player (there's a module called
shutil that's good for things like file copies).

The full script is at http://shallowsky.com/software/scripts/pods

So that's a great use for object-oriented programming: making sorted
lists sorted by anything you want.

Anybody do any fun or interesting Python hacking recently?
Or have any Python questions?