Skip to content
Tags

Python vs Ruby

July 12, 2009

I see Ruby people bashing Python a lot on Stackoverflow. It’s a bit sad, Python and Ruby are usually bestest friends forevah. So I started a question on Stackoverflow, not about which of them is best, but just what the differences are, objectively.

It was more difficult to make that objective than I thought, but I sure learnt a lot. And, as suspected, many of the differences are just semantic, like Ruby using @attribute and Python using self.attribute. And of course it’s objectively it’s impossible to say what language is better, which we of course knew from the beginning. That’s no surprise. The surprise is that there are so few differences that can be cast as better or worse at all. Even such things that sound like an objective good or bad, such as a language having a certain feature, turns out to mostly be a matter of taste.

I could just find these differences that in any way can be called objectively better:

1. Ruby has a reference to the class in the class body

This means that code like this is possible:

class MyClass
    initialize_magick()
end

While in Python, you would have to write:

class MyClass:
    pass
initialize_macgick(MyClass)

As you see the practical difference is very small. But Rubys variant is cleaner, as the magic stuff is done in the class definition, so you see that it’s being done when you look at the class. And indeed, the Zope component architecture uses some heavy magic with metaclasses to make the same thing happen in Python:

def MyClass:
    implements(IMyInterface)

So it’s possible (In Python 2) by some clever tricks to get the same effect. In Python 3 it isn’t because the metaclass syntax is different, so in Python 3 you instead need to use class decorators. And what you think is cleaner of

@magickly_initialized
def MyClass:
    pass

or

def MyClass
    initialize_magick()
end

is again a matter of taste. So, a small plus for Ruby there, without a doubt. But it’s really not a big deal, because calling the initialize method after the class or as a decorator is really not a major drawback.

2. Ruby has continuations

Continuations are heavy magic. And Ruby has them, and Python has not. You can “fake” them, and it seems that many of the usecases can instead be done with passing variables into .next() which you can do in Python 3.1. The use of continuations seem rather limited, and hard to understand, but it’s there in Ruby, and not in Python. So another plus for Ruby.

3. Python has generators

You can fake them in Ruby by using blocks, or use continuations. So no big deal again, but a small plus for Python anyway, as Pythons generators are both easy and clean.

4. Python has multiple inheritance

Some people claim multiple inheritance is evil. But having it means that if you think it’s evil, you can simply not use it. I have used it a lot, never found it a problem, but I think adaptation is a better pattern. Still, it’s clearly a plus for Python.

5. Python has docstrings

Docstrings makes it possible to attach documentation directly to the classes and methods. That’sa nice documentation plus, and makes things like the Python interpreters help() function really useful. Another plus.

Aaaaannnd, that’s it!

These five small differences are the only things that I can see are objective improvements over the other language. And as you see, none of them are really major. It’s just small things that are more convenient or not. So, am I gonna switch to Ruby now, when it’s almost just as good? Nope. Because there are lot of other differences, that are differences in attitudes and semantics. And there I really like Python better. Here are three major features of Ruby that in my opinion either are misfeatures or just not of value:

1. Ruby has built-in regexp and line input looping

This is inspired by Perl, and means you can easily make a script that looks through a text file and munges each line separately and prints out another text line. This is extremely useful’in many cases. Also Ruby is said to be better to make glue.scripts, so it can more readily be used for a shell script replacement than Python. Plus for Ruby? Well, no, not in my book. I do these things sometimes, mostly in awk. If they get more complex than that, I prefer to use the clarity of Python than the obscure machinations of regexps. And having a small open(filename).readlines() isn’t that much trouble. So this is a feature I think only adds clutterm and I’m happy Python doesn’t have it. Wow! That turned out to be a subjective issue! That surprised me.

2. Ruby protects class attributes etc

Ruby treats variable names that has the first letter in capitals like a constant, so you can’t modify it. You also can’t access attributes of objects from outside the class. Python doesn’t protect your code from other programmers. If they want to shoot themselves in the foot they are allowed to. I like that. I remember when using Delphi, and I needed to subclass an object in the standard library, but some attributes or methods were protected, so I couldn’t. I ended up having to duplicate almost the whole (rather big) component class in my subclass, just because the developer of the base class hadn’t forseen my type or requirement. So these sorts of protections are generally just a problem. OK, it’s less of a problem in Ruby, as it allows you to monkey-patch the class but this still is a big plus for Python in my book. I’m sure Ruby people do not agree. It’s subjective again.

3. Ruby has blocks

But some differences are more differences in attitudes than anything else. And sometimes these different attitudes seem to in the end be the same attitude but from different angles. Ruby has for example the concept of blocks. Blocks seems to pretty much be Rubys name for closures, and it’s an abstract concept basically meaning a piece of code that gets variables from somewhere else and can have local variables that doesn’t pollute the surrounding name space.

Rubys blocks are widely hailed (by Ruby people) as something fantastic compared to Python. But it turned out to be very difficult to find actual cases where Ruby really did something in a cleaner way than Python thanks to blocks. Well, it turns out that Python also has blocks. But they are called “functions”. What’s the difference? Functions need a name, while blocks don’t. At this point a Python programmer says “Aha, so blocks are lambdas!” Yes, except that blocks can be multiline code and do anything, while Pythons lambdas are restricted to being expressions.

OK, so plus one to Ruby then? Well, no. Because what use is a block if you don’t attach it to a variable name so you can call it? In Ruby you create blocks and use them directly like this:

amethod do |variable|
    print variable
end

This is principally equivalent to Pythons

def theblock(variable)
    print variable
amethod(theblock)

Which of course is doable in Ruby as well. Which way is neater? Matter of taste again. And it becomes even harder to decide when considering that Ruby has a special statement to call the block with parameters. It’s called yield. Yield exists in Python as well, but there it’s used for generators. But the we get this code examples:

