Tao of the Machine

Programming, Python, my projects, card games, books, music, Zoids, bettas, manga, cool stuff, and whatever comes to mind.

Ancient Python

For kicks and giggles, I uploaded the old Usenet posts containing the first public Python release (0.9.1). This version is from February 1991, and has little practical value, except as a curiosity and for studying Python's history. But I suspect that not too many people know of this release, and that it might be interesting to some.

(The zip file contains the original posts, which are shell archives. It's best that you unpack them yourself if you can; if not, download the unpacked source here (possibly faulty, since I'm not on Unix).)

0.9.1 wasn't so different from modern Python. Sure, there were a few quirks; the = operator was used for both comparison and assignment, and a class declaration had to be followed by () even if there were no base classes. Still, compare this piece of code from 1991:

class Set():
    def new(self):
        self.elements = []
        return self
    def add(self, e):
        if e not in self.elements:
            self.elements.append(e)
    def remove(self, e):
        if e in self.elements:
            for i in range(len(self.elements)):
                if self.elements[i] = e:
                    del self.elements[i]
                    break
    def is_element(self, e):
        return e in self.elements
    def size(self):
        return len(self.elements)

Except for the two differences mentioned above, and the peculiar new() method (which might have been the precursor of __init__? I'm not sure) this would work just fine in today's Python.

Or fibo.py (still works):

# Fibonacci numbers demo

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b <= n:
          print b,
          a, b = b, a+b

def fib2(n): # return Fibonacci series up to n
    ret = []
    a, b = 0, 1
    while b <= n:
          ret.append(b)
          a, b = b, a+b
    return ret

It comes with a 68-file standard library; not as much as today's, but still impressive for a first version. Some modules have been there since day one; calendar.py, for example, and fnmatch.py and getopt.py. (Especially interesting is a file called lambda.py. emoticon:devil)

It can be compiled with little trouble, too. (Hey, if *I* can compile it using DJGPP or whatever, anybody can.)

Enjoy!

Posted by Hans Nowak on 2003-07-17 20:31:14   {link}
Categories: Python

The importance of being selfish

Some people don't understand the usage of 'self' in Python OO. That's fine, many people initially don't, especially those who come from C++ or Java. However, even after reading the FAQ they not only still don't understand it, but they also spout nonsense about self "being added for backward compatibility" and "Python didn't start out as an object-oriented language".

'self' is not just a good idea, it's also necessary. Consider:

class Foo:
    def bar():
        x = 42

What does x = 42 mean here? Does it create a local variable x? Or does it set the instance attribute x? Hmm...

One could argue that you have to declare instance attributes first, then it will be clear what x is. Possibly, but that means that you cannot add attributes on the fly anymore.

One could argue that a statement like x = 42 in a method implicitly refers to the instance attribute. But if that is the case, how will we set a local variable with name x? You can't, at least not without inventing a scope operator or something similar.

One could argue that a statement like x = 42 should always refer to a local variable. If that is the case, how will we set the instance attribute x? Through 'self', maybe? :-) That's exactly what happens now. No ambiguity. Life is good.

Posted by Hans "Python isn't perfect, but this isn't a wart" Nowak on 2003-07-17 19:56:03   {link}
Categories: Python

We'll fix your problem... maybe

Great service from Alltel, my ISP/phone company. My DSL connection died earlier today, and they do... uhm... nothing!?

The guy on the phone said they would check their equipment, and if there wasn't a problem with that, they would call to make an appointment to send a "service engineer" or whatever. OK, it's 8:30 PM now, nobody called, and the problem still isn't fixed. Don't rush, guys, I only need this thing for my work, so take your time. emoticon:angry

I'm sure tomorrow they will send over some Bubba Joe who doesn't know !@#&$* about networks (like the guy who was supposed to install the DSL modem), so he can mess around with my computer and generally waste my time (because I'm pretty sure the problem isn't on my side).

Fortunately I still have my old earthlink account, that I should have cancelled months ago. It's kinda sad that I have to keep it because the DSL connection is unreliable.

Totally unrelated: In other news, plesiosaur fossils have been found near Loch Ness. ^_^

Also: Hmm, BeeOne vs BeeOne... who was first?

Posted by Hans Nowak on 2003-07-16 20:31:37   {link}
Categories: general

Thrown-away language ideas, part 1

My main problem with the Lisp/Scheme family of languages is that my brain isn't so suited to grok deeply nested expressions. (Apparently I'm not the only one, or we would all be programming in Lisp.)

So, what about a language that breaks up the nested expression into easily manageable parts? Let's say that a function's body consists of a list of named expressions, of the form

name: expr

For example:

function average a b
    sum: + a b
    result: / sum 2
end

When evaluating an expression like average 1 10, we evaluate the sub-expression result, which causes us the evaluate sum also. So far, so good.

It doesn't look so pretty and readable anymore for longer functions, though:

function factorial n
    zero?: = 0 n
    default: 1
    n-1: - n 1
    prev-factorial: factorial n-1
    otherwise: * n prev-factorial
    result: if zero? default otherwise
end

This becomes a bit of a mess. Things like n-1 have to have their own sub-expression, which is silly. factorial isn't an extremely long function. What will a more complex function look like? It will be unreadable because of the sheer length of its expression list. Sigh. Can't win for losing.

