Ok, so I figure it's about time to live up to the title of this blog, since I've spent the vast majority of the language discussion firmly planted in parentheses. Aside from the fact that my company is starting a project in Erlang, I've also been scripting Python and Ruby pretty heavily.
They're actually not very different languages. Neither is perfect from my perspective[1], and neither sucks. If I had to, I could get work done in both (and having gone through the Ruby chapter in 7 Languages in 7 Weeks, I'm more inclined to look at Ruby for my next big project than I used to be). To start with, here's a boiled down, no-nonsense table that represents my perspective.
...is more annoying than... | |
len([1, 2, 3])
|
[1, 2, 3].length |
"foo " + bar + " baz" or
"foo %s bar" % bar
|
"foo #{bar} baz" |
", ".join(["one", "two", "three"]) |
["one", "two", "three"].join ", " |
map(lambda a: a + 1, [4, 3, 2, 1]) ## still makes more sense ## than join or len, though |
[4, 3, 2, 1].map {|a| a + 1} |
a = [4, 3, 2, 1].sort()
a[0]
|
[4, 3, 2, 1].sort[0] |
nothing.jpg | foo.methods.sort |
require 'optparse' require 'pp' require 'fileutils' |
import optparse, fileutils
## I also prefer the more granular
## symbol access I get with python
|
sudo apt-get install ruby-full irb |
python |
...is about as annoying as... | |
def aFunction(foo, bar): #do stuff return baz |
def a_function(foo, bar) #do stuff baz end |
with tempfile.NamedTempFile() as tmp: tmp.write("Test test\n") ##more stuff tmp.flush() popen(["lp", "-d", "a-printer", tmp.name()]) |
Tempfile.open() do |tmp| tmp.write("Test test \n") ## more stuff tmp.flush system("lp", "-d", "a-printer", tmp.name) end |
So I am slightly biased, but like I said earlier, not enough to actually decry either language. The biggest point in Ruby's favor is its handling of blocks (as seen in that tempfile pseudo-code). I like having an expression that says "Create an entity, do this stuff and then clean up", without having to clean up myself. Python doesn't like that.[2] Gotta admit, I boggled at the join
syntax the first time around. Rhetorically, who the hell decided it makes sense that a join
operation is something you do to the delimiter, rather than the list? In my opinion, it would even make more sense to make it a standalone function a-la len
.
I really like the syntactic whitespace in Python.
def something(): foo() bar()seems like it's cleaner than the Ruby equivalent. Except that when I want to return the result of
bar
(which I do quite often, given that I much prefer functional programming to OO), I need to do so explicitly. Ruby has me waste an additional line on end
, but returns implicitly. While I'm at it, Python libraries seem to be heavily anti-functional programming. They do the standard "OO" thing of exposing functionality via classes, but they also typically have a heavy reliance on side effects, which makes it harder than it ought to be to compose things. A recent example I had to go through involved using pyPDF
and reportlab
to process existing PDFs. You can do it, but the amount of fiddling involved is nontrivial if you want to decompose the problem properly because you need to do so by setting up multiple instances of PdfFileReader
/canvas
and making destructive changes to them.
Also, not represented in the table is how much easier it is to install python
packages in Debian. While gem
frequently errors on something, I've yet to find a package I need that I can't either apt-get
or retrieve using python-setuptools
. That's worth something (in fact, it's worth enough that I've been procrastinating on a ruby port of get-youtube-series
, which used only default components in Python, but requires several installs in Ruby).
The last thing that table doesn't encompass is the version situation. That's a fairly major one from my perspective, but I'm not sure how serious it actually is. Python 3 has been out for quite a while, but it's not uncommon to see "Supports Python 2.7" on various frameworks/utilities. Squeeze still provides 2.6.6, Django still requires 2.[4-7] and Google app-engine is still asking for 2.5 (with 2.7 being supported as an "experimental" feature). That's less than encouraging. By contrast, Ruby 1.9 is fairly widely supported (though the Debian repos are still at 1.8.7). That just doesn't seem to bode well for the next version, regardless of how enthusiastic Rossum is about it.
Footnotes
1 - [back] - Though, to be clear, my opinion is that Ruby gets a damn sight closer than Python.
2 - [back] - Thank you Brendan Miller for pointing me to the with
statement (documented here, here and here) which does emulate blocks well enough for my purposes.
For the tempfile thing, you should use python's with statement. It's actually very similar to lisp's with-* macros like with-open-file, but a little more flexible since it defines a general interface for releasing any resource...
ReplyDeletewith tempfile.NamedTemporaryFile() as tmp:
tmp.write("Test test\n")
tmp.flush()
subprocess.popen(["lp", "-d", "a-printer", tmp.name()])
This will of course, properly clean up in the face of an exception.
@Brendan Miller: Thanks! Updated the article to reflect that point.
ReplyDeleteI took another look. You should also replace:
ReplyDeletemap(lambda a: a + 1, [4, 3, 2, 1])
With [a + 1 for a in [4, 3, 2, 1]]
map isn't really used much in python because list comprehensions/generators do the same job better.
The first time I saw the loop macro in CL, I thought of how similar it is to python comprehensions and generators.
adapazarı eskort
ReplyDeleteadana eskort
aksaray eskort
bartın eskort
yalova eskort
eskort
düzce masöz
manisa masöz
izmit masöz
görükle masöz
YENİ PERDE MODELLERİ
ReplyDeletenumara onay
vodafone mobil ödeme bozdurma
Nft Nasıl Alınır
ankara evden eve nakliyat
TRAFİK SİGORTASİ
DEDEKTOR
Kurma website
ask romanlari
Smm Panel
ReplyDeletesmm panel
iş ilanları
İNSTAGRAM TAKİPÇİ SATIN AL
hirdavatciburada.com
beyazesyateknikservisi.com.tr
Servis
tiktok para hilesi indir