Archive for May, 2008

list(dict)

The other day there was a thread on comp.lang.python that started off by discussing a common problem: deleting keys from a dict while iterating over it causes an exception. In other words, the following code fails:

>>> d = {1: 2, 3: 4, 5: 6}
>>> for i in d: del d[i]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

This is easily solved by replacing for i in d with for i in d.keys(). The former iterates over the keys one by one, while the later creates a list of keys first, then iterates over *that*; the list does not change during the loop or after deleting keys from the dictionary, so the error above does not occur.

However. In Python 3000 this is going to change. d.keys() will then return an iterator, and effectively produce the same result as for i in d; that is, an exception. This can be solved (in both 2.5 and 3.0) by forcing a list; e.g. for i in list(d.keys()).

Then someone pointed out that this can be written as for i in list(d) as well. I had not given this much thought before, but this would work as well, of course. It's just that list(d) strikes me as very counter-intuitive. I mean, it makes sense, in a way; if you can iterate over a dictionary's keys by doing for i in d, then list(d) would do just that: iterate over the keys, collect them in a list, and return that list. Except that list(d) kind of reads to me as, "convert a dictionary to a list", which is not what it does. The reverse operation does not work because of this; dict(list(d)) doesn't fly. Maybe iterating over a dictionary's items would have been a better choice, after all. :-/

:: Comments

Python 3000 in 60 seconds

After studying the relevant PEPs and other documents, I've come to the following conclusions:

  • Python 3000 used to be the mythical, revolutionary new release, implemented from scratch (possibly in C++), that would solve all of Python's problems, and then some.
  • However, over time, features that were originally intended for Python 3000 were added to the 2.x branch instead. (Actually, many of these were more like cleanups than new features. Fixing the class/type dichotomy, nested scopes, unifying longs and ints, division operator, etc.)
  • So, in 2008, Python 3000 is not quite so revolutionary anymore, compared to 2.5. As PEP 3000 says, "Python 3000 will be implemented in C, and the implementation will be derived as an evolution of the Python 2 code base. [...] Since Python 3000 as a language is a relatively mild improvement on Python 2, we can gain a lot by not attempting to reimplement the language from scratch."
  • In spite of that, Python 3000 is still special, because it introduces a number of changes that will break backward compatibility. Again, many of these deal with the fixing of warts and inconsistencies. For example: print will become a function; as and with will be keywords, and so will True, False and None; some functions (like map) now return iterators rather than lists; exception handling is different; etc. More here. (I will probably write about some of these changes in more detail later.)
  • Don't count on changes that will change the face of Python completely: explicit self and limited lambda are here to stay, not to mention indentation-based syntax and case sensitivity. (See PEP 3099.)

:: Comments (3)

A really simple personal bug tracker, using just the Unix shell

When working on my personal projects, I find that I often get overwhelmed with ideas and possibilities, causing me to lose track of what needs to be done first, what is important, etc. Some kind of bug tracker would be helpful, except most of them are overkill for my purposes, IMHO. Also, they tend to be platform-dependent (whereas I tend to develop on multiple operating systems) or web-based (and I don't always have internet access). So, I started looking for something Really Simple.

As it turns out, the following is sufficient for my needs:

  • store bugs/ideas as simple text files;
  • use a Unix shell (or similar) to manipulate these files.

Again, this is for *personal* bug tracking. I don't work with other people on these projects. Also, I don't need fancy reports, or a polished user interface. It is meant to be extremely simple.

Anyway, so I thought I'd share this. (Feeble disclaimer: The idea probably isn't new. Hell, maybe it's decades old; if so, I still find it useful.)

This is how it works:

Filenames look like xxxxyz, where xxxx is the number of the item, y is a letter indicating the status (like "o" for open and "c" for closed), and z is a digit indicating the priority. For example, a filename might look like 0007o2, which tells us that this is item #7, it's currently open, and has priority 2.

You add a new item simply by looking at the last number used, and creating a new file with that number plus one, and the desired priority, in your favorite editor. In other words, if I have 27 bugs in my directory, then I create the next one by doing vim 0028o3, or something like that. (I figure you could write a script for this, or maybe it's a one-liner given the right tools... but it seems like overkill when all you need to figure out the next number is ls.)

These files are just text files. They don't have a special format, *except* that the first line should be the title, or a summary of the item. Anything after that has no special meaning. (The reason for this will become clear soon.)

Now, we are ready to unleash the awesome power of the Unix shell onto these files! :-)

Show all open/closed bugs:

$ ls *o*
$ ls *c*

Show a specific bug:

$ cat 0024<Tab><Enter>
# or open it in an editor, of course

Show the number of open bugs:

$ ls -l *o* | wc -l

Show the summaries of all open bugs with priority 1:

$ head -1 *o1

(This is why it's useful to have the title on the first line... head -1 will display just the title. If there are multiple files matching the "*o1" pattern, head will display the names of the files as well.)

Search bugs for the text "refactoring":

$ ack -ui refactoring *
$ grep -i refactoring *

(I use the ack tool, but grep works as well.)

List complete entries for all open bugs with priority 1:

$ head -h 1000 *o1

(Assuming no file has more than a thousand lines. If it does, maybe it's time to split it up...)

Changing status/priority is just a rename:

$ mv 0024o1 0024o2

# or, when files are in svn:
$ svn mv 0024o1 0024o2 --force

Notes:

1. Naturally, you can change the filenames to suit your needs and preferences. I use priorities 1-5, where 1 is the most urgent, but one might well use 1-3 or 1-9, etc. Similarly, there could be more status indicators than just "o" and "c". There could be additional indicators for the type of item (bug, idea, feature), and so on.

2. When I say "Unix shell", I really mean an environment that is similar to sh. Linux and OS X have actual Unix shells; Windows has Cygwin, but in a pinch, 4NT could be used as well (or these days it's Take Command).

:: Comments (2)

ViewIt

As it happens, I have a few (*cough*) manga scanlations laying around on CD-ROMs. These are usually in the form of a directory with a bunch of JPG files in it.  In order to read these volumes comfortably, an image viewer with certain capabilities is necessary.  On Windows, I used ACDSee, which allows me to view images full-screen, then press PgUp or PgDn to go to the previous/next image.

For the Mac, I have now finally found a program that has most of the features I need. It's called ViewIt (and it's shareware).  Some of the features I find very useful are:

  • Drag a folder to the ViewIt window to make the program "aware" of the folder; it will display the first image found.
  • Use ⌘1 to display the image at its original size (100%).  This is important because fitting the image to the screen width often renders the smaller text unreadable.
  • Use ⌘F to display the image full-screen (rather than in a window).  I've found that quite a few image viewers don't support this feature and the previous one *at the same time*. That is, you can view the image at 100% in a window, or cropped full-size.  Fortunately, ViewIt supports both.
  • The above means that most images will be larger than the screen, so the ability to scroll (especially up and down) is crucial.  In ViewIt, this is done with Ctrl+cursor.
  • Cursor left and right goes to the next/previous image.

All these features sound simple, but they're almost mandatory for reading scanlations in a pleasant manner, yet rarely do image viewer support all of them. At least, that is my experience. A while ago, I tested quite a few, and found all of them lacking in one way or another. :-(

(Of course, if you happen to know about another image viewer for OS X that does all the above, I'd like to hear about it. ^_^)

:: Comments

Software Hero

This actually seems like a good idea. (Well, the first paragraph, anyway. :-)

:: Comments