BETA

PythonとRubyの違い

投稿日:2019-03-10
最終更新:2019-03-18

作りかけだけど、疲れたのでひとまず公開することにする。追加・修正を募集中。

思想編

思想 Python Ruby
開発者達 現実主義者/実践主義者 理想主義者/完璧主義者
TMTOWTDI やり方は一つ 多様性は善
より良いやり方 強制する 洗脳する
よくやるやり方 明示する 暗示する
規則の決め方 実用性重視 整合性重視
オブジェクト指向 構成要素の一つだが縛られない 根幹をなす
関数型プログラミング 構成要素の一つだが縛られない 思想のみ取り入れる
最終決定機関 PEPの採択 Ruby Issue Tracking Systemでの議論

Pythonは現実主義者の理想解であり、Rubyは理想主義者の現実解である。Pythonは実践主義者の追求によって成り立ち、Rubyは完璧主義者の妥協によって成り立つ。Pythonの文法は「わかりやすさ」や「シンプルさ」と言った感性的な面の善し悪しで採用が決定される。Rubyの文法は「純粋さ」や「無矛盾性」といった理性的な面の有り無しで採用が決定される。設計思想は似て非なる物と言わざるを得ない。

文法編

文法 Python Ruby
ブロックを伴う構文^1 ほとんどが文 全てが式
デフォルト引数 デフォルト値 デフォルト式
代入 =
=:
=
左辺値 有り 無し
条件 if
if
if
後置if
? :三項演算子
内包表記 for in n/a
構文ブロック インデント end
モジュール/名前空間 ファイル単位 moduleで作成
他ファイル読み込み import requireメソッド
関数 全てが関数 実体はメソッド
メソッド 実体は関数 全てがメソッド
関数呼び出し f() 関数として呼び出し レシーバーをselfとしてメソッド呼び出し
メソッド呼び出し a.f() レシーバーが属性を持つ場合: その属性に対する関数呼び出し
レシーバーが属性を持たない場合: レシーバーのクラスまたはその親クラスの属性をレシーバーが第一引数として部分関数化したmethodオブジェクトに対する関数呼び出し
レシーバーの特異クラスまたはクラスまたはその親クラス(Mixinされたモジュール含む)のインスタンスメソッド呼び出し
プロパティ読み込み a.x レシーバーが属性を持つ場合: その属性
レシーバーが属性を持たない場合: レシーバーのクラスまたはその親クラスの属性、ただし、属性が関数である場合はその属性をレシーバーが第一引数として部分関数化したmethodオブジェクト
引数無しのメソッド呼び出し
プロパティ書き込み a.x = y 属性に対する代入 名前=のメソッド呼び出し
関数オブジェクト 第一級オブジェクト n/a(ProcやMethodがその役割を担う)
インスタンスメソッド 関数オブジェクトであるクラスの属性(インスタンスからの呼び出し時はmethodオブジェクトにラップされる) クラスのインスタンスメソッド
クラスメソッド 関数オブジェクトまたはclassmethodオブジェクトであるクラスの属性 クラスの特異クラスのインスタンスメソッド
スタティックメソッド staticmethodオブジェクトであるクラスの属性 n/a
特定オブジェクト専用のメソッド オブジェクトの属性(関数オブジェクト) オブジェクトの特異クラスのインスタンスメソッド
トップレベルでの関数/メソッド 関数(モジュールスコープ) Objectのプライベートインスタンスメソッド(グローバルスコープ)
ラムダ式 lambda単一式のみ ->複合式可能
変数宣言 代入 代入
ローカル変数 クラスや関数内で代入された変数 先頭小文字
グローバル変数 n/a 先頭$
モジュール変数 トップレベルローカル変数 先頭大文字(ただし、再代入すると警告が表示される定数扱い)
インスタンス変数 インスタンスの属性 先頭@
クラス変数 クラスの属性 先頭@@
クロージャー 関数(内部で代入する場合はgloablを使って明示する必要あり) doブロック(同名のブロックローカル変数は使用不可)
リテラル 整数、浮動小数点数、複素数、文字列、シーケンシャル(リスト)、タプル集合、連想配列(辞書) 整数、浮動小数点数、有理数、複素数、文字列、シンボル正規表現、シーケンシャル(配列)、連想配列(ハッシュテーブル)
整数 多倍長整数 多倍長指数
浮動小数点数 IEEE 754 binary64 IEEE 754 binary64
複素数の要素 浮動小数点数 整数、浮動小数点数、有理数
虚数リテラル j i
シーケンシャル リスト(list) 配列(Array)
連想配列 辞書(dict) ハッシュテーブル(Hash)
連想配列のキー ハッシュ可能な任意のオブジェクト ハッシュ可能な任意のオブジェクト
文字列 変更不可 変更可能(不変化可能、リテラルについてはバージョンやfrozen_string_literalマジックコメントによって異なる)

「グローバル変数」はモジュールの内外を問わず使える変数のことを意味する。浮動小数点数はPythonもRubyも実装依存だが、ほとんどのプラットフォームにおいてIEEE 754 binary64(倍精度浮動小数点数)になっている。

やり方編

目的 Python Ruby
リスト処理 リスト内包表記 メソッドチェーン

標準スタイルガイド編

文法 Python Ruby
インデント スペース4個 スペース2個
ローカル変数 snake_case snake_case
組み込み型(クラス) smallcase UpperCamelCase
クラス UpperCamelCase UpperCamelCase
パッケージ名 smallcase snake_case
モジュール名 smallcase UpperCamelCase
関数/メソッド snake_case snake_case
定数 n/a SCREAMING_SNAKE_CASE
特殊名 __smallcase__ __smallcase__
グローバル変数 snake_case $SCREAMING_SNAKE_CASE
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@raccyの詩集

