Python vs. Ruby: A Battle to The Death by Gary Bernhardt¶
| ruby | python | vs | comparison |
- Ruby Experience
- I. Ruby Complaints
- The Zen of Python (PEP-20)
- 8. Special cases aren’t special enough to break the rules
- 13. There should be one and preferably only one obvious way to do it
- 16. Although never is often better than right now
- 17. If the implementation is hard to explain, it’s a bad idea
- 19. Namespaces are one honking great idea - let’s do more of those!
- The Zen of Python (PEP-20)
- II. Ruby Praise
- References
Ruby Experience¶
end
for block- () are optional
- method name can be ended in
!
or?
I. Ruby Complaints¶
The Zen of Python (PEP-20)¶
- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Flat is better than nested.
- Sparse is better than dense.
- Readability counts.
- Special cases aren’t special enough to break the rules.
- Although practicality beats purity.
- Errors should never pass silently.
- Unless explicitly silenced.
- In the face of ambiguity, refuse the temptation to guess.
- There should be one– and preferably only one –obvious way to do it.
- Although that way may not be obvious at first unless you’re Dutch.
- Now is better than never.
- Although never is often better than right now.
- If the implementation is hard to explain, it’s a bad idea.
- If the implementation is easy to explain, it may be a good idea.
- Namespaces are one honking great idea – let’s do more of those!
8. Special cases aren’t special enough to break the rules¶
Very strange behavior
>> x = Proc.new { 5 }
>> x()
NoMethodError: undefined method `x' for main:Object
>> x.call
5
>> x[]
5
13. There should be one and preferably only one obvious way to do it¶
Yukihiro Matsumoto: Ruby inherited the Perl philosophy of having more than one way to do the same thing. I inherited that philosophy from Larry Wall, who is my hero actually. I want to make Ruby users free. I want to give them the freedom to choose. People are different. People choose different criteria. But if there is a better way among many alternatives, I want to encourage that way by making it comfortable. So that’s what I’ve tried to do. Maybe Python code is a bit more readable. Everyone can write the same style of Python code, so it can be easier to read, maybe. But the difference from one person to the next is so big, providing only one way is little help even if you’re using Python, I think. I’d rather provide many ways if it’s possible, but encourage or guide users to choose a better way if it’s possible. - Reference: The Philosophy of Ruby.A Conversation with Yukihiro Matsumoto, Part I by Bill Venners. September 29, 2003
16. Although never is often better than right now¶
Then Ruby v.1.8.6
>> ['a', 'b'].map(&:upcase)
TypeError: wrong argument type Symbol (expected Proc) form (irb):4
>> require 'activerecord'
=> true
>> ['a', 'b'].map(&:upcase)
=> ["A", "B"]
&:foo
Ruby 1.8.7: &:foo
syntax added Now
>> ['a', 'b'].map(&:upcase)
=> ["A", "B"]
17. If the implementation is hard to explain, it’s a bad idea¶
- Python grammar dependency graph. Generated from this Python 2.3.3 grammar from antlr.org.
- Ruby 1.8.4 grammar dependency graph
Ruby Grammar¶
Python Grammar¶
19. Namespaces are one honking great idea - let’s do more of those!¶
>> require 'activerecord'
>> ActiveSupport
=> ActiveSupport
II. Ruby Praise¶
Good part
Composability¶
Python lacks this feature
'\n'.join(obj.name
for obj in (
repository.retrieve(id)
for id in ids
)
)
ids.map do |id|
repository.retrieve(id)
end.compact.map do |obj|
obj.name
end.join('\n')
- Python has
comprehensions
andsum
- Ruby has the full Lisp chainsaw
RSpec¶
# game_spec.rb
describe Game do
describe "#score" do
it "returns 0 for an all gutter game" do
game = Game.new
20.times { game.roll(0) }
expect(game.score).to eq(0)
end
end
end
lambda do
MyClass.add(2, 'foo')
end.should raise_error(TypeError)
matz.should have_item(chain_show)
Python Mote (spec runner)¶
from __future__ import with_statement
from expecter import expect
def describe_integer():
def describe_when_adding_one_and_one():
x = 1 + 1
def should_get_two():
assert x == 2
def raises_error_when_dividing_by_zero():
with expect.raises(ZeroDivisionError):
1 / 0
# Output:
#
# integer
# integer when adding one and one
# - should get two
# - raises error when dividing by zero
# OK
WARNING! Extreme Opinions Ahead!¶
At the beginning: Ruby is ugly; Python is beautifyl. Then: Nose is ugle; RSpec is beautiful.
Cucumber¶
# features/step_definitions/coffee_steps.rb
Given /there are (\d+) coffees left in the machine/ do |n|
@machine = Machine.new(n.to_i)
end
# features/step_definitions/coffee_steps.rb
Then "I should be served coffee" do
@machine.dispensed_drink.should == "coffee"
end
References¶
- Vimeo: Python vs. Ruby: A Battle to The Death
- This talk was given at Northwest Python Day 2010. The companion blog post is at blog.extracheese.org/2010/02/python-vs-ruby-a-battle-to-the-death.html
- Blog post: Python vs. Ruby: A Battle to The Death