def themethod
    for a in [1,2,3,4,5]
        yield a
    end
end

themethod do |b|
   puts b
end

Which is almost suspisciously similar to

def themethod():
    for a in [1,2,3,4,5]:
        yield a

for b in themethod():
    print b

So in the end, this much touted principle of block seem to very rarely actually lead to any significantly different code than in Python. So here are widely discussed differences in principals that in the end…end up as the same thing (almost)!

4. Python has list comprehensions

It’s worth mentioning here that Python has some big features that Ruby doesn’t, like for example list comprehensions.

[foo(x) for x in alist if bar(x) != 'frotz']

But although I use them all the time because they are practical I don’t know what I think about them. Well, it’s shorter than:

foo = []
for x in alist:
   if bar(x) != 'frotz':
      foo.append(x)

But is it really neater and more readable? I’m not sure. It becomes a matter of taste again. I did not like list comprehensions when they first arrived in Python, but of course now I’ve gotten used to them. So that is not a good argument for Python. It’s subjective again.

5. Python has decorators

Decorators are prettier than the other ways of doing the same in Python, for example the above initialize_magick(class). But again it can be argued that the @decorator syntax just makes Python ugly, and that you don’t need them as much in Ruby. Again, matters of taste.

So why Python?

So, in the end, why do I, subjectively prefer Python over Ruby in almost everything? Because of Pythons clarity and simplicity, and it’s attitudes and principles. In Ruby, you have open classes, so you can extend any class. In Python, you can monkey patch in extensions into any class. The difference? That in Python it’s an ugly attitude that is frowned upon. In Ruby, many people tutorials and examples of blocks extend the Array class, like brutally monkey patching the standard types is a normal thing to do. (A hint guys: That does NOT help in explaining blocks, it’s just confusing).

In Ruby, there are no functions, but there are methods, blocks and lambdas. All of them seem to have subtle differences, and sometimes you need to not just call them, but use .call(). In Python, there are only functions. Lambdas are functions whose __name__ is <lambda>. Methods are functions that are wrapped to you don’t have to pass self. Simple and clear.

Python is more explicit. In Ruby you can skip the () when calling a method. Rubyists like that because it makes calls look like statements they say. Pythonists like me think it’s a bad idea to make a call look like a statement. If it’s a call it should bloody well look like one.

And Pythons packages and modules are just so much better for namespaces than Rubys modules. Again, subjectively. And you can choose if you want to import * in Python or not. In Ruby that’s all you can do

And all of these things, the things that makes me go “Eww…” about Ruby and “Yeah!” about Python turns out not to be features, but just subjective options of the different languages semantics and attitudes. It is truly so that none of the Languages are better than the other.

Except, of course, that Ruby sucks. ;-)

About these ads

From → python

