Eric Radman : a Journal

A Comparison of Ruby and Python

Ruby is an extremely consistent, flexible language. These are some examples of how it compares with Python in my experience.

Gather Results from a command
# rb: fantastic for scripting
arch = `uname -m`
# py: no recommended way to do this
from subprocess import Popen, PIPE
p = Popen(["uname", "-m"], stdout=PIPE)
arch = p.communicate()[0]
List Object Methods
# rb: simple OO
"string".methods.sort
# py: fundimentally it's another operator
dir("string")
Print a Hash Sorted on Keys
# rb: standard blocks and simple iterators
h = {"rabbit" => 2, "cat" => 1, "dog" => 3}
pairs = h.sort_by {|k, v| k}
pairs.each do |k, v|
  puts "#{k} : #{v}"
end
# py: sort() mutates the list
d = {"rabbit": 1, "cat": 2, "dog": 3}
keys = d.keys()
keys.sort()
for k in keys:
    print "%s : %s" % (k, d[k])
Print a Hash Sorted on Values
# rb: standard blocks and simple iterators
h = {"rabbit" => 2, "cat" => 1, "dog" => 3}
pairs = h.sort_by {|k, v| v}
pairs.each do |k, v|
  puts "#{k} : #{v}"
end
# py: sorted() takes a function
d = {"rabbit": 1, "cat": 2, "dog": 3}
pairs = sorted(d.items(), key=lambda (k,v): (v,k))
for k, v in pairs:
    print "%s : %s" % (k, d[k])
Clear Hash Entries
# rb: very predictable
h = {"a" => 100, "b" => 200}
h.delete("a")
# py: is this a statement or an operator?
d = {"a": 100, "b": 200}
del d["a"]
Test for a Value
# rb: 0 != nil, all numbers are values
if 0 then "valid" end
# valid
# py: None != 0, but zero is not a value?
if 0:
    "valid"
# condition fails
Test for Equality on a Regular Expression
# rb: regex is seamless
if "item5" =~ /item\d/ then "true" end
# py: regexp is not integrated
import re
p = re.compile('item\d')
if p.match("item5"):
    "true"
Variable Interpolation
# rb: any variable in current environment
pin = 9876
"you're new pin is #{pin + rnd()}"
# py: must build a dictionary
dict = {'pin':9876 + rnd()}
"you're new pin is %(pin)s" % dict
Literal String
# rb: Use single quotes
puts 'the tab character is \t.'
# py: String prefixed with 'r' or 'R'
print R"the tab character is \t."
Heredoc
# rb: use of shift operator allows input to be terminated
# arbitrarily
def send
    <<MESSAGE
From: Eric Radman <ericshane@eradman.com>
To: Test User <test@eradman.com>
Subject: e-mail test

Test Message
MESSAGE
end
# py: tripple-quotes have to be escaped; text cannot start
# on following line
def send():
   return """From: Eric Radman <ericshane@eradman.com>
To: Test User <test@eradman.com>
Subject: e-mail test

Test Message
"""
Access Private Class Variables
# rb: attr_accessor() shortcut enables get/set or we can
# create our own methods
class Person
  attr_reader :name
  def name=(name)
    @name = name
  end
end

# py: mangled names (prefixed by double-underscores) must
# be used, and get/set is not overloaded
class Person(object):
    def set_name(self, name):
        self.__name = name

    def get_name(self):
        return self.__name
Filter Duplicate Values from a List
# rb: very intuitive
[7, 6, 1, 6].uniq
# py: ug, casting to the rescue?
list(set([7, 6, 1, 6]))
Reverse and Return a List
# rb: as with many methods, us ! to mutate
[1, 2, 3].reverse
# py: no option to return the list unharmed
numbers = [1, 2, 3]
numbers.reverse()
return numbers
Hidden classes
# rb: redefining a constant produces a warning
TestMissileLauncher = Class.new do
  def test_safety_lock
    # ...
  end
end

TestMissileLauncher = Class.new do
  def test_launch_controls
    # ...
  end
end
# warning: already initialized constant TestMissileLauncher
# py: dangerous and common--the first class overwrites the
# second, only the second set of tests run
class TestMissileLauncher(object):
    def test_safety_lock(self):
        # ...

class TestMissileLauncher(object):
    def test_launch_controls(self):
        # ...

Notes

Tests formed with Ruby >= 1.8.7, and Python >= 2.5.1

$ Fri Feb 12 15:13:16 -0500 2010 $