A work in progress. Listed approximately from most to least important, in my opinion. (They get re-arranged fairly frequently as my feelings on the issues change.)
[1, 2, 3, 4]
. It also has tuples, which are like Arrays but immutable, with syntax that’s more natural in some cases: (1, 2, 3, 4)
. Python has dictionaries, which are like Ruby Hashes: {1: 2, 3: 4}
. It also has sets, which are like … Ruby’s Sets, only they have syntax: {1, 2, 3, 4}
and don’t need you to import a library, even one that comes with the language. The collections module in the standard library also contains a deque data structure, a doubly-linked list with head pointers at both ends for when you need a list with O(1) appends and prepends, as well as an ordered dictionary class (though this should be the default behaviour) and a dictionary supporting default values for key access (likewise). ¶
Encoding::UndefinedConversionError
or an invalid byte sequence in UTF-8
error in Ruby, you’re either lucky, damn smart, or unaware of the existence of Unicode, in which case your app is likely to break the first time someone types some non-ASCII characters into it.) ¶
def
s to define functions that can only be used within the scope of another, enclosing function. This is terrifically useful. When Ruby encounters nested def
s, it defines a new function on the class of object the enclosing function was called on. This behaviour is so useless as to be laughable, especially when, if you really wanted that, you could use define_method
. ¶
Date
stores a date as a year–month–day tuple; DateTime
stores a date and time together; Time
, contrary to what you’d expect, also stores a date and time. The difference between Time
and DateTime
is that the former is built in to the language, and (internally) stores the date-time as a POSIX timespec
, whereas the latter is in stdlib, meaning it comes with the language but isn’t loaded automatically, and it implements the Gregorian calendar “properly” (counting days since some arbitrary epoch nobody cares about, and adding time-of-day on top of that.). Python also has an awareness of the ‘naive’ vs. ‘aware’ date-time objects, the former having no conception of the existence of time zones and the latter being extensible to allow support for e.g. the IANA tz database for full historical timezone awareness. ¶
IO.select
is nice and simple, but inflexible. Python provides a whole damn library of interfaces to various UNIX/POSIX variants of multiplexed I/O system calls. Python also has an interface to the BSD kqueue system calls, which Ruby lacks. On the downside, IO.select
, contrary to its name, sensibly picks either select
or poll
depending on which is most suited to the situation; Python makes you choose for yourself. ¶
(0..99).select {|x| x % 2 == 0 }.map {|x| x ** 2 }
is easier to understand than [(x ** 2) for x in range(100) if (x % 2 is 0)]
. ¶
"The sum of 2 and 2 is #{2 + 2}"
; Python makes you use sprintf
, but at least has some nice sugar for it: "The sum of 2 and 2 is %d." % (2 + 2)
. Python recently gained a new way to suck at this: "The sum of 2 and 2 is {0}".format(2 + 2)
, which manages to be both longer and less familiar to those who are used to printf
format strings from other languages. ¶
a = if b: x else: y
? Statements were a mistake in programming language history: expressions are universally superior. ¶
return
to break out of a function and specify its return value. Ruby gives you the best of both worlds: you can use return
to return early, but functions still implicitly return the value of the last expression. ¶
case
/switch
blocks have a bad rap because C screwed them up. Even Ruby’s implementation leaves something to be desired, but at least it has them, without the opportunity to make yourself look like a fool by forgetting a break
. Even worse, Python had a proposal for a switch/case statement, but it was rejected! ¶
hash
on anything, regardless of whether it really makes sense to use it as a hash key; this allows it to be used to speed up comparisons. Python only allows it to be used on immutable data types, which kind of makes sense, but really makes assumptions which are not always guaranteed to be true. ¶
list.join(string)
(the Ruby way) makes a ton more sense than string.join(list)
(the Python way). ¶
+
as a name like you can in Lisp or Ruby, so to overload the addition operator, you define a method called __add__
. There are enough of these that I find myself referring to the documentation of them fairly frequently, whereas in Ruby I know to define a method called +
; other ‘overloading’ methods are similarly intuitively named. (Though it does look quite odd in code, I admit, though you soon get used to it.) ¶
urllib
sucks; Net::HTTP
does too. I’m assured that there are third-party replacements for both available, which don’t suck, but it’s 2013, and good HTTP support should come packaged with every language. Built-in libcurl
bindings would be terrific. (Something PHP actually managed to get right …) ¶