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