よく一緒に読まれる記事

5件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
03/16 20:20

pythonについて気になった点が幾つかあったので、書いてみます。

オブジェクト指向 構成要素の一つだが重要では無い

すべてがオブジェクトなので重要では無いとは言いづらいと思います。プリミティブ型を持つJavaなどよりオブジェクト指向を徹底しているという議論も成立します。トップレベル関数が駄目ならJavaScriptなどはオブジェクト指向言語ではないことになります。

文と式 ほとんどが文

これについてはそう判断した根拠を聞きたいところです。半々くらいだと思いますが。

インスタンスメソッド クラスの属性(関数オブジェクト)

methodオブジェクトがインスタンスの属性として生じてそこからクラスの属性である関数オブジェクトを呼びに行くという流れなので、この説明は間違いです。

03/17 00:56

hayataka2049さん

Pythonのオブジェクト指向感

Pythonのオブジェクト指向への考え方は下記の記事を参考にしています。

len が py3k でも 関数のままである理由 - methaneのブログ

オブジェクト指向的であるよりもわかりやすさを追求するのがPythonであり、いかなる場合もオブジェクト指向的であろうとするRubyとは対称的です。ただ、オブジェクト指向が扱えないと言う意味ではありません。

Pythonの式と文

言語リファレンスを見る限り、リテラル、演算、変数、関数呼び出しといった通常式と考えられるもの以外の式は

  • 6.2.9. Yield 式
  • 6.4. Await 式
  • 6.12. 条件式

ぐらいしかないと思い、ほとんどが文と表現いました。3.8ではここに代入式が追加されることでしょうが。while 文や関数定義などは全て文です。

本当は代入や条件のところのように一個一個書いていく予定だったんですが、力尽きました。

インスタンスメソッドを持っている属性

インスタンス生成時にクラスの属性を参照するmethodオブジェクトが作られてしまうのですね。これは私が勘違いでした。修正しておきます。

03/17 01:42

インスタンスメソッドはインスタンスの属性だと思ったけど、__dict__に現れないし、よくわからなくなってきたぞ。hayataka2049さんの説明だとインスタンス生成時に生成されるような気がしたんですが、違うんですかね。誰か修正案を書いてください。

03/17 19:11

オブジェクト指向に関して

そういう捉え方があるのは理解しています。ただ、オブジェクト指向そのものは(少なくともpython3では)言語の根幹をなしている要素なので、重要ではないというのは言い過ぎに思えます。「オブジェクト指向的なコーディングを強要しないが、内部はオブジェクト指向」とでも言えば良いのでしょうか。

文に関して

「通常式と考えられるもの以外」という前提が伝わりにくいので、脚注でもつけるか、単に「式と文の両方がある」とした方が良いかと。

インスタンスメソッドに関して

すみません、説明が悪かったです。 methodオブジェクトはメソッドへのアクセス時に生成されます。大雑把な流れとしては、 メソッドを参照→インスタンスメソッドの属性を検索→__dict__など通常の属性になければメソッドとみなしてクラス階層から検索→見つかったらmethodオブジェクトでwrapして返す となります。

インスタンスの非データ属性が参照されたときは、そのインスタンスのクラスが検索されます。その名前が有効なクラス属性を表している関数オブジェクトなら、インスタンスオブジェクトと見つかった関数オブジェクト (へのポインタ) を抽象オブジェクト、すなわちメソッドオブジェクトにパックして作成します。

https://docs.python.org/ja/3/tutorial/classes.html#method-objects

関数オブジェクトからインスタンスメソッドオブジェクトへの変換は、インスタンスから属性が取り出されるたびに行われます。

https://docs.python.org/ja/3/reference/datamodel.html#the-standard-type-hierarchy

こういう実行例を見るとわかりやすいのではないでしょうか。

>>> class Hoge:
...     def f(self):
...         print("hoge")
... 
>>> Hoge.f is Hoge.f  # クラスに属する関数オブジェクトはひとつだけ
True
>>> hoge = Hoge()
>>> hoge.f is hoge.f  # インスタンスに属するmethodオブジェクトは参照するたびに生成
False
>>> a, b = hoge.f, hoge.f
>>> id(a), id(b)
(140198419984776, 140198419693064)
>>> tmp = hoge.f
>>> Hoge.f = lambda self: print("aaa")
>>> tmp()  # こちらは変化なし
hoge
>>> hoge.f()  # hoge.fが新しく作られるのでクラスへの変更が反映される。
aaa
03/18 18:39

hayataka2049さん

色々書き替えました。

おぶじぇ・・・

「縛られない」って表現に変えてみました。ついでに関数型についても。

ぶん・・・

「ブロックを伴う構文」と制限してみました。なんか、フッタの使い方がおかしい気がしますが、Qrunchでのやり方がよくわからない。

いんすた・・・

どうしたら良いのか凄く迷いました。インスタンスをレシーバーとしたメソッド呼び出しについてはその上で説明しているつもりでした。そのうえで、実体はどこにあるんだと言うことで「クラスの属性」という表現をしたつもりです。

メソッド呼び出しのことしか書いていないこともあったので、プロパティ読み書きを追加して、インスタンスメソッドの部分にも注釈を入れるようにしてみました。

だんだん素人向けの説明じゃ無くなっている気がしますが、初めからそうでは無いので、そういうことにしておきます。


それにしてもQrunchはQiitaに比べてMarkdownがなんかおかしいし、書きにくい。Qiitaにポエムは書かないって方針にしているから、こっちに書いたけど、失敗だったかな。

目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!