Python vs. Ruby?

For a couple years now, I’ve been a big Python fan. I’ve been using Ruby at work for the past month or so, and it’s beginning to grow on me. At first, I didn’t like that there were multiple ways to do one thing, often with only slightly nuanced differences. For instance, the .length, .size, and .count methods on enumerables perform essentially the same function, but apply in different ways. Similarly, STDERR, $stderr, and ARGF all refer to standard error. I also thought that optional parentheses around function arguments and question marks and exclamation points in method names were strange.

But now that I’ve used Ruby a little more, I’m beginning to like certain constructs and missing them when I write Python. The following idiom (rather reminiscent of Perl), which prints lines from stdin is kind of fun, even though it’s a little ugly:

while gets
  puts $_.strip
end

What I really like about Ruby, though, is the extra support it has for functional programming. Python has filter, map, reduce and nice list comprehensions, but certain Ruby statements return values when Python ones don’t, making functional things more difficult to write. For example, iterating over a list of tokens and producing a hash of the count of the occurrence of each token can be accomplished with the following:

foo_list.inject(Hash.new(0)) do |hash, item|
  hash[item] += 1
  hash
end

Hash.new(0) creates a hash that returns 0 for keys that don’t already exist in the hash, making this an ideal data structure for counting frequencies of objects. inject is Ruby’s reduce. Ruby allows multiline “code blocks”, which are anonymous functions. The line “hash” returns the updated hash after each iteration of “inject”. (Ruby functions and code blocks treat the last statement as a return without needing an explicit return keyword.)

In contrast, Python’s dictionary[item] += 1 does not return anything, so to implement something similar, we have to either do it with an explicit loop, or write a class whose increment method returns itself:

from collections import defaultdict

class FooDict:
    def __init__(self, init):
        self.hash = defaultdict(lambda: init)

    def increment(self, key, incr):
        self.hash[key] += incr
        return self

reduce(lambda hash, item: hash.increment(item, 1), foo_list, FooDict())

which is considerably less elegant.

If you know of a better way to do this, please let me know!

Advertisements

One thought on “Python vs. Ruby?

  1. I’m a little late to this post, but I wrote about a class (http://www.goodmami.org/2012/02/accumulating-dictionaries-in-python/) where you can define the behavior for key collisions, thus allowing the following:


    token_counts = AccumulationDict(operator.add, [(token, 1) for token in corpus])

    (I hope the html tags worked)

    Without that class, if you want to avoid for-loops, here’s (an ugly) one with reduce:

    reduce(lambda d, k: d.update([(k, d.get(k, 0) + 1)]) or d, corpus, {})

    And here’s one with map (which is rather inefficient):

    dict(map(lambda k: (k, corpus.count(k)), set(corpus)))

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s