pythonとperlについて気になる仕様の違い

仕事でどうしてもpythonのコードを書く必要に迫られました。今や学生の間でも飛ぶ鳥を落とす勢いのある数値計算系では無く、非同期通信やプロセス間通信といった泥臭い分野のコーディングをpythonで行うというテーマです。この分野は仕事ではperlを多用して来たわけですが、今ではperlはコードとしての資産価値が無いと思っている人がたくさんいるらしいです。悲しい限りですが。

pthonの一般的な情報に関して備忘録を何回かに分けて記事にしようと思います。

違和感

まずは違和感を覚えたperlとの仕様の違いについて思い付く限り書いておきます。

(1){}が無い!

慣れている人には当たり前なんだと思いますが、pythonには{}によるブロック定義が無いんです。ブロックは、最初の行末に「:」を置いて、その下方に半角4文字分のインデントで記述された行がひと固まりのブロックということになります。forループもif文も全てこのルールに従います。この制約は私のコーディング速度に著しく影響しました。見栄えは良くなりますけどね。

(2)main()を使いたくなるわけ

pythonでは、関数は定義した後でしか使うことができません。別の関数内で使用する関数は、後で定義されていても実行することができます。

print(hello())
def hello():
print('Hello!!')

このコードはエラーになりますが、下記であればエラーになりません。別にmain()内のコードを関数定義が終わった最後に記述すれば良いだけなんですが。

def main():
print(hello())
def hello():
print('Hello!!')
main()

(3)if __name__ == "__main__": って何?

pythonでは様々な便利なモジュールを使用するために、「import」文を使用します。perlにもimport文は存在するのですが、私はほとんど、use (Module名)しか使いません。これは、BEGIN { require (Module名); import (Module名; }と等価です。

もし上記のような普通のpythonコードをimportすると、importした時にmain()が実行されてしまいます。「if __name__ == "__main__":」は、「__name__」変数の値が「'__main__'」であるとき(=importでは無く直接実行されたとき)のみmain()を実行することができるということです。上記の場合下記のようになります。

def main():
print(hello())
def hello():
print('Hello!!')
if __name__ == "__main__":
main()

perlでは、「if ($0 eq __FILE__) {}」とすれば良いようです。スクリプト名($0)が実行ファイル名(__FILE__関数が返す値)に等しい場合は、importによる実行では無くて直接実行ということになります。しかし、perlではpackage宣言されているモジュールしか使わないので、使う必要性が正直わかりません。

(4)集合型

pythonには標準で「集合型(set型)」という変数型が有ります。リスト(配列)型の重複要素が除かれたような型です。今回の仕事では、futureオブジェクト(別記事にて登場)の集合を定義しましたが、あまり、型の恩恵を受けた使用方法ではありませんでした。この型同士は、集合演算が標準でできるようです。perlでは、モジュール「Set::Object」を使うと結構便利だそうです。

(5)pythonの関数への引数は全て参照渡し(?)

これが結構な違和感でした。pythonの変数には、イミュータブル(宣言後値を変更不可能)な型とミュータブルな型(宣言後値を変更可能)があり、前者には文字列型、数値型があり、後者にはリスト型などがあります。

結論を言うと、pythonの引数は全て参照渡しですが、その引数がイミュータブルの場合は値渡しの挙動となり、ミュータブルの場合は参照渡しの挙動となります。

イミュータブルの場合、関数内で引数の値を変更すると、その参照を採番し直すため呼び出し元の値に影響を与えないのです。ミュータブルの場合は採番し直さないため、その値が呼び出し元でも変更されます。下記ではこの事を大変わかりやすく説明しています。

Pythonの引数における参照渡しと値渡しについて

ちなみに、pythonではid()関数を使って様々な型の変数の参照値を得ることはできますが、あからさまな「リファレンス(参照)」という変数型がありません。したがってperlの様にリファレンス変数を使った様々な便利なコードを書くことができません。