83 Comments
  1. You say, ” Zope component architecture uses some heavy magic with metaclasses”. I’m not sure directives like implements() uses metaclasses. It does use sys._getframe() though :-)

    Personally, I find the Ruby syntax really obtuse. Terribly subjective, I know. But having learned, roughly in order, DOS batch files, Visual Basic (yuck!), Bash shell scripts, Perl, C, PHP, C++, Java and C#, I found Python quite a natural progression and the syntax was obvious to me. Ruby syntax makes me go ugh every time I look at it (and I’ve tried to learn it properly a few times). Sorry :)

    Martin

  2. It does use metaclasses, by replacing the local __metaclass__ with a metaclass wrapper that does the implements bit. And it uses getframe to get to the correct locals. :-) It’s pretty hairy.

    The Python 3 port of zope.interface will therefore replace the implements statement with an implementor decorator, since __metaclass__ goes away in Python 3.

    I agree with you about the Ruby syntax, and as you say that’s completely subjective. It’s all these special character for different things, like | foo |, :blah, @@bleh, etc. You have to remember what each of them do, and I tend to forget each time when I look at Ruby code. Same thing with Smalltalk. Maybe that problem goes away if I would use the languages for an extended period of time, but I have no incentive to do that, so…

    If I’m gonna learn a new language properly it should be something functional.

  3. On big annoyance to me was the import mechanism in Ruby (or perhaps I misunderstood).

    In Python you can control what is imported into the namespace from other libraries. This explicit import allows you to see easily pull in the part you want and during code development track the source of a method.

    Ruby has “require” which imports everything from the file implicitly. This can make it really hard to track down the source of some code. In Rails you end up with something like this: http://www.agmweb.ca/blog/andy/2054/.

    I found not being able to follow the source of the code a real pain in many Rails projects. Glad I’ll never do it again.

  4. Ah, you are right. I didn’t even think about the fact that it makes it hard to follow where definitions come from, I just though about namespace clashes.

  5. You shouldn’t say Ruby sucks. We’re all dynamic languages here, and the in-fighting is draining resources that could be better used elsewhere.

  6. You say “many of the differences are just semantic”, and then go on to describe a syntactic difference.

  7. Stephen permalink

    I think Paddy3118 has a point. You wrote a strong post but then you cheapened it with your final line.

  8. Between Python and Ruby I prefer Ruby despite this “clarity of intention” motto of Python.

    And between Javascript and Python I prefer Javascript.

    And between Javascript and Ruby I prefer both. ;-)

    Javascript is just like Python in many ways, but Javascript is more mainstream, more standard, in its features so Java guys, C# dudes, etc. can grok and write Javascript code right away. Where Javascript breaks down is in not having a standard way for writing OO code so different open source libraries offer each their own take on the issue. I use the Prototype JS OO support and can use Mixin just like in Ruby and inheritance in a similar way to how it works in Ruby.

    Each of these languages can give programmers enough rope to hang themselves pretty well.

  9. Guillermo Alcántara permalink

    Hi, I may not have understood it correctly but at one point you say (while talking about a possible danger):

    “Python doesn’t protect your code from other programmers. If they want to shoot themselves in the foot they are allowed to.”

    Then you say:

    “In Ruby, you have open classes, so you can extend any class. In Python, you cab(sic) monkey patch in extensions into any class. The difference? That in Python it’s an ugly attitude that is frowned upon.”

    So what it is? Does Python devs get frowned upon for trying to “access attributes of objects from outside the class”?

    By the way, those are NOT class attributes. Those begin wih @@. Variables that begin with Uppercase are constants. You can have them anywhere.

    (I don’t believe you are deceptive, I believe you are misinformed.)

    Another question you asked was: “What use is a block if you don’t attach it to a variable name so you can call it?”. My first answer is that “yield” doesn’t need a name, so you don’t need a name to call it. That feels kinda like cheating. So I will say: “to handle Combinators”. That’s a huge topic. I don’t have the space/time here to give you clear examples, I apologize. I can give you some links.

    http://www.angelfire.com/tx4/cus/combinator/birds.html

    http://en.wikipedia.org/wiki/SKI_combinator_calculus

    By the way, I generally agree with your points, it’s just that I found some points lacking information. This is an old post but you may find it interesting:

    http://redhanded.hobix.com/inspect/holyRedSnakes.html

    Finally, I do think Ruby needs list comprehension. Mean I use Range, Array#maps, Array#select or Set.

  10. @Lennart, Your interpretation of my comment is wrong. After reading the blog entry, I think the casual derogatory remark detracts from the points you take great pains to make.

    You set yourself up to be a seeker of objective, carefully reasoned, arguments from your first paragraph.on. You give the reader an expectation. Then you sink into the mire yourself with the throw-away quip at the end.

    Just a thought :-)

    – Paddy.

  11. Could you follow up with some more examples of big features python has ruby doesn’t?

    List comprehensions seem pretty cool. :)
    I think they can be emulated in ruby with blocks. Simple example:
    foo = alist.select {|x| bar(x) != ‘frotz’}

  12. Finally some sensible talk about Ruby & Python :) Otherwise it’s usually one community bashing the other. I’ve just started learning ruby and am loving it. I had tried to learn python a while back but never got the time. I guess it doesn’t hurt to try out both languages. But if you already are using one of them there ain’t a big reason to switch desperately.

  13. Class extensions are actually quite common. Not only Ruby is using them extensively. Have a look at Objective-C for example. A lot of Apple’s sample code includes class extensions. I think if it would be as bad of a habit as you say it is, Apple would barely do it. And I am sure that Apple has a big bunch of skilled folk working for them.

  14. @Paddy, @Stephen: Grow a sense of humour, will ya. :-)

    @Matthew: I never said ALL the differences where semantic.

    @Guillermo: No, Python devs does not get frowned upon for accessing private attributes, assuming they needed to. Yes, I know constants are not class attributes.
    I don’t see how combinatory logic is different from lambda calculus when it comes to these things. Yes, you can build computer programs by just having long lines of combinatory or lambda expressions. That is not, however, “elegant” in any practical way since it becomes unreadable and hard to understand if you do it very much. Also, combinatory logic uses only primitive expressions. Are you even allowed to have multiline methods with them? It doesn’t seem so to me. And then you don’t need Rubys blocks. You just need single-line lambda expressions, and Python has that.

    And yes, you can call a truly anonymous block with yield in Ruby. But as I showed above, Pythons generators, although different in principle, results in code that looks almost exactly the same.

    @Joel: I’ll see if I can find any more. I’m so used to Python now that I hardly know what features it has anymore, I just use them. :-) And you are right, they can be emulated using blocks and the select and map functions.

    @Rohit: Exactly!!!

  15. @Lennart, My sense of humour is more purple than yours!

  16. Ah, I see. :-)

  17. Brian Takita permalink

    Yehuda Kats has a nice follow-up.

    http://yehudakatz.com/2009/07/11/python-decorators-in-ruby/

  18. Regarding #4, note that the usual Ruby way to do that is as follows, …

    alist.reject{|i| i==’frotz’}

    Joel posted something similar and correct above, but using reject with == is slightly friendlier than using select with !=.

    I’d call this a score 1 for Ruby. List comprehensions are fairly nice, and fairly expressive, but I find the Ruby enumerators with block arguments to be both more expressive and more legible/literate.

    Note that I’m not saying this makes Ruby superior to Python, although I do prefer Ruby over Python somewhat (personal taste).

  19. mannemerak permalink

    A big plus for me on the Python side is the WX and QT bindings. Ruby has them as well, but wxPython (and recently PyQT) has been around for a while and is well supported. I can also push my scripts through bbFreeze and generate binaries for Windows and Linux users (for the ones to lazy to install the dependencies). Does Ruby have something like this?

  20. Sinan permalink

    *In regards to your point on “ruby protecting class attributes”*: You can access everything inside a ruby object, even if the designer doesn’t want you to, using things such as instance_eval() and send(). For example:

    
    class A
      private
      def some_private_method
        "i am in private"
      end
    end
    
    # A.new.some_private_method # => raises "NoMethodError: private method .."
    A.new.send(:some_private_method) # => "i am in private"
    
    

    So, you actually can access whatever you want, this gives double benefit; you save the newbie from accessing things he is not supposed to, but you still let the expert access whatever he wants.

    *In regards blocks in ruby*: I think the beauty comes really nicely when you start to chain method calls which all take blocks. For example, in a cards game I am working on, I use the numbers from 0 to 51 to represent the cards in a deck. To get the smallest card from the shortest suit (in a subset of the deck), I can use:

    
    
    cards.group_by { |card| card / 13 }.min_by { |suit, cards| cards.length }.last.min
    
    

    Imagine if I had to give names to those two blocks! Some people could argue that this could be done with lambdas in python, but still, it wouldn’t be as readable, imho.

    • @Sinan: You don’t need to name those blocks since they are all just expressions, and therefore, they can be done with lambdas. You only need to name them in Python if they are multiline, and if you have several multiline blocks nested, there is surely no way you can call that elegant, even in Ruby. I did come up with a Python one-liner for that code, and I agree it’s not very readable, but then again I don’t think your code is either.

      min(min([list(x[1]) for x in groupby(cards, key=lambda x:x//13)], key=lambda x:len(x)))

      Not so pretty. But the horrid part here is that list(x[1]) for x in, and that’s a side effect of itertools groupb., It returns the grouped with key and a generator, not just lists of lists. That’s obviously way more flexible, but here we want a list of lists, so lets make a group_by that actually returns a list of lists, as Rubys does:

      def group_by(iterable, key):
          return [list(x[1]) for x in groupby(iterable, key)]
      

      Then it gets better:

      min(min(group_by(cards, lambda x: x//13), key=lambda x: len(x)))

      Can’t say that is any less readable than your code. in any case, in real life I would make both Card objects and Hand objects, with methods like “by_suite” etc. That would make for much cleaner and more readable (and hence elegant) code. It’s not very Pythonic to represent something that clearly an object like a playing card with just an integer.

  21. mark permalink

    “Pythonists like me think it’s a bad idea to make a call look like a statement. If it’s a call it should bloody well look like one.”

    What you fail to realize is that you can do
    method()
    in ruby too. Noone stops you. But we ruby guys have the freedom to CHOOSE.

    You python guys can not choose.

    It is silly to claim you hate to omit () when YOU CAN DO THE VERY SAME IN RUBY, AS IN PYTHON, AND USE THOSE (). Or omit them. You get to choose. If choosing is too difficult, then python is better because you dont have to think at all. :>

    About “import *” in python, I agree. That is actually an import/load mechanism which is smart.

    In the end what matters more is what one creates with a given language. The best language has no use if noone writes anything in it….

    I think it would be better to create a new language which learned from both ruby and python.

    • @Mark: I do not fail to realize anything.

      You say it’s a choice. Yes, and when you code by yourself, what choices you do doesn’t matter. You can write Ruby code that looks like brainfuck and nobody would care. Elegance and readability only becomes an issue when others need to read the code. And then you don’t have a choice, because it wasn’t you who wrote the code, it was somebody else, so it was his/her choice, not yours. Perl code is famously readable for whoever wrote it, but incomprehensible to others. Why? Choice.

      What would I change in Python, and take from Ruby?

      Well, I’d rename “lambda x:” to “def (x):” to show that lambdas are just anonymous functions. Maybe I’d even allow multiline anonymous functions, just to get Ruby people off my back. And I would have an until statement. And I would have the class being available in the class body. That’s it. That’s honestly all I think Python has to learn from Ruby. And I’m sure you think similar things, but the other way around. New language that learns from both? Nah. We’d just end up with Python and Ruby all over again. :)

      • @Tom: Ah. I was told they were protected. Now it turns out they aren’t protected, the “protection” is only an effect of the @syntax. Yet another argument for self., I have to say.

  22. Interesting article. I do a lot of development in Ruby, but I appreciate Python and the different design choices that have gone into it. In general both communities are very similar, and the choice between languages is very subjective.

    That said, I think your 2nd subjective point, ‘Ruby protects class attributes’ either isn’t explained well or just is based on a misunderstanding of ruby. It’s true that variables with a capitalized first letter (such as classes) are treated as constants; attempts to redefine them will usually result in a warning (though you can still do so if you wish). It’s only the variable that’s ‘protected’ though, not the actual class which can still be reopened at will.

    It’s also true that direct instance variable access is discouraged from outside the class though it is still possible using #instance_variable_get(“@secret_data”) and #instance_variable_set(“@secret_data”, value). From inside the class or any subclass though, instance variables can always be accessed directly.

    In fact one of the main arguments used against ruby (though one that I strongly disagree with) is that these protections don’t exist. I believe (as you stated) that when these protections are present, they can cause more problems than they solve.

  23. Malakas permalink

    >many of the differences are just semantic, like Ruby using @attribute and Python using self.attribute.

    I think you meant syntactic.

    • Nope. Maybe semantic is not the right word, but I do not mean syntactic, as every difference between two programming languages are syntactic. What I mean is that you may call things differently, although they use the same principle behind it. Like self.foo vs @foo. A syntactic difference is things like “for x in foo” vs “for (i=0, i<len(foo)) {x = foo[i] }. The former can be argued to be "syntactic sugar" for the later. In fact, all programming languages are just syntactic sugar for machine code. :-) So syntactic differences are important. What you *call* things are not. Hence "semantic". Better words for that are welcome. :)

  24. Demur Rumed permalink

    Earlier python (2.5) generators have a .send to pass values to generators

  25. Regarding list comprehensions:

    In ruby, you’d do:

    anotherlist = alist.select{|x| bar(x) != ‘frotz’}

    OR

    anotherlist = alist.reject{|x| bar(x) == ‘frotz’}

  26. Jay permalink

    I think perhaps that you don’t understand blocks. They are much nicer than iterators. They make possible some hacky sorts of things that you might not like, but that’s a matter of taste.

    Additionally, iterator blocks mostly subsume whatever you might do with a list comprehension. I much prefer the functional style, but whatever.

    • I think perhaps I do. They aren’t particularly complex after all. It’s just an anonymous function.

  27. I love this post. I’m neither a fan of Ruby or Python (Groovy baby!) but the idea you expressed are very much on point. It all comes down to taste. One person’s language preference could be more affected by the smell emitting from the lunch room the first time they tried it, or their upbringing than the language’s actual features. All modern dynamic languages sport an equivalent set of features and while I prefer Groovy mostly because of its closeness to Java I could easily see myself being a Python advocate if I had only bought that book many years ago as I sat in Barnes & Nobels. I could just as well have been a Ruby nut if I was migrating from a language like Perl.

  28. I’d say you also missed the “library support” category.

    Python’s library support stomps ruby’s libraries into the ground.

    I like the technical side of ruby better, but the practical/community side of python wins.

  29. thet permalink

    monty python is funny, ruby not.

  30. Background: I’ve been doing more than a year of Ruby before starting with Python. Having said that I feel mostly like a Lisp programmer of old age.

    I agree that most of the differences between Ruby and Python are a matter of personal preference. However, as we all know, personal preference has a huge impact when chosing technology. When I felt that I had to look elsewhere from Perl because things started to get a little bit out of hand with a more complex application, I chose Ruby over Python mainly out of personal preferences. For one thing, I don’t subscribe to the “there should be only one way to do it” preference of the Python community (actually, I don’t think the Python community doesn’t really subscribe to it either, and I think pypi proves it). For a second reason, I think that the Ruby community is more open to functional approaches whereas Python is more tied to purer OO approaches, but maybe that’s just my personal impression again.

    Wrt. to blog post, I have on quibble with your discussion of blocks. First of all, blocks are foremost used as anonymous functions. It’s true that they capture state like closures do and that you can pass them around but a lot more often you use them where in Python you would either use a lambda statement or simply define and call some small function. I agree it’s not a big issue but you avoid polluting namespace by allowing multi-line anonymous functions, so I definitely see blocks as plus of Ruby. The different ways to define them and the subtle semantic differences are a minus, on the other hand.

    Wrt. to list comprehensions I too have mixed emotions. I generally like them for their simplicity, but I think they become a lot less attractive if you’re starting to use nested comprehensions.

    • @Holger: The position is “There should be one– and preferably only one –obvious way to do it.” That statement only goes for the language itself, it has never extended to be “There can only be one library to parse XML” for example. So your assertion about PyPI is a misunderstanding.

      Yes, in theory you can avoid polluting the name space with anonymous functions. When you define a function with a name, and then also start passing around you in fact have two names for it, and it may be that one isn’t needed. In theory.

      But in practice, if you don’t have names for your functions, and then start passing them around, you’ll end up in a situation where you, when debugging, in fact will not know which function a variable points to (unless you step into it with a debugger). And, if you don’t pass functions around, but instead just assign one function to one variable and then keep referencing that function via that variable name, how is that different from defining the function with a name and using that name? Right, it isn’t.

      There is only one case in Ruby where you have a truly anonymous function, and that’s the case of the yield magick. And as I shown, you can create very similar code in Python, without anonymous functions.

  31. Gravity permalink

    “Except, of course, that Ruby sucks. ;-)”

    You totally pwnt Ruby there.

  32. cnicolaou permalink

    Regebro,

    Many thanks for sharing your thoughts about Python and Ruby.
    It is clearly obvious that this blog entry is to praise Python over Ruby.

    Which is better/faster/more elegant? Well, It isn’t quite the case, as both languages are have lots of similarities and some core differences.

    IMO the comparison should be based on the output. Are developers happy programming with? Are they hitting any walls, constraints, limitations?

    Cheers,

    • “It is clearly obvious that this blog entry is to praise Python over Ruby.”

      I think you should read it again.

  33. I updated the post with two more things Ruby doesn’t seem to have: Decorators and named/keyword arguments.

  34. Andy Fleener permalink

    Ruby has something similar to keyword arguments, you just include an blank block as the last parameter, it works like this:

    def funky(a, b, c=3, d=4, ablock={})
    puts a, b, c, d, ablock
    end
    …..
    >> funky(1,2,d=6, :e=>800, :g=>”hey!”)
    1
    2
    6
    e800ghey!

    • Uhm…. I have to admit that after fiddling around with that, I’m completely unable to make that do anything useful. Do you have some code examples that actually get the parameter *back* so you can use them?

  35. Emmanuel permalink

    @thet: that’s why Python was named after the Monty Python and Ruby after the actual gem.

  36. Emmanuel permalink

    To all the person who commented on the last line of the original post: I’m pretty sure the last line, “except Ruby sucks” it there to confirm that the differences are a matter of subjective preference and not to say that Ruby in fact sucks. My impression is that Lennart thinks that Ruby does in fact, overall, suck, but he is aware that he does not think so for objective reasons.

    This is exactly the type of reasoning that all politicians should have, but that almost none do have. “I believe that X is wrong but that belief is not relevant to running this place, so, even though I really think it’s true, it’s not something I should take into account now. And that sucks because it IS so true.”

  37. Andy Fleener permalink

    {:foo => “bar” }.each do |key, value|
    puts “#{key}=#{value}”
    end
    >>foo=bar

    or if you have the key name you can access it like this

    block = { :foo => “bar” }
    puts block[:foo]
    >>bar

  38. Thanks, Andy, but could you show how to do that in an actual method call? Because I tried, and I can’t get the block[:foo] version (that makes sense to me) to work. Also, do you have to use :foo, and not “foo”, for example? One typical use for **kw in Python is when you get values in from a form and want to do something with them, and http doesn’t use symbols. ;-)

    Like this, you know:

    def form_validator(**kw):
        for key, value in kw.items():
            validate(key, value)
    

    Or something.

  39. You mean like:
    def x(sym={})
    puts sym[:test]
    end
    x(:test=>”hello world!”)

    which prints:
    hello world!
    ?
    It’s really quite easy and pretty. I’ve seen some pretty cool stuff done with this syntxc. You must use the colon (as you seem to know) because that’s how you tell ruby that the following string is a symbol (which is distinct from a string in ruby although you can interconvert). I don’t know why http not using symbols matters at all. HTTP also doesn’t use arrays or make calls to your functions.

    • Yeah, that’s not useful. In that example, I must pass in :test. The point of the **kw syntax in Python is that you can pass in ANYTHING.

      Note how the code in my form validator above has no idea of what parameters I passed in. If I hard code a symbol in the code, why even use that syntax at all? In your example, I could just as well replace that with def x(test=nil), it works the same.

      And why is this important for web? Because webforms doesn’t use symbols. And yes, HTTP *does* make calls to your functions. That’s the whole point of object publishing, that you use the web browser to make a call to the functions written in Python/Ruby. And mapping forms to method parameters is a basic and practical feature of any webframework, at least in Python, and a part of that is passing arbitrary forms, with **kw.

  40. Oh, I think I know what you want now,
    def x(sym={})
    sym.each_pair{|k,v|
    puts “#{k} => #{v}”
    }
    end
    x(:hi=>”woo”,:foo=>”bar”)
    which prints :
    hi => woo
    foo => bar
    Perhaps you should learn more about ruby first before judging it. “sym” here is just a hash (your dict) and the docs are really clear (http://www.ruby-doc.org/core/classes/Hash.html#M002864). I’d say ruby’s great docs are an overlooked advantage over python (whose organization never made sense to me).

  41. I’m not judging, I’m asking. Perhaps you should stop being so defensive?

  42. Ian F. Hood permalink

    Wow, it took longer to scroll through the comments than the original post!

    There’s nothing new about language wars, not since Babylon.

    I don’t think the end comment was derogatory, It made me chuckle.

    If you really want clean code then smalltalk IMHO is the master, but to use it effectively you must make a paradigm shift into pure objects and away from typical TTL logic languages (which all of the rest of these are). That shift isn’t easy to make and most ‘anti smalltalk’ rhetoric is from those that don’t get it.

    Python is about my 20th language and I chose it quite a few years ago. It keeps me happy so really I don’t care to switch unless there’s a very compelling reason.

    My next language will have to be as different from python as python is from C++ or it’s not really worth the time.

    Oh, that and the fact Python is best ;-)

  43. Andy Fleener permalink

    Lennart, ruby hashes can take strings as values. The convention is to use symbols because they are constants that stay in memory. If you use strings as a key in the has it creates a new block of memory

    def form_validator(kw={})
    kw.each do |key, value|
    #in this case the to_sym isn’t important, just depends no how your validation #is written(whether or not it uses symbols, or strings)
    validate(key.to_sym, value)
    end

    h = { “foo” => “bar” }
    hash.keys.first.class
    >>String
    hash.values.first.class
    >>String

    h = {:foo => “bar”}
    h.keys.first.class
    >> Symbol

    h = {1 => “bar” }
    h.keys.first.class
    >> Fixnum

    So as you can see it doesn’t matter what the key is, symbols are just nice. They can always be converted to strings just in time or vice versa.

  44. Thanks for that Andy, that cleared up some things.

  45. I’m only concerned at all because I’m afraid someone will google for named arguments in ruby and find your post and get confused. This is why I hope you correct this error (ah, it seems you did that, thanks!).

    If I really wanted to get defensive I’d point out that ruby has generators http://ruby-doc.org/stdlib/libdoc/generator/rdoc/index.html and that docstrings are ugly and that mixins are great and that I like constants and that the self notation is annoying and that indentation is tedious. :)

    I understand languages are a personal decision and I use both ruby and python. The main advantage of python over ruby (in fact the real reason I ever use python aside from cases where ruby lacks bindings) is speed.

  46. Could we not all agree on at least one thing?

    PHP[1] really does suck.

    [1] New and improved! Now with extra zing provided by “goto” as of version 5.3 just released.

    http://ca2.php.net/goto
    ;) obligatory smiley face to placate PHP fans.

  47. Here here! Let’s go beat up the php guys! They don’t even count as a scripting language in my book.

  48. Attila Oláh permalink

    +1 for list comprehensions. Combine them with sum(), min() or max(), and you get code that looks more like math then programming. Anyway, I tend to use them a lot…

  49. banisterfiend permalink

    you think ruby guys bash python guys on stack overflow?

    you should check and see how python guys treat ruby programmers on reddit….

  50. Avy permalink

    What amazes me, is how can Python be considered a OO language without concepts of encapsulation and interface ?

    That misconception leaded to the myth of “instance methods in Ruby are not first class objects” because you cannot do
    m = obj.meth
    m()
    You can do this in Python because there is no encapsulation, so you just get the method reference and execute it with the “ugly magick operator that is defined nowhere” ().
    In Ruby, with the strict encapsulation that is the legacy of the true OO language like SmallTalk, you have to pass a message to the object to retrieve its method :
    m = obj.method(:meth)
    m.call

    And then the Pythonistas argued “if the () is not mandatory for method calls, how do you tell if its a method call or an attribute ?”
    Still a misconception by the Pythonistas : there is no such thing as obj.attribute in Ruby. They do not understand OO at all.

    And finally, the ugliest thing in Python :
    class Foo :
    pass
    f = Foo()
    f.response = 42

    works perfectly… so f, an object in the sense of Python has no concept of “interface”… but !!!

    o = object()
    o.response = 42
    craches dramatically…
    So… o and f do not have the same behaviour. So o is not an object, since f IS an object in the Python sense…
    So instance of object are not objects… Oh wait…
    Python Semantic Epic Fail !

    The only reason Python is considered a “OO” language is because there is classes…
    The only reason Pythonistas bash on Ruby, is because they have absolute no idea of what real OO in the sens of SmallTalk is.
    The only reason Python is used over Ruby, is because of libraries… But wait, has Python librairies like Rubygems or Rake ?

    • Python has encapsulation. What you call “strict” encapsulation is a concept that is not needed. Interfaces exist as third-party packages since a long time, and in Python 3 there is abstract base classes. You comment about object instances not being objects is just silly. And yes, Python has libraries like Rubygems and Rake.

  51. Avy permalink

    [quote]
    Python has encapsulation. What you call “strict” encapsulation is a concept that is not needed.
    [/quote]
    Sure, it is not needed. C has no encapsulation… But C does not claim to be a OO language =)
    [quote]
    Interfaces exist as third-party packages since a long time
    [/quote]
    So you say that interfaces are not part of the language but encapsulation do ? It is impossible, as the whole encapsulation/interface/message passing concepts of OO are bounded together…. Oh, you mean the Java interface thing…
    Encapsulation is not “making attributes and methods public or private”. Encapsulation is the concept that the outside cannot access the attributes and cannot call the methods of an object.
    You pass a message to the object. The object looks its interface (and not in the Java sense) and calls the method that correspod to the message. A public method does not mean it can be called from the outside ; it means the method can be called by its owner object in order to respond to a message.
    Saying Python has encapsulation is like saying C has encapsulation because of the structs that can have members.

    [quote]
    You comment about object instances not being objects is just silly.
    [/quote]
    Yep, sure. I’m glad you pointed it.
    Because it just show how silly the whole “built-in” types of Python are.
    Honestly, don’t you find it silly that you can add attributes to an instance of a user class, but not on instances of object ?
    When I see this kind of semantic inconsistencies, I just suddenly feel better about the name inconsistencies in the Ruby std libs, or about the imaginary syntactic inconsistencies the Pythonistas like to bash Ruby for…

    So please elaborate. I’d really like to know your opinion on that.

  52. Lennart Regebro permalink

    Right, C has no encapsulation. And python does.

    Interfaces in the meaning that one class presents different interfaces to different classes based on public/private/etc, has, as mentioned, turned out to be a useless tool. Protecting the class like that doesn’t solve any problems, but causes them.

    You seem to require a strict adherence to all OO concepts for things to be called OO, even if these concepts are negative and outdated and doesn’t make sense in a dynamic language. That’s an attitude I have little sympathy with.

    And your comments about object is still just silly, and you don’t become less silly just because you repeat them. It’s obviously a case of you trying really hard to find negatives with Python, for some sort of emotional/religious reason. Apparently, that’s the best you could come up with, which in itself is a good indicator of how good and consistent Python really is.

  53. Avy,

    Language Smalltalk is *real* OO

    Language Smalltalk has feature F.

    Language X is not Smalltalk.

    Language Y is not Smalltalk.

    Language X has feature F

    Language Y does not have feature F

    You argue that that makes Language X *real* OO and language Y not *real* OO

    …. Things don’t work that way … :-)

  54. sweetsinse permalink

    variable unpacking in python is pretty cool:

    pack = {}

  55. sweetsinse permalink

    heh,

    list/variable unpacking in python is pretty cool:

    pack = { ‘hi’ : ‘there’, ‘big’ : ‘guy’, ‘man’ : ‘dude’, ‘has’ : ‘snake’ }

    res = MyFuction.(**pack)

    –equals–

    res = MyFuction.(hi=’there’, big=’guy’, man=’dude’, has=’snake’)

    can make argument list factories/cleasers, not sure a similar in ruby

    py3k can do things like:

    ( one, *two, three ) = [ 1, 2, 3, 4, 5 ]
    –or–
    # simple comma equals tuple anyway… i like ^ for consistency
    one, *two, three = [ 1, 2, 3, 4, 5 ]

    –equals–

    one = 1
    two = [ 2, 3, 4 ]
    three = 5

  56. Marion M permalink

    Lennart,

    I’m looking to use either Ruby or Python. I found this overview helpful. Although, it did not help me to make a decision, it did help me to see that it really is just a matter of choice. Of course if you have additional ideas of why I’d use one over the other outside of coding, I’m all ears.

    @Avy I have previously used C, C++, and now C# and Java. Personally, it makes no difference to me what is more OO than the other.

    What I want to know about is what does one language do better than the other. Not how you code it. In the end, it’s all just code. I do prefer OO, but not over getting the job done. But I do agree with you about the encapsulation issue. There principles of OO PIE. Without all three, it aint OO.

    Another site I found, but have not yet read, may aid in making a decision. http://www.c2.com/cgi/wiki?PythonVsRuby. Perhaps it will help others as well.

    Thanks.

  57. banisterfiend permalink

    sweetsinse:

    In Ruby:

    pack = [1, 2, 3, 4, 5]

    res = my_function(*pack)

    _equals:_

    res = my_function(1, 2, 3, 4, 5)

    Ruby allows things like the following too:

    x, y, *z = 1, *[2, 3, 4]

    _equals_:

    x = 1
    y = 2
    z = [3, 4]

    and this:

    x, y, z = 1, *[2, 3]

    _equals_:
    x = 1
    y = 2
    z = 3

  58. Find for each Python feature its Ruby equivalent and for each Ruby feature its Python equivalent is basically just stating that you’re missing the big picture.

    You can write with ease some Lisp that mimic the behavior of a for loop, but that do not morph magically Lisp in C.

    Every language comes with its choices, its paradigms, and its way to do things.

    Ruby is truly fun to code, you can write code which is a pleasure to read and thus allowing you to maintain it with ease. Since it’s easy to write and read you can focus on how you need to solve your problem, which design you should use, and so on.

    Yeah you can do this in python too, but in a general manner that’s not why people advise to choose it. Simplicity, only one way to do things, everything is explicit, these are many nice reasons to choose python.

    Moreover, I’ve not read here something I do really consider as crucial to choose between those too.

    If you feel Ruby is magic, you should spend more time studying OO, read more books about design patterns, try to implement a language by yourself and so on. In this context, I use magic as an equivalent too “I have no fucking idea on how it’s done, I did not thought it was even possible”, not its superlative meaning. I would never advice a beginner to start with Ruby, it’s way too dynamic to start with.

    Python is simple, explicit everywhere it can, suited to beginners to gurus, focuses on being useful, and I’m sure you can complete this list in a better way than me.

    Ruby / Python are just both side of the same coin, it’s basically the same thing but with different approach.

    I used to think that programming has to look cryptic. I stepped on Ruby, I discovered that writing code that is simple, classy, good looking is also the better way force me to design it efficiently.

    A shorter way of saying it, is : “If it does not make sense when I’m reading it, I’ve done it wrong.” Just pick : http://github.com/sstephenson/sprockets and read it, I think you’ll see what I’m trying to explain. That’s not a principle invented by Ruby, but everything almost forces you to go in that way.

    Imho, that’s why some people try Ruby, got hooked and never want to come back, because they are feeling damn good while writing.

    Regards,

    jhc_.

  59. First off, I’m a Python guy. I’m actually kind of a Python 1.5 guy, who thinks the language has gotten uglier with each addition. If I had to learn my first serious scripting language today instead of ten years ago, I might pick Ruby over Python, but the reasons have to do with those ten years’ of experience and I already know Python so I’m inclined to stick with it.

    I mention all that because I think you’ve missed an important way in which Ruby blocks are more powerful than anything in Python: a block executes fully within the defining context. A block can modify local variables in its defining context, which a lambda can’t. A block can use a return statement to return from the defining function, whereas a lambda just returns from itself. This allows blocks to be used in macro-like ways that lambdas can’t. Some might say that the flexibility this provides is often abused, yielding unreadable code, and maybe they’re right but that’s not the point. The point is that Python’s lambdas, generators, etc. only cover *some* of the ways that Ruby’s blocks can be used. Dismissing blocks as just another way of doing things you can also do in Python is erroneous.

    • OK, so that’s a genuine difference then. A case of something you can’t do in Python.

      It’s also a case of something you don’t WANT to do, but fine.

  60. Basically you’re saying no to a common concept which is used extensively in every functional language.

    http://en.wikipedia.org/wiki/Closure_(computer_science)

    Truly it’s something you definitively want to do.

    Example : Apple crafted an extension which adds them to C : http://developer.apple.com/mac/articles/cocoa/introblocksgcd.html

    • No I’m, not saying that.

      From the apple page: “Blocks capture read-only copies of local variables, similar to “closures” in other languages”.

      Python does that. This is necessary. The macro-like functionality talked about above in Ruby is something you don’t want. Python doesn’t do that.

  61. re: #3 Ruby 1.9 has “generators” in the form of enumerators [1]

    re: #4 Ruby has a type of multiple inheritance via mixins (or hack arounds [1.5])

    re: #5 Ruby has docstrings–they’re just above the method, in the preceding comments. With 1.9 you can display them at runtime just like python’s docstrings [2].

    If you want named parameters you can do that with a little meta-programming (or with a hash) [3][4].

    If you want more speed ruby 1.9 or jruby is much faster than 1.8.

    My personal take on differences is
    1) Python has a faster runtime. It does, trust me.
    2) Python has less white space. I think I like that, though haven’t done much Python.
    3) Python has more libraries, like multi-process, etc. and is much more popular/support behind it, like google using it, etc.

    There’s really not much bad I can say about it. Except the apparent dislike of closures.

    Back to my Ruby programming because it’s addictive.
    Cheers!
    -r

    [1] http://wiki.github.com/rogerdpack/ruby_code_tutorials/enumerator
    [1.5] http://betterlogic.com/roger/?p=1983
    [2] http://github.com/rogerdpack/method_describer
    [3] http://github.com/maca/arguments
    [4] http://deepfall.blogspot.com/2008/08/named-parameters-in-ruby.html

  62. No, not really. There are some semi-standard tricks to take advantage of how Python variables are bound in objects or nested functions, but they’re not quite the same as real language-supported closures and can’t quite be used in all the same ways [1]. As a result, you get a leaky abstraction that can result in hard-to-diagnose bugs [2]. I’m not sure that closures are All That but, again, claiming equivalence is erroneous.

    True closures are one thing that some people like about Ruby, and others think are a bad idea. True multiple inheritance is one thing that some people like about Python, and that others think is a bad idea. Trying to “trick” either language into providing a semblance of feature from the other is a really effective way to reduce maintainability. Why try to write Ruby in Python, or Python in Ruby? This isn’t Highlander; there can be more than one. ;) Anybody who prefers either language’s features, or is otherwise predisposed to use one instead of the other (as I am predisposed toward Python) should just use it. Variety is good. I’m glad there’s more than one language that doesn’t suck, because there are surely enough that do. That seems like cause for celebration, not argument.

    [1] http://mrevelle.blogspot.com/2005/08/closures-in-ruby-and-python.html
    [2] http://code.activestate.com/recipes/502271/

    • Ah, there are True Closures now, while Pythons closures are False Closures. ;-)

      I stand by my comment that using closures as some sort of macro functionality is something you don’t want to do. I can’t see anything in your links that argue otherwise.

  63. No, it’s not something *you* want to do. I think the fact that you’d say one while meaning the other is telling. Similarly, just because you don’t see something might not mean it isn’t there. If you claim that something does X when in fact it doesn’t satisfy the use cases for X, then it’s your claim that deserves the eye-roll. Dismissing the difference just because you don’t understand it seems more than a bit immature.

    I’m glad that other people enjoy using Ruby. I’m OK with the fact that some things are easier in Ruby. I’ll keep using Python because it’s familiar, and not generalize my own likes and dislikes to everyone.

  64. I don’t say one while meaning the other, there has been no use case presented that isn’t satisfied, I do not dismiss any difference.

    I’m tired of the religious bickering in the comments here. The point of my comments was that language wars were stupid, few who comments seem to understand that.

    The end.

Trackbacks & Pingbacks

  1. Top Posts « WordPress.com
  2. Ruby & Python « My Blog
  3. The Rubyist: July 2009 Edition
  4. ccomb : Open-Source Developers Conference / France 2009

Comments are closed.

Follow

Get every new post delivered to your Inbox.

Join 1,320 other followers

%d bloggers like this: