pythonに関する基礎事項¶
python3¶
python2は2020年1月1日でサポートが切れています。 特別な理由がない限りはpython3を使いましょう。 python2のインタープリタを使う場合でも、少なくともpython3に互換な記法にしておきましょう。
python3記法のコードをpython2で実行する可能性がある場合には、互換性を保つために
from __future__ import print_function
をインポートしておくとよいです。
__future__ の公式ドキュメントには、__future__
モジュールに含まれる機能の一覧と、
pythonのどのバージョン以降に標準仕様になったかが書かれています。
python2.7を使用するなら、print_function
に加えて division
と unicode_literals
あたりはインポートしておいてもいいと思います。
if __name__ == '__main__':¶
pythonはスクリプトを上から順に実行します。 関数の定義もどこにでも書けます(関数を使えるのは定義よりも後です)。 ですが、スクリプトが長くなってくると見通しが悪くなるので、スクリプト中で実際に実行するmain部分は
if __name__ == '__main__':
以下のブロックに書き、関数などの定義はこれより上に書くようにしましょう(少々C言語ライクではありますが)。 こうすると、関数定義と実際の実行箇所が明確に区別されて、スクリプトの見通しがよくなります。 また、このファイルで定義された関数を他のスクリプトで使いたいときに、このファイルをインポートして使えます。 インポートされたときはmain部分が無視されます。
"pythonic"なコーディング¶
C/C++などのコンパイル言語に慣れた人からすると、pythonは独特です。 Effective Python [2] をお勧めします。
for文は極力使わない¶
pythonはfor文の処理が極めて遅いです。numpy配列に関する基本的な操作はほとんど関数として用意されています。それを使った方が速いし、間違いも減ります。
例えば、ある配列xから新しい配列yを によって作りたいとします。C/C++であれば
for(int i=0; i<n-1; i++) y[i] = 1.0 / x[i+1] - 1.0 / x[i];
と書くのが普通ですが、これをそのままpythonに直訳して
y = np.empty(n-1, dtype=x.dtype)
for i in range(n-1):
y[i] = 1.0 / x[i+1] - 1.0 / x[i]
と書くのはpythonicではありません(間違いではないです)。 要素ごとに逆数を計算するnp.reciprocalという関数と隣の要素との差を取るnp.diffという関数が用意されているので、それらを使って
temp = np.reciprocal(x)
y = np.diff(temp)
と書きます。あるいは一行で
y = np.diff(np.reciprocal(x))
と書いても同じことです。
書く前にまずはググる¶
基本的な操作であれば、たいてい、関数やライブラリ(pythonではモジュールと呼ぶ)が用意されています。自分で書くよりもモジュールを使用したほうが楽ですし、コードがシンプルになって間違いが減ります。 ただし、使用方法を間違えるとかえって逆効果になるので、
しかっりと動作テストをする
公式ドキュメントを確認する
ことが重要です。
標準ライブラリを積極的に使う¶
標準ライブラリ だけでもかなりのことができます(それに安心です)。積極的に使いましょう。 標準ライブラリ の中から便利なものを一例として挙げておきます:
パラメーターを別ファイルに書いて読み込みたい → configparser
コマンドライン引数を使いたい → argparse
forループをシンプルに書きたい → itertools
様々なコンテナ型を使いたい → collections
ライブラリの使い方¶
公式ドキュメントを参照する¶
web検索で引っかかる情報には古いものも多くあります。 web検索で自分の目的に合ったモジュール名や関数名が分かったら、そのあとは公式ドキュメントを参照することを勧めます。 公式ドキュメントは日本語訳がないものも多くありますが、億劫にならずに正しい情報を得る習慣をつけましょう。
必須引数とオプショナル引数¶
SciPyの scipy.integrate.quad 関数を例にとります。 公式ドキュメントによると引数は次のようになっています:
scipy.integrate.quad(func, a, b, args=(), full_output=0, epsabs=1.49e-08,
epsrel=1.49e-08, limit=50, points=None, weight=None,
wvar=None, wopts=None, maxp1=50, limlst=50)
=
の後ろに書かれているのはデフォルト値です。
デフォルト値のある引数は省略できます(オプショナル引数)。
最初の3つはデフォルト値が設定されていないので、必ず与える必要があります(必須引数)。
以下に関数の呼び出し方の例を示します:
1from scipy import integrate
2y, err = integrate.quad(f, 0, 1.5)
3y, err = integrate.quad(f, 0, 1.5, epsabs=1e-10, limit=100)
4y, err = integrate.quad(a=0, b=1.5, func=f)
5y, err = integrate.quad(a=0, b=1.5, epsabs=1e-10, func=f)
6y, _ = integrate.quad(f, 0, 1.5)
1行目:関数を使う前にインポートします。通常はソースファイルの冒頭に書きます。
2行目:最小限の使い方です。
3行目:必要なオプションを指定します。
4行目:このように func=f
のような書き方をする場合は、順番は任意です。
また、この場合は、オプショナル引数を必須引数よりも前に持ってくることもできます(5行目)。
6行目:戻り値が必要ない場合には _
で受けると、その戻り値は破棄されます。
注釈
インポートの仕方は他にもあります。
from scipy.integrate import quad
y, err = quad(f, 0, 1.5)
これも可能です。他にも
from scipy.integrate import *
y, err = quad(f, 0, 1.5)
と書くこともできますが、これはお勧めしません。quad
関数がどのモジュールに含まれているのか、ソースからは判断できないため、可読性が落ちます。これについては、例えば文献 [2] で述べられてます。
引数が増えてきた場合、関数の後ろに全ての引数を書くと読みにくくなります。 そこで、次のように、いったん辞書型に値を入れてからまとめて関数に渡すこともできます。
1params = dict(
2 func=f,
3 a=0,
4 b=1.5,
5 epsabs=1e-10,
6 epsrel=1e-10,
7 limit=100,
8 maxpl=100,
9)
10y, err = integrate.quad(**params)
**params
は辞書型を展開することを意味します。
全ての引数を辞書に含めず、例えば、func=f
を辞書に含めないで、integrate.quad(func=f, **params)
とすることもできます。
このような辞書を使った関数の呼び出し方は、関数を繰り返し呼び出す場合やオプショナル引数を使いまわす場合にも便利です。
開発環境¶
pythonに対応したエディターや統合開発環境(IDEと呼ばれる)を使えば、文法間違いを指摘してくれたり、関数の引数を表示してくれたりするので便利です。
Linux/Windows/Macの全てのプラットフォームで使えるエディターとして atom があります。
統合開発環境なら Visual Studio (VS) Code をお勧めします。 マイクロソフトが無償で提供している開発環境で、動作が軽く、とても使いやすいです。全てのプラットフォームで使用できます。 pycharm というソフトウェアもあります。有償ソフトですが、学生なら無償で使えます。
ちなみに、筆者は atom → pycharm → VS Code と乗り換えてます。
PEP8コーディング規約¶
pythonではインデント(字下げ)が重要な意味を持ちます。 ただ、インデントとしてタブ記号を使うのかスペース2つにするか4つにするかといった自由度があり、 複数の人が関わるプロジェクトで、それらが混在するとエラーにつながります。
そこで、プロジェクトでは最初にルールを決めて、人によって書き方にバラツキの無いようにします。 これを標準化したものが PEP8 と呼ばれるコーディング規約です。 とりあえずこれに従っておけば間違いありません。 (コードを人に見せないのであればあまり気にする必要はありません。)
上で紹介したatomエディターやpycharm統合開発環境では、PEP8 に沿った書き方になっているか自動で判別して教えてくれます。