Needless to say, I didn't proceed with this language.

Still, I'm looking for something that is elegant *and* readable. Python is the closest thing I've found so far. The Lisp languages are (arguably) more elegant, but their strength is also their weakness. Hmm. What about Haskell?

Posted by Hans Nowak on 2003-07-15 11:20:01   {link}
Categories: programming

A backup script for spambayes

A few days ago I had some problems with spambayes after the power went off... the database was corrupt. Since power outages happen almost daily in Florida during some periods, I decided that it was a good idea to make a daily backup of the database files.

Here's how to set things up so that this daily backup happens automatically. On Windows, that is. As with my simple FTP upload script, the assumed level is somewhere between newbie and advanced. (I'm using Python 2.2.2, but it probably works with older versions as well, by the way.)

1. Save the following script, bayesbackup.py, in c:\python22\scripts:

# bayesbackup.py

import calendar
import os
import shutil
import time

SOURCE_DIR = "c:/python22/scripts"
TARGET_DIR = "c:/python22/scripts/spambayes-backup"

if not os.path.exists(TARGET_DIR):
    os.makedirs(TARGET_DIR)

FILES = [
    'hammie.db',
    'hammie.db.dat',
    'hammie.db.dir',
    'spambayes.messageinfo.db',
    'spambayes.messageinfo.db.dat',
    'spambayes.messageinfo.db.dir',
]

year, month, day = time.localtime(time.time())[:3]
weekday = calendar.weekday(year, month, day)
suffix = "~%d" % (weekday,)

for file in FILES:
    sourcename = os.path.join(SOURCE_DIR, file)
    targetname = os.path.join(TARGET_DIR, file+suffix)
    print "Copying:", file, "...",
    if os.path.exists(sourcename):
        shutil.copyfile(sourcename, targetname)
    print "OK"

(I'm not sure all those files are needed, by the way. But better safe than sorry...)

2. Replace the values for SOURCE_DIR and TARGET_DIR with the directory that contains your spambayes database files, and the directory where you want to store the backups.

3. Start the Windows task scheduler. In 8 years of Windows usage, I've *never* used this thing before, so don't feel embarrassed if you don't know where it is. ;-) It's at Programs -> Accessories -> System Tools -> Scheduled Tasks. Double-click it, and add a new task.

Point the file browser to c:\python22\scripts\bayesbackup.py (or wherever you stored the script).

In the next screen, select "Daily". (This script was written to make daily backups. If you want more/less frequent backups, you'll have to change the code.)

Add a convenient time, when you can be certain that your computer is on. (I chose 12:01 PM.)

Finally, enter your username and password.

4. Now, every day, at the desired time, the script will run. For every weekday, it makes a different backup; the backup filenames are the same as the original files, *plus* a suffix ~x, where x is a digit indicating the day of the week; 0 for Monday, 1 for Tuesday, etc. In other words, when the script runs on a Monday, it will create backup files hammie.db~0, hammie.db.dat~0, etc. The next day, backups with suffix ~1 will be created, etc. This way, if a backup messes up, you'll still have some of previous days. (If you accidentally backup corrupt files, you just restore those from the previous day.)

5. If you don't want the console window to appear, rename the file to bayesbackup.pyw before adding it to the schedule.

6. To "restore" the backups, simply copy the files of a given day to the spambayes directory, and remove the ~x suffixen.

Posted by Hans "rotating backups leichtgemacht" Nowak on 2003-07-14 22:29:46   {link}
Categories: Python

New stuff

Some new features in my pet projects. Downloads should be available soon, at least for some of these.

  • Sextile now supports the \option "tag". The first option is soft_line_breaks, which, if set, doesn't insert <br> tags for single line breaks.

  • Firedrop2 entries can now have the publish attribute, which is 1 by default; if set to 0, that entry doesn't show up on web pages, archives or RSS. (I'm currently still testing this.)

  • Also Firedrop2: If the site's blogping attribute is set, then blo.gs and weblogs.com are pinged after (successful) uploading. (Or so I hope. :)

  • Charm now has some support for Scheme files. Extension .sc is assumed. There is some syntax highlighting. To be added: matching of braces.

Charm and Firedrop2 are currently not available for download here, but they should be soon. The usual disclaimers will apply.

Posted by Hans "Real Soon Now" Nowak on 2003-07-13 20:18:27   {link}
Categories: Python

Studying SICP

Doing a SICP reread... (the paper version, not the online one) Scheme is sure a beautiful language. (Whether it's *useful* or *readable* is something else entirely.)

So far (I'm on page 62), everything can be done in Python as well (but it wouldn't have been possible in languages like Pascal, C or Java). I'm not sure how useful it is to translate the Scheme code to Python, though... one could wonder, is the book meant to illustrate programming concepts, or to illustrate Scheme? Probably both, but the implementations they show require a Lisp-like language. If you translate the code to a less expressive language, you lose important insights. Much like translating the Tao Teh Ching, I guess... ^_^

(I do not have a strong math or computer science background, so some parts of SICP were quite difficult/boring for me, upon the first reading. Let's see if I have learned anything...)

Posted by Hans Nowak on 2003-07-12 20:18:24   {link}
Categories: programming

--
Generated by Firedrop2.