pyenvで環境構築

pyenvというツールを利用すると,簡単に科学技術計算のためのpython環境を整えることができるから,使い始める最初に行うべきと思う(170411).

以下のようにしてGitHubから取ってきてホームディレクトリに置く.

$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv

~/.bashrcなどに,

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

のような設定を書いてパスが通るようにする.

以下のようにしてインストールしたいバージョンを探す.

$ pyenv install -l
Available versions:
  2.1.3
  2.2.3
  ...

numpyscipyなど,科学技術計算に必要なものをまとめてインストールしてくれるanaconda-4.0.0を指定してインストール.

$ pyenv install anaconda-4.0.0
$ pyenv global anaconda-4.0.0

二行目のglobalでマシン全体のデフォルト設定を指定している.

$ pyenv versions

とすることで,現在そのマシンで利用可能なバージョンを確認できる.

ソースコードの文字コードを指定

下記のように,先頭の次の行にコメント行としてutf-8指定を記述しておく.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

数値を文字列に変換

例えば,

 print, "Today is %3d-th Jan., %4d" % (date,year)

のようにすれば,変数nの値が代入される.この時の(date,year)をタプルと呼ぶらしい. 文字列に数値を代入する際には,この%の後にタプルとして列挙すれば良いらしい. print文だけでなく,文字列の表現でならば何処でも使用可能らしい.例えば,

 for number in range(0,10):
      filename= "foge%03d" % (number)

のようにすれば,連番ファイル名のファイルを作成可能.

配列

arrという配列の宣言として,

 arr = []

とすれば,何も入っていない長さ0の配列ができる. 配列に要素を加える場合,

 arr= arr + [something]

とすることで加えることができる. なので,1から10までの数値の配列が欲しいときは,

  arr= []
  for i in range(1,11):
      arr= arr +[i]

とすることで,arr=[1,2,3,4,5,6,7,8,9,10]となるハズ.


for文とrange()

 for i in range(1,10):
     print " i=", i

とすると,

 i= 1
 i= 2
 i= 3
 i= 4
 i= 5
 i= 6
 i= 7
 i= 8
 i= 9

となる.10は含まれない

glob()

連番ファイルなどを編集するのに便利なクラス.

 import glob
 for file in glob.glob("%03d/hoge0??" % (ndir)):
     do something

などとすれば,001/hoge001,…, 002/hoge001,…, のようなファイルに対して処理を行える.


importしているモジュールのファイルの場所を特定する

$ python -c 'import some_module; print some_module.__file__'

そのモジュールの中身を調べたい時などにまずはファイルの場所を調べなければならない.

optparseを使って引数をとる

optparseよりは次のdocoptの方が圧倒的にエレガントと思うのでそちらをおすすめする

http://docs.python.jp/2.6/library/optparse.html を参考にした.

import optparse
 
usage= '%prog [options] '
parser= optparse.OptionParser(usage=usage)
parser.add_option("-n",dest="num",type="int",default=1,
                  help="number of something.")
parser.add_option("--no-hoge",dest="do_hoge",action="store_false"
                  default=True,
                  help="not to hoge.")
(options,args)= parser.parse_args()
 
num= options.num
do_hoge= options.do_hoge

上記のようにして引数をとることができるようになり,自動的に-hオプションが追加され, ヘルプを表示できるようになる.

$ hoge.py -h
Usage: hoge.py [options] 
 
Options:
  -h, --help            show this help message and exit
  -n NUM                number of something.
  ...

docoptを使って引数をとる

usageやoptionsをdocstringに記述しておけば,それを解析してコマンドライン引数をとってくるということをやってくれる. 説明書を書いたらそのまま動くものができるみたいな素晴らしい方法.

下記参考:

例えば,

"""
Program that uses the docopt module.
 
Usage: test_docopt.py [options] TXT
 
Options:
    -h, --help   show this help message and exit.
    --what       defines an option like this.
"""
from docopt import docopt
args= docopt(__doc__)
what= args['--what']
txt= args['TXT']
 
print args

上記のようなプログラムを作ると,以下のように,ヘルプメッセージはそのdocstringそのものだし,そのdocstringを解析して,オプションや引数を辞書型変数に代入してくれる. 簡単で便利.

$ python test.py -h
Program that uses the docopt module.
 
Usage: test.py [options] TXT
 
Options:
    -h, --help   show this help message and exit.
    --what       defines an option like this.
