Pythonは汎用プログラミング言語の一つで、科学計算のみならずWeb開発、ソフトフェア開発などの広い目的に利用されています。Pythonの特徴として、基本的な言語仕様は書きやすく読みやすいシンプルなものである一方、多くの強力なサードパーティライブラリによって非常に高機能な専門ツールとして使えることが挙げられます。何より言語そのものに加え多くのライブラリがオープンソースで開発されており、フリーで使えるという強みがあります。
近年、NumPy(高速な配列計算)、SciPy(高機能な科学計算)、Matplotlib(描画)などのライブラリの発展に伴って、科学計算ツールとしてのPythonはMatlabなどの有料ソフトに劣らないものとなってきました。Pythonを用いた科学計算ではこれらのライブラリを駆使していくことになるのですが、本稿ではその目的のために必要なPythonそのものの文法を解説します。
本稿はPython 3.6に準拠した解説を行いますが、Python 2系統からの変更点についても言及しています。
まずは伝統に従い、端末にメッセージを出力させてみましょう。Pythonにおいては、print関数を用いて次のように行います。
print("Hello, World!")
print関数は引数としてさまざまな種類のオブジェクト(変数)をとることができます。上の例の場合、引数となっているのは文字列"Hello, World!"です。他の言語と同様に、print関数は変数の値や計算結果を出力するのに使えます。
a = 3
b = 2*a
print(b)
print(a+b)
なお、Python 2においてprintは関数ではなく、print文と呼ばれるものでした(おそらくこれがPython 2と3の最大の違いです)。print文は次のように使います。
print "Hello, World!"
print b
print a+b
つづいて、Pythonによる科学計算に頻出するデータ型(クラス)と、それらの基本的な演算・操作を紹介します。
型の紹介に入る前に、type関数を紹介します。type関数は、引数のオブジェクトの型を返してくれます。対話型環境の場合はtype(変数)、スクリプト実行の場合はprint(type(変数))とすると出力してくれます。
a = 1
b = 1.0
c = "Spam!"
print(type(a))
print(type(b))
print(type(c))
Pythonは動的型付け言語で、変数の定義の仕方によって自動で型が判別されます(上の例の場合、変数aとbは同じ値だが、aは整数、bは実数として判別された)。数の型には整数int、倍精度実数float、複素数complexなどがあります。
my_int = -10 # 整数
my_float = 2.5 # 実数
my_complex = 3 + 2.5j # 複素数
基本的な四則演算を次に示します。
x = 3
y = 2
print(x + y) # 足し算
print(x - y) # 引き算
print(x * y) # 掛け算
print(x / y) # 割り算 (Python 3から、intわるintでもfloatで返してくれるようになった。Python 2ではFortranなどと同じ)
print(x // y) # 割り算(整数部)
print(x % y) # 余り
print(x ** y) # べき乗
論理型はBooleanとも呼ばれ、TrueとFalseの2値のみをとる変数型です(注意: Pythonでは変数名の大文字と小文字を区別します。a=trueやb=TRUEなどとしてもtrueなどが定義されていない限りエラーとなります)。
論理型を返す代表的な演算として、Comparison operatorがあります。以下、Comparison operatorの例を示します。
x = 3
y = 2
print(x == y) # 等しい x,yが数以外のときも用いることができる
print(x > y) # 大なり
print(x < y) # 小なり
print(x >= y) # 大なりイコール
print(x <= y) # 小なりイコール
print(x != y) # ノットイコール
2つの論理型変数の間の論理積、論理和を表す演算子としてandとor、1つの論理型変数の否定を表す演算子としてnotがあります。これらの間の優先順位は
not > and > or
ですが、カッコをつけた方が安全で読みやすい場合も多いでしょう。
a = (1 < 2) # a = True
b = (3**2 < 2**3) # b = False
print(a and b)
print(a or b)
print(a and (not b))
不等式を並べることもできます。
x = 3
y = 5
z = 7
print (4 <= x < 6)
print (4 <= y < 6)
print (4 <= z < 6)
print (0 < x < 4 < y < 7 == z)
4 <= x < 6 は 4 <= x かつ x < 6 と解釈されます。また、0 < x < 4 < y < 7 == z は、 0 < x かつ x < 4 かつ 4 < y かつ y < 7 かつ 7 == z という意味になります。
Pythonには、「配列」に相当する型が複数あります(配列という名前の型は無いのですが、便宜上複数データを格納する型を「配列型」と呼ぶことにします)。Pythonでは配列要素はa[n]のように表され、ここでnは原則0からN-1(Nが配列の長さ)の整数を表します。配列要素のインデックスが0から始まることに注意しましょう。
ここに挙げる配列型のすべてにおいて、配列要素数を得るlen関数を用いることができます。
my_list = [1,2,3,4,5]
my_str = "Hello, world!"
print(len(my_list))
print(len(my_str))
list(リスト)は代表的な配列で、[ ](スクエアブラケット)で囲われていることで特徴づけられます。listの要素の型は統一されている必要はなく、数、論理型、果てはlistやtupleまで、あらゆる型のものを要素として取ることができます。
my_list = [1.0, "orange", [1,2,3]]
print(my_list[0])
print(my_list[1])
print(my_list[2])
print(my_list[2][0])
listの代表的な操作として、appendメソッドとpopメソッドを紹介します。メソッドとはある型の変数(オブジェクトといいます)に固有の関数で、
[オブジェクト名].[メソッド名]([引数])
のかたちで用いられます。
appendはlistの最後に[引数]を付け足すメソッド、popは[引数]番目の要素を取り消すメソッドです。
print(my_list)
my_list.append(3.14)
print(my_list)
my_list.pop(1) # インデックスは0から始まることに注意
print(my_list)
listのその他の操作はこちらに詳しいです。
tuple(タプル)はlistと並び代表的な配列で、( )(丸カッコ)で囲われていることで特徴づけられます。 listとtupleの最大の違いは、listでは要素の書き換えが行えるのに対して、tupleはそれを許さないということです。
my_tuple = (1.0, [1,2,3], 3.14)
print(my_list)
print(my_tuple)
my_list[2] = "replaced"
print(my_list)
my_tuple[2] = "replaced?" # raises TypeError
str(ストリング、文字列型)はその名の通り文字列の型で、' '(シングルクォーテーション)または" "(ダブルクォーテーション)によって生成されます。インデックスによって「何文字目」かを表現するというように、配列的な操作が行われます。
my_str = "abc"
print(my_str)
print(my_str[0])
strどうしの結合はconcentrationと呼ばれ、+(足し算)で行うことができます。
new_str = my_str + "def"
print(new_str)
配列のなかでもlist, tuple, strは0からN-1(Nは要素数)の整数でインデクシングが行われています(要素に順序がある)。これらの型ではFortranなどと同様に部分配列を得る操作が行えます(スライスと呼ばれます)。スライスの文法は、
a[start:stop:step]
のようになっています。ここでstartは部分配列の始まりのインデックスで、省略するとaの始まり(0)となります。stopは部分配列の終わりのインデックスで、省略するとaの終わりとなります。注意すべきなのは、a[stop]の要素自体はスライスされた部分配列に含まれないということです。 stepはスライスする要素の間隔を指示し、省略すると(stepの前のコロンから省略できます)startとstopの間のすべての要素を抜き出します。
my_list = [0,1,2,3,4,5,6,7,8,9]
slice1 = my_list[2:5] # my_list[5]を含まないことに注目
slice2 = my_list[1:8:3] # 1から8まで(8を含まない)、増分3(2つおき)
slice3 = my_list[8:] # 8から終わりまで
slice4 = my_list[::-1] # 9から0まで1つずつ減っていく: stepが負の時はstartおよびstopのデフォルト値が入れ替わる
print(slice1)
print(slice2)
print(slice3)
print(slice4)
list, tuple, strのインデックスは原則0からN-1(Nは要素数)の整数ですが、-Nから-1までの負の数をインデックスに用いることができます。
a[-1]=a[N-1], a[-2]=a[N-2], ..., a[-N]=a[0]
を意味します。
その他たまに使う配列型として、整数ではなく文字列でインデクシングを行うdictionaryや、要素の順序を区別せず、またダブった要素を同一視するsetなどが挙げられます。
my_dict = {"Jim": 10, "Alex": 20, "Mike": 30} # dictionary
print(my_dict["Alex"])
my_set = {4,7,8,9,4,5,8,9,0} # set
print(my_set)
オブジェクト指向型言語であるPythonでは、ユーザーが新たな型(クラス)を定義する際に、そのデータ構造だけでなく演算規則(+,-,...)や多様なメソッドまでも定義することができます。自らクラスを定義して洗練されたコード運用を行うまでいかなくても、ライブラリを使用するときにユーザー定義型のお世話になることはよくあります。その中で最も重要な例として、NumPy ndarrayオブジェクトが挙げられます。NumPy ndarrayはNumpyモジュールで定義されるユーザー定義型で、多次元配列(数を要素とする)を高速に扱うことができます(実際の運用においてデータ格納のためにlistやtupleを用いると、多くの場合遅くて使えたものではありません)。NumPy Arrayの詳しい使い方はここでは述べませんが、以下にユーザー定義されたNumPy ndarrayの演算規則やメソッドの例を示します。
import numpy as np # NumPyモジュールのインポート: モジュールのインポートについては後述
my_arr1 = np.arange(10) # NumPy Arrayの生成
my_arr2 = np.arange(0,20,2)
print(type(my_arr1))
print(my_arr1)
print(my_arr2)
print(my_arr1 + my_arr2) # 要素ごとの足し算
print(my_arr1.sum()) # 和をとるメソッド
Fortranなどの言語と同様に、[型の名前]([変換する変数])のようにして型の変換を行うことができます。
print(str(123)) # int -> str
print(complex(-10.0)) # float -> complex
print(tuple(['a',1, 1.5])) # list -> tuple