Python vs. Ruby

There is a discussion on the net where people discuss Python vs. Ruby. The Ruby and Python Compared article started it, and here is a good answer article: Ruby misconceptions about Python.

I have both tried Python and Ruby and the languages are very alike, but yet a lot different. Python is more explicit - this gives clarity and more code.

An example of this clarity:

On Reddit a Ruby programmer posted some code that made building XML easy:

def method_missing(name, attributes)
  atts = attributes.map {|k,v| "#{k}='#{v}'" }.join(" ")
  puts "<#{name} #{atts}>"
  yield
  puts "</#{name}>"
end

With that special method one can do following:

div :id => "content" do
  a :href => "reddit.com" do
    print "reddit"
  end
end

I wrote something similar in Python:

import types
class Element:
  def __init__(self, **kw):
    self.elms = []
    self.kw = kw
  def __getattr__(self, name):
    if name == "__getitem__":
      self.elms = []
      def add(l):
        if type(l) == types.ListType: self.elms.extend(l)
        else: self.elms.append(l)
        return self
      return add
  def __str__(self):
    attrs = " ".join('%s="%s"' % a for a in self.kw.items())
    self.html = ["<%s %s>" % (self.name, attrs)]
    self.html.append("".join(map(str, self.elms)))
    self.html.append("</%s>" % self.name)
    return "".join(self.html)
class Div(Element): name = "div"
class A(Element): name = "a"

Where one can do:

print Div(id="content")[ A(href="reddit.com")["reddit"] ]

Functionality similar, but the way of achieving it is way different. Notice that in the Ruby case the "div" and "a" aren't defined and there is a lot of magic going on. In my Python code everything is defined explicitly. This approach gives a little more code, but better understanding. And that I think is the main difference between Python and Ruby.

Update

I have redone my Python version (functional style):

def elmBuilder(name, **kw):
  attrs = " ".join('%s="%s"' % a for a in kw.items())
  def applyElms(*elms):
    return "<%s %s>%s</%s>" % (name, attrs, "".join(elms), name)
  return applyElms
def Div(**kw): return elmBuilder("div", **kw)
def A(**kw): return elmBuilder("a", **kw)

One can then do:

print Div(id="content")( A(href="reddit.com")("reddit") )

My picnic in Lisp was well spent ;-)

Code · Python 13. Apr 2006
10 comments so far

Better understanding? I can see what the Ruby code does at a GLANCE, whereas the Python code requires closer inspection... If you think the Python code is easier to understand, clearly, the difference is mainly in taste.

Hi Tomas

I wouldn't argue that my first Python code is more readable than the Ruby code. I am just trying to state that one can track down things in Python - and this can give better understanding and clarity (at least for me).

But you are right that taste plays a big role in what is more readable :)

Amir,

Thanks for the interesting comparison. You seem to believe that Python hits a "sweet spot" between Ruby's elegant conciseness and Java's verbose explicitness, is that right?

Hi Rubinelli

Interesting question. A lot of people see Python's explicitness as a bug [especially the Ruby people], but in reality it's a future. My point is that it's there for a reason, and one can either love it or hate it. Personally I love the explicit approach, even if I have to write a bit more code.

Hey, but on the Ruby version you don't have to declare A and Div .
What happens when you want to add more tags??
The Ruby version still works, on the Python one you have to declare each tag you are going to use.

What?? that on Python, because you have to explicitely declare the tags, you aren't going to have typos ??
Ok, you can have that on the Ruby version by declaring a list of all the tags you want as valid, and add an IF.

Hi tizoc

One could just rename elmBuilder to elm and use this approach:

elm("b", id="blah")("Text")

That's pretty clean IMO. Else one could use __getattr_ which can act like method_missing. So you get something like this:

class Builder:
  def __getattr__(self, name):
    def a(**kw):
      return elmBuilder(name, **kw)
    return a
b = Builder()

print b.div(id="cow")( b.p(style="color: red")("This is a test") )

Point: Python's explicitness doesn't mean it can't do the same polymorphic things like Ruby...

Ok, I like the new aproach better than your original one ;)
But I still like the Ruby one better... to me, it looks "cleaner"

It isn't because I'm a Ruby fan or something, I'm not, if anything, I'm a Scheme fan, that likes Ruby a little more than Python :P

Scheme fan eh? :]

Anyway, I hope my post doesn't make it look like I only use Python because of it's explicitness - I don't, I just argue that it isn't a weakness :)

To improve the clarity of the Python example, try using a backslash ("\") to combine the physical lines into one logical statement, like so:

 div (id="content") \
    (a (href="reddit.com") \
        ("reddit"))

Its similarity to Lisp is spooky. ;-)

P.S. This is also a good example of the murky area where Python doesn't care about whitespace or indentation, since the 2nd and 3rd lines are really just an extension of the first line and not expressions or statements by themselves.

While a competent programmer in either language could produce elegant code that does the same thing as its programing language counterpart (at least when comparing these two particular languages), to me the advantage of Python is the design of 'no wasted pixels.' I.E. No need to explicitly type "end" to end the scope of a function, etc. (Frankly I'd rather have the C style brackets than syntax that reminds me of BASH madness)

About the backslash trick Jason Huggins suggested -- it has its place for long lines that can not easily be broken into more than one line. But one should be wary to avoid it when possible. It can lead to situations where debugging becomes a pain. You are escaping the newline character with the backslash, if you happen to put a space (or any other whitespace character) between the slash and the newline you will be escaping the other character.

Post a comment
Commenting on this post has expired.
© 2000-2009 amix. Powered by Skeletonz.