Python for Rubyists — Two Languages That Look Similar but Think Differently
How Ruby blocks, open classes, and implicit returns translate to Python
Ruby and Python were born in the same era as dynamically typed languages. Both influenced by Perl, both claim to prioritize "developer happiness." But use them side by side and the philosophical gap is obvious.
No Blocks
The first wall Rubyists hit in Python.
# Ruby — resource management with blocks
File.open('data.txt') do |f|
puts f.read
end
# Python — with statement (context manager)
with open('data.txt') as f:
print(f.read())
Same result. Different mechanism. Ruby has blocks as a general-purpose construct — any method can yield to a block. Python created a dedicated protocol (__enter__/__exit__) specifically for resource management.
The power of Ruby blocks: you can pass them to anything. 3.times { puts 'hello' } just works. In Python, you'd pass a lambda or function as an argument. Possible, but not as natural.
Expression vs Statement
In Ruby, almost everything returns a value.
# Ruby — if is an expression
status = if score >= 90 then 'A' else 'B' end
# Implicit return — last line is the return value
def greet(name)
"Hello, #{name}"
end
# Python — if is a statement
status = 'A' if score >= 90 else 'B'
# Must write return explicitly
def greet(name):
return f"Hello, {name}"
Forget return in Python and you get None. Ruby habits die hard — you'll debug this at least once.
Open Classes vs Closed Classes
# Ruby — reopen any class anywhere
class String
def shout
upcase + '!!!'
end
end
'hello'.shout # => 'HELLO!!!'
Python built-in types are implemented in C — you can't modify them. Python's philosophy: "Don't touch existing classes." The magic that makes Rails' 3.days.ago possible? Python doesn't do that. More predictable, less expressive.
Enumerable vs itertools + Comprehension
# Ruby — method chaining reads left to right
users.select { |u| u.active? }.map(&:name).first(5)
# Python — list comprehension
[u.name for u in users if u.active][:5]
Ruby's chaining is natural for method chains. Python's comprehension is its own syntax — awkward at first, concise once familiar. But past 3 levels of nesting, comprehensions get hard to read. That's when you miss Ruby's chaining.
Explicit self vs Implicit self
Python's explicit self as the first method parameter irritates every Rubyist.
Python: "Explicit is better than implicit" (PEP 20). Ruby: "Reduce typing for programmer happiness." This difference shows in something as small as self.
Which Is Better?
Wrong question. Ruby optimizes for "code that's pleasant to write." Python optimizes for "code that's easy for anyone to read." Ruby excels at DSLs. Python excels at team consistency.
The hardest part for Rubyists in Python isn't missing features — it's the aesthetic gap. The capabilities are similar. The answer to "what makes good code" is different.
Key Points
Ruby blocks → Python context managers (with) + lambda — general vs dedicated
Ruby has implicit return, Python requires explicit return — forget it and get None
Ruby open classes vs Python sealed built-ins — no monkey patching
Enumerable chaining vs list comprehension — past 3 levels you miss chaining
Explicit self vs implicit self — "Explicit is better than implicit" vs "developer happiness"