As my coding has moved from Ruby to Python, I've noticed a few fundamental differences between the two over the last year or so.

The first interesting difference was that Ruby is likely to return nil if a hash key or an instance @variable doesn't exist, whereas Python will throw a KeyError or AttributeError when the same situation occurs. This can best be summed up by line 2 of the Zen of Python: https://www.python.org/dev/peps/pep-0020/#id3

Explicit is better than implicit.

Python doesn't do things that you might not expect from it, and always raises an error rather than doing something that assumes your intent or use-case as a developer.


1. Requesting a non-existent key from a Hash/dict

In Ruby, you start to find NoMethodError: undefined method 'blah' for nil:NilClass in all sorts of places. This is often due to ruby's style of returning nil if a hash key does not exist

  • Ruby returns nil, Python raises KeyError
 00:14:05 │ ☯ ~ irb
2.5.1 :001 > h = {'a' => 'b'}
 => {"a"=>"b"}
2.5.1 :002 > h[1]
 => nil
 00:15:18 │ ☯ ~ ipython
Python 3.7.2 (v3.7.2:9a3ffc0492, Dec 24 2018, 02:44:43)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: d = {'a': 'b'}

In [2]: d
Out[2]: {'a': 'b'}

In [3]: d[1]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-3-abe283337115> in <module>
----> 1 d[1]

KeyError: 1

2. Accessing a non-existent instance variable

This is the same behaviour described above, I found this one quite surprising at the time when I discovered it, breaking my tests due to accessing a variable name with a typo, e.g. @line_counnter += 1.

 00:09:27 │ ☯ ~ irb
2.5.1 :001 > class Testr
2.5.1 :002?>   def initialize(a)
2.5.1 :003?>     @a = a
2.5.1 :004?>     end
2.5.1 :005?>   def test
2.5.1 :006?>     puts @a
2.5.1 :007?>     puts @b["something"]
2.5.1 :008?>     end
2.5.1 :009?>   end
 => :test
2.5.1 :010 > Testr.new(1).test
1
Traceback (most recent call last):
        3: from /Users/freman/.rvm/rubies/ruby-2.5.1/bin/irb:11:in `<main>'
        2: from (irb):10
        1: from (irb):7:in `test'
NoMethodError (undefined method `[]' for nil:NilClass)
 00:11:30 │ ☯ ~ ipython
Python 3.7.2 (v3.7.2:9a3ffc0492, Dec 24 2018, 02:44:43)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: class Testr(object):
   ...:     def __init__(self, a):
   ...:         self.a = a
   ...:     def test(self):
   ...:         print(self.a)
   ...:         print(self.b)
   ...:

In [2]: Testr(1).test()
1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-2-3abdbcf221c3> in <module>
----> 1 Testr(1).test()

<ipython-input-1-ee0b9957b45a> in test(self)
      4     def test(self):
      5         print(self.a)
----> 6         print(self.b)
      7

AttributeError: 'Testr' object has no attribute 'b'