はじめに
こんにちは。入社早々、在宅勤務となった@sho-hata です。
在宅勤務は通勤時間がないという嬉しい点がある一方、オンオフの切り替えが難しいですね。
さて、今までPythonしか触ってこなかった自分ですが、仕事でRuby on Railsを触ることになり、日々勉強の毎日を過ごしています。
今回は、自分がRuby触り始め第一週ということで、Rubyの公式ドキュメントの「多言語からのRuby入門」の項にある「pythonからRubyへ」を読みながら、Rubyとpythonとのちょくちょく気になる類似点・異なる点を簡単に調べて、まとめてみました。
内容は適宜、追加予定です。
なお、以下全てRubyを主語としています。
Pythonとの類似点
対話型の実行環境がある
めっちゃ便利ですよね。コードをさくっと試したい時とか、インタプリタ型言語の本領発揮って感じです。
Rubyの対話型実行環境
irb
irb(main):001:0>
Pythonの対話型実行環境
python
>>>
ちょっとリッチなPythonの対話型実行環境
ipython
In [1]:
配列(リスト)は可変長配列
組み込みのリストコンテナは、可変長配列です。なので、要素を追加すれば勝手に要素数が大きくなっていく!
array1 = [1, 2, 3] # => [1, 2, 3]
array1[3] = 4 # => 4
array1
# => [1, 2, 3, 4]
Pythonとの異なる点
文字列が可変
Pythonでは、文字列リテラルは変更不可(immutable)です。よって、同値なら同じメモリ上のアドレスを参照します。
str1, str2 = "hoge", "hoge"
str1 is str2 # -> True
id(str1) # -> 140682191246064
id(str2) # -> 140682191246064
※(4/18)追記
文字列の場合、同じ文字列リテラルであれば同じオブジェクトを共有しますが、演算などで文字列を作った場合には同値でも違うメモリ上のアドレスを参照します。
@shiracamus さんよりご指摘いただきました。
以下のように、変数に値の再代入を行う場合には、同値であっても違うメモリ上のアドレスを参照します。再代入時に新しいオブジェクトが生成され、そのリファレンスが変数str2に格納されるためですね。
str1 = "hoge"
str2 = "ho"
str2 += "ge"
str1 == str2 # -> True
str1 is str2 # -> False
id(str1) # -> 140239943766896
id(str2) # -> 140239943767152
変数宣言時に、演算などで文字列リテラルを連結して文字列を作った場合には、同値であれば同じメモリ上のアドレスを参照します。
str1 = "hoge"
str2 = "ho" + "ge"
str1 is str2 # -> True
str1 == str2 # -> True
ただ、変数宣言時に空文字列を生成し、再代入を行った場合には、再代入後の変数のオブジェクトidは同値の変数のidと同じになります。言語って難しい。。。
str1 = "hoge"
str2 = ""
id(str1) # -> 140239943766896
id(str2) # -> 140240212059056
str2 += "hoge"
str1 is str2 # -> True
id(str2) # -> 140239943766896
しかし、Rubyでは文字列リテラルは変更可能(mutable)です。それぞれ異なるメモリ上のアドレスを指しています。
str1, str2 = "hoge", "hoge"
p str1.equal?(str2) # => false
p str1.object_id # => 70220509475900
p str2.object_id # => 70220643515600
ただ、Rubyには、文字列リテラルの代わりとして用いられる、ソース上では文字列のように見え、内部では整数として扱われるシンボルリテラルがあります。
シンボルは不変(immutabule)&メモリ消費が少ないので、よく使われるそうですね。
シンボル何もわからない・・・
※他の方が書かれた参考記事↓
Rubyの文字列とシンボルの違いをキッチリ説明できる人になりたい
定数(値が変更されることを期待しない変数)を作ることができる
Rubyでは、アルファベット大文字で始まる識別子は定数として扱われます。
ここで、
プログラミング言語における定数 = 一度初期化するとその内容を変更することができない
という認識だと思います。
しかし、Rubyでは初期化した定数に再代入することが可能です。(警告が出るため、推奨はされていないっぽい)
よって、再代入時にエラーが出ない。
LANG = "Ruby" # => "Ruby"
LANG = "Python"
warning: already initialized constant LANG
warning: previous definition of LANG was here
# => Ruby
自分としては、Rubyにおける定数=同じオブジェクトidを指す
という思想なのかな?という認識です。
ちなみに、Pythonでは定数はサポートされていませんが、定数として扱う変数(=固定値)を扱う際には、全て大文字とアンダーバー(_)で構成するのが慣例とされています。
PREFIX = 'お疲れ様です'
MAX_COUNT = 255
参考:PEP 8 – Style Guide for Python Code|Python.org
※他の方が書かれた参考記事↓
Ruby 定数について
タプルがない
Pythonには、タプルと呼ばれる、要素が変更不可能なオブジェクトがあります。
用途としては、軽量な要素固定のリストコンテナを作成したい場合や、複数の要素をパック・アンパックする時などに使われていますね。
tuple1 = (1, 2, 3)
tuple2 = 1, 2, 3
type(tuple1) # -> <class 'tuple'>
type(tuple2) # -> <class 'tuple'>
しかし、Rubyでは、組み込みオブジェクトとしてタプルは実装されていません。
ただ、書き方によってはタプルっぽいことはできるそうです。
rb_tuple = [1, 2, 3].map(&:freeze).freeze
rb_tuple[2] = 3
# => FrozenError (can't modify frozen Array)
(参考:RubyエンジニアがPythonをdisるためにPythonを勉強してみた)
elifの代わりにelsifを使う
else ifを表現する書き方として、Rubyではelsifと書きます。
Python では elifと記述しますが、else ifの短縮形としては発音が変わっちゃっていますね。
Rubyの生みの親、Matsさんの発言を拝見すると、どうやら文字数最短と発音のバランスをとっているらしいです。
https://twitter.com/yukihiro_matz/status/1161556434728808448
※他の方が書かれた参考記事↓
Rubyは何故 if else ではなく if elsif なのか
終わりに
同じ動的型付け言語であっても、ちょっとしたところに Python / Ruby 独自の部分が見え隠れしていました。
「言語設計者の方々が、どのような思想で言語を作ったのか」に考えを馳せるのは、新しい言語を勉強するときの醍醐味ですね!
すごい楽しい!