$ python test.py --what hey
{'--help': False,
 '--what': True,
 'TXT': 'hey'}
$ python test.py hey
{'--help': False,
 '--what': False,
 'TXT': 'hey'}

YAMLの書き込み・読み込み

YAMLはデータを人間にとって見易いテキストとして保存するための言語. Python用にはいくつかモジュールが存在するらしいが,PyYAMLというやつが一般的らしい.

import yaml
 
 
### file.yamlの読み込み
with open('file.yaml','r') as f:
    data= yaml.load(f)
 
with open('out.yaml','w') as f:
    yaml.dump(data,f)

のようにして,loaddumpを行うことができる.

numpy arrayデータのYAMLの書き込み・読み込み

import yaml
 
with open('file.yaml','r') as f:
    data= yaml.load(f)
data= np.array(data)
 
with open('out.yaml','w') as f:
    yaml.dump(data.tolist(),f)

のように,list型とnp.array型との間の変換を行って,YAMLとして扱えばよし.

クラスインスタンスを返すclassmethod

class SomeClass():
    ...
 
    def __init__(self):
        pass
 
    @classmethod
    def make_some_class(cls):
        newClass = cls()
        return newClass

上記のようなclassmethodを用意すると,

newclass = SomeClass.make_some_class()

とすることで,SomeClassのインスタンスを作成できる. __init__()を用いたクラス作成とは別の方法でクラスを作る際に使える.

subprocessを使った並列処理

並列処理にはホントはmultiprocessモジュールを使うべきなのだろうが,ここではsubprocessを用いた場合のやり方を.

from subprocess import Popen
...
cmd = 'somecommand arg1 arg2'
p = Popen(cmd.split())  # launch somecommand
p.communicate()  # wait until somecommand is done

のようにして用いる. shell=Trueというオプションを指定すると,cmd.split()のような渡し方ではなく,文字列をダイレクトに渡してShellで実行するようになる. そのため,セキュリティ上は少々問題があるが,セキュリティが問題とならない状況ではこの方が楽と思われる.

p = Popen(cmd,shell=True)

並列実行する場合は下記のようなコードとなる.

from subprocess import Popen
npara = 10
procs = []
for n in range(npara):
    cmd = 'somecommand arg1 arg2 > out.{0:d}'.format(10)
    p = Popen(cmd,shell=True)
    procs.append(p)
for p in procs:
    p.communicate()

簡単な時間計測

以下のように,timeモジュールを利用して,開始時間と終了時間の差を秒で計測できる.

from time import time
 
start = time()
...
end = time()
print 'time = {0:10.2f} sec'.format(end-start)

loggingの利用

参考

参考であげたリンクで,とりあえず以下のようにして,loggerとhandlerを生成すべしと書かれている.

from logging import getLogger, StreamHandler, DEBUG
logger = getLogger(__name__)
handler = StreamHandler()
handler.setLevel(DEBUG)
logger.setLevel(DEBUG)
logger.addHandler(handler)
 
logger.debug('hello')

主要な関数では,loggerを引数で受け取って設定できるようにすべしとも書かれている.

def func(arg_a, arg_b, logger=None):
    logger = logger or _your_default_logger
    ...

こうすることで,この関数をライブラリとして利用するときの利便性があがるらしい.


Jupyter Notebook

$ jupyter notebook

とするとウェブブラウザでpythonプログラミングができる.

  • ipythonからjupyterに名称変更されて以降,pythonだけでなくいろいろな言語に対応している.
  • ウェブブラウザで実行するからといってネット接続が必要なわけではない.
  • シミュレーションのための実験ノートのような位置づけで,カードという単位でプログラムを実行していくことができ, markdown形式の文章も挿入できるから,どのような数式をプログラミングして結果としてどのような結果が得られたかのグラフ描画までを一つのノートにできる.

Jupyter Lab

現在はまだ開発中とのことなのだが,ほとんどのことは問題なく使える. 以下のようにインストールして起動すればよい.

$ pip install jupyterlab
$ jupyter lab

自作モジュールimport

my_project
├── notebook
│   └── my_note.ipynb
└── src
    └── my_module.py

上記のような構成のnotebook my_note.ipynb の中で,src/my_module.py を import したい場合,notebookの中で次のようにパスを指定して import する.

from pathlib import Path
current_dir = os.path.join(Path().resolve())
sys.path.append(str(current_dir)+'/../src/')
import my_module