A blog article was posted by jesusphreak the other day about
why he chose python over ruby. Several people have commented on this in the blogosphere and mailing-lists (e.g.,
here,
here and
here), and in his comments section. So I might as well add my two bits.
I use both ruby and python, though I've only been using python for about 6 months (been using ruby for like...hmmm...3 years or so). Knowing ruby and chrome-level javascript (i.e., from writing firefox extensions) greatly decreased the python learning curve for me because of the similarities with those languages, and I can pretty much do everything I want to in python with minimal effort after just 6 months (writing fairly complex gui apps in any language in under 6 months bespeaks the power and intuitivness of the language -- 'course previous knowledge of ruby and javascript helped!). In fact, I've just been porting a desktop app I wrote in ruby+gtk over to python, and everything is going smoothly. The reason for porting it is mainly for ease of distribution -- I'm getting near to public release, and all the python extensions I'm using have graphical installers for win32, plus python is installed by default on many flavors of *nix, and the speed boost from
psyco is nice too.
But don't worry, fellow rubyists, for admin scripts and personal projects I use ruby, mainly because of its expressiveness. Adding methods to built-in objects, transparent regexp support, code blocks, and so forth; I know that I can get all the same results in python, using different techniques, but some of them just look...ugly, by comparison. And I really dislike top-level methods like
len() and
str()...yuck! I know I can use a class-wrapper to get around this in python...like adding a
str() method to a
UserInteger wrapper class for class
int, and then initializing all my
ints as
UserInteger instances:
class UserInteger(int):
def str(self):
return str(self)
## YES! You need these...
## the arithmetic operators cast their
## result as a normal int
def __add__(self, i):
return UserInteger(int(self).__add__(int(i)))
def __sub__(self, i):
return UserInteger(int(self).__sub__(int(i)))
def __mul__(self, i):
return UserInteger(int(self).__mul__(int(i)))
def __div__(self, i):
return UserInteger(int(self).__div__(int(i)))
def __radd__(self, i):
return UserInteger(int(i).__radd__(int(self)))
def __rsub__(self, i):
return UserInteger(int(i).__rsub__(int(self)))
def __rmul__(self, i):
return UserInteger(int(i).__rmul__(int(self)))
def __rdiv__(self, i):
return UserInteger(int(i).__rdiv__(int(self)))
n = 5
i = UserInteger(n)
i = ((i * i) / 3) + 2
i.str() # => '10'
...but that's a lot of trouble just to add a
str() method to class
int -- especially the part about initializing all
int objects as instances of the class wrapper rather than just using a literal, not to mention adding methods to the wrapper to ensure type safety. Compare that to ruby's equivalent:
class Fixnum
def str()
self.to_s
end
end
i = 5
i = ((i * i) / 3) + 2
i.str # => "10"
No need to initialize instances of a subclass before my custom methods are accessible -- I've actually extended the base-class itself, not created a custom subclass.
But minor issues aside, the two are very similar (kissing cousins, I'd say). Consider the following sed-like program (which I aptly named gsub ;) ), first in ruby, then in python:
unless ARGV.length > 2
puts 'usage: gsub "PATTERN" "REPLACEMENT" file [file ...]'
exit
end
pattern = ARGV.shift
replace = ARGV.shift
files = ARGV.dup
files.each { |filename|
File.open(filename, 'rb') { |fh|
data = fh.read
if data =~ /#{pattern}/
fh.reopen(filename, 'wb')
fh.write(data.gsub(/#{pattern}/, replace))
end
}
}
And in python:
import sys, re
if len(sys.argv) < 4:
print 'usage: gsub "PATTERN" "REPLACEMENT" file [file ...]'
sys.exit()
pattern = sys.argv.pop(1)
replace = sys.argv.pop(1)
files = sys.argv[1:]
for filename in files:
fh = open(filename, 'rb')
data = fh.read()
fh.close()
if re.search(pattern, data):
fh = open(filename, 'wb')
fh.write(re.sub(pattern, replace, data))
fh.close()
Anyhow, in my own humble opinion, both ruby and python are great languages (in the words of Rodgers and Hammerstein: "
the farmer and the cowman should be friends"), and a person should not limit themselves to using only one or the other of them; or at least they should try using both for some time to see which is better suited to their own needs before they make a final decision. It seems that jp found python more adequate to his needs at the time, so more power to him for using it! No haterism here.
Labels: python, ruby