Ruby公式「Pythonとの違い」から学ぶ、Pythonの「Rubyとの違い」
はじめに
隔週で開催される社内勉強会で、Python の基本的な言語仕様を紹介するために Ruby 公式の「PythonからRubyへ」というドキュメントを用いた回が意外に盛り上がったので記事にします。
Ruby コミュニティのメンバーによって運営されている Ruby 公式サイトに掲載されているドキュメントで、Python 使いが Ruby と Python の言語仕様の違いを理解するのにぴったりな内容となっています。
今回、こちらのドキュメントの「Python との違い」の章を一部「Ruby との違い」に読み替えて、Ruby 使いに向けた Python との言語仕様の比較を行いたいと思います。
Rubyと違って、Pythonは…
Pythonと違って、Rubyは…
引用: PythonからRubyへ
文字列は不変です。
文字列は可変です。
引用: PythonからRubyへ
Python では文字列がデフォルトで不変、つまりイミュータブルです。文字列オブジェクトの状態を変更することはできません。
text = "abc"
text[0] = "A"
text
# "Abc"
text = "abc"
text[0] = "A"
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: 'str' object does not support item assignment
定数がサポートされていません。
定数(値が変更されることを期待しない変数)をつくれます。
引用: PythonからRubyへ
Python では、定数は慣習的な存在で、厳密には言語としてサポートされていないので再代入ができてしまいます。
MAX_COUNT = 10
MAX_COUNT = 0
# (irb):24: warning: already initialized constant MAX_COUNT
# (irb):23: warning: previous definition of MAX_COUNT was here
# => 0
MAX_COUNT = 10
MAX_COUNT = 0
PEP8 に記載されている定数の命名規約(大文字で命名しアンダースコアで単語を区切る)は、Ruby と同じです。
Python3.8以上であれば typing.Final
型ヒントが使えるので、静的解析時に型エラーで定数への再代入を防ぐことができます。
from typing import Final
MAX_COUNT: Final[int] = 10
リストコンテナは、リスト・タプル・集合など複数あります。
リストコンテナは、配列しかありません。配列は可変です。
引用: PythonからRubyへ
Python には組み込みコンテナとしてリスト・タプル・集合などがあります(他にも辞書がありますが、Ruby のハッシュと比較するべきなのでここでは省略します)。
リストは基本的に Ruby の配列と同様でミュータブルなコンテナです。
animal_list = ["dog", "cat", "bird"]
animal_list[0] = "lion"
animal_list
# ['lion', 'cat', 'bird']
イミュータブルにしたい場合は、タプルを用います。
animal_tuple = ("dog", "cat", "bird")
animal_tuple[0] = "lion"
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# TypeError: 'tuple' object does not support item assignment
重複を許したくない場合は、集合を用います。
animal_set = {"dog", "cat", "bird"}
animal_set.add("dog")
animal_set
# {'dog', 'bird', 'cat'}
Python2系とPython3系では完全な互換性がありません。
クラスに新しいスタイル・古いスタイルといったものはありません (Python3からはこの問題はなくなりました。けれど、Python2との完全な後方互換性はありません)。
引用: PythonからRubyへ
Python2系は2020年でサポートが終了しています。
例えば、Python2系では print
が括弧無しで書けたのに対し、Python3系では print
関数になり括弧が必要になりました。
print("Hello World!!")
# Hello World!!
print "Hello World!!"
# File "<stdin>", line 1
# print "Hello World!!"
# ^^^^^^^^^^^^^^^^^^^^^
# SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
コード自動変換ツールが公式で提供されています。
属性に直接アクセスできます。
属性には直接アクセスできません。 Rubyでは、属性へのアクセスはすべてメソッド経由になります。
引用: PythonからRubyへ
Ruby では、属性へのアクセスはすべてメソッド経由で行いますが、Python ではオブジェクトの属性に直接ドット(.
)演算子を使ってアクセスすることができます。
class User:
def __init__(self, name):
self.name = name
user = User("taro")
user.name
# "taro"
これにより、簡潔で直感的なコードを書くことができますが、属性に直接アクセスすることが制限されないので、アンダースコアを用いてアクセス制御をするなど、ある程度考慮をする必要があります(後述)。
メソッド(関数)呼び出しの括弧は必須です。
メソッド呼び出しの括弧は基本的にオプションです。
引用: PythonからRubyへ
def add(a, b):
return a + b
add(1, 2)
# 3
add 1, 2
# File "<stdin>", line 1
# add 1, 2
# ^
# SyntaxError: invalid syntax
メソッドや属性のアクセス制御をアンダースコアの数によって実現しています。
Pythonでアンダースコアの数によって実現しているアクセス制御は、 public、private、protectedを使って行います。
引用: PythonからRubyへ
Python では、1つのアンダースコア(_
)で始まるメソッドや属性は、慣習的に外部から隠蔽するプライベートであることを表します。実際にアクセス制御がされているわけではないので、アクセスすることはできてしまいます。
2つのアンダースコア(__
通称ダンダー:double underscore)で始まるメソッドや属性は、ネームマングリングが適用されるので、厳密なプライベート化が実現できます。
class User:
def __init__(self, name):
self.name = name
self._name = name
self.__name = name
user = User("taro")
user.name
# "taro"
user._name
# "taro"
user.__name
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# AttributeError: 'User' object has no attribute '__name'. Did you mean: '_name'?
Mix-inの代わりに多重継承を使います。
多重継承の代わりにMix-inを使います。
引用: PythonからRubyへ
Python では、Ruby の Mix-in と同様の機能を実現するために、多重継承を利用します。
class LoggerMixin:
def hello(self):
print(f"Hello!! I'm {self.name}")
class BaseUser:
def __init__(self, name):
self.name = name
class User(BaseUser, LoggerMixin):
pass
user = User("taro")
user.hello()
# Hello!! I'm taro
組み込みクラスにメソッドを追加したり、書き換えたりできません。
組み込みクラスにメソッドを追加したり、書き換えたりできます。 どちらの言語でも任意の時点でクラスを開いたり編集できますが、 Pythonでは組み込みクラスに対してはそれは許可されていないのに対し、 Rubyではその制限はありません。
引用: PythonからRubyへ
trueとfalseは、TrueとFalseになります。 また、nilの代わりはNoneになります。
TrueとFalseは、trueとfalseになります。 また、Noneの代わりはnilになります。
引用: PythonからRubyへ
is_true = True
is_false = False
is_none = None
if is_true:
print("This is true.")
if not is_false:
print("This is not false.")
if is_none is None:
print("This is None.")
真か偽かの判定では、FalseとNone以外に0、0.0、""、[]なども偽と評価されます。
真か偽かの判定では、falseとnilのみが偽と評価されます。 それ以外の値(0、0.0、""、[]など)はすべて真と評価されます。
引用: PythonからRubyへ
false = False
none = None
zero = 0
float_zero = 0.0
empty_string = ""
empty_list = []
if not false:
print("Falseは偽")
if not none:
print("Noneは偽")
if not zero:
print("0は偽")
if not float_zero:
print("0.0は偽")
if not empty_string:
print("空文字列は偽")
if not empty_list:
print("空配列は偽")
elsifの代わりにelifを使います。
elifの代わりにelsifを使います。
引用: PythonからRubyへ
x = 10
if x > 10:
print("xは10より大きい")
elif x < 10:
print("xは10より小さい")
else:
print("xは10です")
株式会社オープンエイトのテックブログです!カジュアル面談大歓迎ですー!エンジニア積極採用中 👉 open.talentio.com/r/1/c/open8/homes/3396
Discussion