Python vs Ruby

From Exterior Memory
Revision as of 15:58, 22 March 2012 by MacFreek (Talk | contribs) (Created page with "A lot has been written comparing the Python versus Ruby languages. For no particular reason I'm just adding a few more lines about it. ==The Commonalities== Python and Ruby ...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

A lot has been written comparing the Python versus Ruby languages. For no particular reason I'm just adding a few more lines about it.

The Commonalities

Python and Ruby have much in common. Both are modern languages with all the modern requirements:

  • Namespaces
  • Garbage collection
  • Object Oriented
  • Exception Handling
  • Proper Unicode support (Ruby 1.9 and up; Python 3 and up)

What's more, they both

  • are Interpreted (scripting) languages
  • are Dynamically typed
  • have a large user base
  • support a wide range of platforms (Linux, BSD, Windows, Mac). In fact, it comes standard on most of these platforms.

Finally, neither is

  • a "enterprise" language (like Java), in the sense that it has strict typing or makes sure that all exceptions are caught. Instead, both Python and Ruby are geared towards rapid prototyping.

But talking about commonalities is boring. Let's talk about the differences in syntax, language concepts and available codebase.

The Syntax

Variable Names

Ruby (as the name implies) is strongly influenced by Perl. Unfortunately, this means that it also inherited the incomprehensible global variables.


Ruby Python

While a programmer writing code has to spent roughly the same effort to memorise $< and $< or sys.stdin and sys.stderr, someone who is reading the code has a much easier time understanding Python.

Class Methods

Class methods are more elegantly written in Python than in Ruby.

Python uses decorators for class methods and static methods (class methods can access the class variables, static methods can not)

class Date():
   def fromtimestamp(cls,timestamp):
      """Return a date by it's POSIX timestamp"""
   def fromdate(year, month, day):
      """Return a date by it's Gregorian year, month and day"""

Ruby uses the self. keyword to refer to the class object, and place a function in the class rather than in the instance.

class Date
   def self.fromTimestamp
      # Return a date by it's POSIX timestamp
   def self.fromTimestamp
      # Return a date by it's Gregorian part

Equivalent alternative #1

class Date
def Date.fromTimestamp
   # Return a date by it's POSIX timestamp
def Date.fromTimestamp
   # Return a date by it's Gregorian part

Equivalent alternative #2

class Date
   class << self
      def fromTimestamp
         # Return a date by it's POSIX timestamp
      def fromTimestamp
         # Return a date by it's Gregorian part


Ruby syntax can be ambiguous:

functionA 1, functionB 2, 3

May either mean either

functionA(1, functionB(2), 3)
functionA(1, functionB(2,3))

The good news is that Ruby allows you to add as many parenthesis as would be required to make even a Lisp-addict happy.

Block Syntax

Any self-respecting article discussing Python's syntax can't get around it: indentation as a way to signify nested blocks.

While it has been much debated, I personally find it sheer brilliant. Nearly all attempts at a decent block style syntaxes struggle to somehow combine the condition and nesting start syntax on a single line. The only ones who succeeded here are Python, Ruby and [PHP's old style if/endif control structure syntax]] (that no-one seems to use anymore).


if true
   return :yeah
   return :nay


if True:
   return "Yeah"
   return "Nay"

Both syntaxes are very readable, and avoid the dreaded if condition { block } syntax.

Ruby define a second closure (next to the normal methods and lambdas), which is a block (or Proc). While conceptually cool, the syntax is not so great. Ruby allows both:

sum = 0
array.each do |item|
   sum += item
sum = 0
array.each { |item|
   sum += item

Regardless if you Pascal (begin/end) or C ({/}) is your big inspiration, none of these syntaxes is very inspired, and allowing two different syntaxes will only give rise to heated debates between the two style fanatics.

Not that Python is debate free. Care for some tab-versus-spaces discussion, anyone?


The better readability, and the other features make me conclude that Python's syntax is superior over Ruby

From The Zen of Python:

Readability counts.
There should be one-- and preferably only one --obvious way to do it.

The Language

One Way

In the syntax section above, I argued that code should not only be easy to write, but also easy to red. Indeed The Zen of Python not only says Readability counts, but also:

There should be one-- and preferably only one --obvious way to do it.

This does not apply to Ruby. For example, the map and collect methods are just aliases, just like the find_all and select methods.

While Python's intentions are clear, in practice it does not always hold. Imagine you are reading a sequence of bytes from a file, Python gives you the primitives (immutable) bytes and (mutable) bytearray, not to mention a (slower) list. Also, you can either use struct.unpack or array.array to do the conversion. Not really a "one obvious way" anymore.


In Ruby, everything is an object. Every Ruby programmer has marvelled at the fact that even numbers are objects:


Python on the other hand, is often criticised by defining global functions such as len() instead of adding it to as a method to every object (behind the scenes, the len(x) function does call a method, x.__len__()).

To me, the fact that len is a function instead of a method is irrelevant. The fact that None is a useful object in Ruby did appeal to me.

For example, it is possible to write:


and Ruby return a 0.

The Python equivalent, int(None) raises a TypeError.

Python's None is also an object, but has only about 20 methods (the same amount as an object), while a Ruby nil object has 55 methods.

Opening objects

The real power of Ruby comes from the addition of methods to modify existing objects in-place.


class ::Integer
   def even?
      return (self % 2) == 0
=> true

How is this useful?

Consider the following Python code snippet:

   page = urllib.request.urlopen("")
   address = json.loads(page.readall().decode('utf-8'))
   if not isinstance(address, dict):
       raise TypeError("Invalid JSON at URL")
except (urllib.URLError, ValueError, TypeError) as e:
country = address["country"].upper()

Even while we dealt with a failing URL fetch or bad JSON syntax, the last line can fail because "country" is not a valid key, or because address["country"] is not a String (but e.g. None), not to mention it might be an empty string.

   country = address["country"].upper()
except (TypeError, AttributeError, LookupError):
   country = 

If you want to set many variables, this quickly becomes a lot of repeated code. Python's equivalent of the ?: tertiary operator can turn this into a one-liner:

country = address["country"].upper() if ("country" in address and address["country"] != None) else 

This is shorter, but not very efficient and still not very readable.

In Ruby, it is is possible to open an existing (even built-in) class, and add a method to it:

class ::Hash
   def value_or_empty key
      if self.has_key? key

And the code simply reduces to:

country = (address.value_or_empty "country").upcase

This particular example can even be written without resorting to modifying the Hash class:

country = address["country"].to_s.upcase

This is possible because Ruby return nil for an undefined key in a Hash, and because nil.to_s returns an empty string.

This is not easily possible in Python. In Python, you would need to write a decorator class to accomplish the same:

class defaultvaluedict(collections.UserDict):
   """Dict decorator that returns an empty string for unknown keys"""
   defaultvalue = 
   # UserDict stores the content of the dict in
   def __getitem__(self, key):
      except LookupError:
          return self.defaultvalue

address = {"country": "nl", "name": "me"}
address = defaultvaluedict(address)
country = address["country"].upper()

While I admire the Ruby flexibility, I do fear that changing objects in-place may yield name collisions. What if I add a method which name is also used for a popular framework that also uses the same name, like the Rails framework? It is likely that my code will break.

Protected Methods

Python provides some syntactic sugar to support class-private names, but for all intends and purposes Python has no protected or private methods or variables. Ruby (and most other programming language) normally support protected methods, as well as private, read-only and read/write variables.

In fact, the two solutions provided by Python that I know of are hardly used:

class MyClass(object) :
   def __init__(self) :
      self.__var = 

a = MyClass()

While a.__var raises an AttributeError, the variable is not really protected, but only mangled. It can still be accessed (and overwritten) using a._MyClass__var. This kind of syntactic sugar reminds me of security through obscurity.

Named Parameters

Ruby has no named parameters (only order), Python has them (will be introduced in 2.0)




labels, named constants Ruby: I love the Symbols (e.g. :label)


Python has tuples, Ruby not (only arrays)


Python yield syntax easier to understand;

Ruby yield much more powerful

  1. !/usr/bin/env ruby

def g

 i = 0
 while true
   i += 1


g do |n|

 puts n
 if n >= 10


Symbol Table

Confusing: there is more than one symbol table.

Eg.: irb(main):056:0> p "hello" "hello" => "hello" irb(main):057:0> p = 1 => 1 irb(main):058:0> p p 1 => 1

In here, "p" has two meanings

Return Values

//Invalid in most programming languages. Two of the exceptions are Ruby and Scala
my_variable = if (condition) { "yes" } else { "no" };

?: ternary operator

my_variable = (condition) ? "yes" : "no";

As a side-note, it is perfectly possible

 C:          x = (condition ? "yes" : "no")
 Python 2.4: x = (condition and "yes" or "no")
 Python 2.5: x = ("yes" if condition else "no")

Type Checking

Code Validation

Python Zen

Errors should never pass silently. In the face of ambiguity, refuse the temptation to guess.

strict typing, exceptions can pass

Code is not validated; code is only checked while it is run. An error in a less-often used branch


Python multitasking support is a joke, despite a thread and a threading modules in the standard library. The reason is a global interpreter lock (GIL), which effectively halt all but one thread to ensure consistent state among all threads.

Ruby has a global VM lock, which is roughly the same as the Python GIL.

The way to use concurrency in Python is to use the subprocess module, even though it has some limitations (mostly caused by the pickle format to communicate between processes)

Nothing is True

Ruby 0 is True.


Python 2 3 3.3 UCS-4 default




Python has easy accessible docstrings, Ruby not

Standard Library

standard library. Python much more mature. Ruby: String.shellescape (1.9.3), very poor logging facility (need log4r)

Package Manger

Integration with Other Languages

Java integration Objective C Dot net (C#)


Further Reading


The Verdict