pythonメモ

よく使うけど忘れること

改行

 Pythonの一番なれない点としてインデントがブロックの意味を持つ点がある.勝手に改行したりすると意味が変わるので注意する.文の途中で改行したい時は"\"を文末に置く.ただし,(), {},[]中の","の後ろは"\"を省略可能.

doc

  • モジュール(pythonでは1つのファイル),クラス,メソッド毎にドキュメントを書くことが出来て,それが"doc"で参照可能.
  • 例えば,下の例はモジュール,クラス,メソッド毎にドキュメントを書いている例.記載する場所でそれぞれ異なる.
'''
This is doc for the module.
'''

class Hoge:
    '''
    This is doc for the class.
    '''
    def __init__(self):
        pass

    def func(self):
        '''
        This is doc for the function.
        '''
        pass

if __name__ == '__main__':
    hoge = Hoge()
    print(__doc__)
    print(hoge.__doc__)
    print(hoge.func.__doc__)

モジュールとパッケージ

  • pythonではファイルがモジュール、ディレクトリがパッケージ。
  • モジュールなりパッケージをimportすると、そのモジュール名、パッケージ名で名前空間を新たに作って、その中で変数や関数を定義してくれる(import MyModuleすると、MyModule.funcみたいな名前に成る)。グローバルな名前空間に出現しないことを覚えておく。
  • パッケージをimportすると、まずそのパッケージ内(ディレクトリ内)のinit.pyが実行される。

文字列

  • ''と""の違いは無い.
  • [1:3]などで1文字目から3文字目までを取り出せる。同様に、[1:]で1文字目以降、[:5]で5文字目までを取り出せる。
  • 文字列に変数を埋め込む時には,formatを使う.単純に{}で囲む部分に引数が展開されて入っていく.
  • Rubyで言うところの#{hoge}に一番近いのは,'%(var)型'.locals()かな.型にはint:d, string:s, float:fなど.
'hello %s %s' % ('Nobu!', 'I am Take')   # 汚くなりがち
'hello {} {}'format('Nobu', 'I am Take') # こっちのほうが分かりやすい.型が異なっても出力できる(良くはないけど)
'hello %{person}s, I am %{name}s'.locals()
  • ある文字が、ある文字の中のどれかであるか?というチェックをするときに、文字列はそれ自体がシーケンスなのでいちいちリストに変換する必要は無い。
ch = 'a'
s = 'abcdefg'
ch in s #=> True
ch = 'z'
ch in s #=> False
  • 一文字単位でsplitしたい場合はlistで変換するだけ。
s = '12345'
list(s) #=> ['1', '2', '3', '4', '5']

タプルとリストの違い

  • タプルとリストの違いは要素を変更可能かどうか.タプルは変更を許さない.それ故にちょっと速い.
  • pythonのリストは名前の通りリスト.配列ではない.間違ってた・・・.オブジェクト型の可変長配列みたいだ.
  • リストは関数に参照渡しで渡されるので,リストそのものが破壊される.
def incList(lst):
  for i, e in enumerate(lst):
    lst[i] = e+1

a = [0,1,2,3,4,5]
incList(a) #=>[1,2,3,4,5,6]

モジュールのバージョン確認

import numpy
print numpy.__version__

もしくは,pipで入れたものなら,

$ pip list

python2/python3のrangeの違い.

  • python3のrangeはpython2のxrangeに相当.リストを返さずにイテレータを返す.これは,必要になった時に必要な値を返すようにすることで,メモリの制限を受けないrangeを実現するため.zipとか多くがpython3からイテレータを返すようになった.
  • 普通にリストが欲しい場合は,list(range(10))とする.

コマンドライン引数

import sys
argv = sys.argv
argc = len(argv)

スワップ,2つの変数の中身の交換

  • pythonでは多重代入をするだけでスワップしてくれる.ソートとかを書くときに便利だ.
a = 'a'
b = 'b'
a, b = b, a #=> a='b', b='a'

小数点刻みのrange

標準のrangeは先頭,終端,刻みはすべて整数のみ.無理やり0.1を掛けたりするのは良くない.numpyにあるarangeを使う.

d = [0.1*x for x in range(0,10,1)] # こんなことはするな
import numpy as np
d = np.arange(0,10,0.1)

ZipとUnzip(=zip(*x))

  • zipはリストのタプルをタプルのリストにする.x=[x1,x2,x3],y=[y1,y2,y3],z=[z1,z2,z3]のときに,point = [(x1,y1,z1), (x2,y2,z2),(x3,y3,z3)]が作れる.複数のリストに同時にforを回す時にも使う.
# [0..100]の3次元立方体の中の点をランダムに生成.
xlist= [np.random.random() for i in xrange(100)]
ylist= [np.random.random() for i in xrange(100)]
zlist= [np.random.random() for i in xrange(100)]
points=zip(xlist,ylist,zlist)
for x, y, z in points:
   xxx
  • zipと逆の操作(zipしたものを戻す)unzipに相当するものが、関数の引数展開を使うとできる。
  • 何をやっているかと言うと、xが配列[1,2,3]の時に関数fにf(*x)として渡すとf(1,2,3)として渡されることを利用する。よって、xが[(1,'a'),(2,'b'),(3,'c')]だとすると、zip*1となる。これは、zip[a,b,c]で、a,b,cの1要素目、2要素目、3要素...をそれぞれ順にまとめた新しいイテレータを作ってくれる。それはまさに、[(1,2,3),('a','b','c')]、という寸法。
ziped_xy = [(1,'a'),(2,'b'),(3,'c')]
xs, ys = zip(*ziped_xy) # xs=[1,2,3], ys=['a','b','c']

exitとquit

assert

  • assertはdebugがTrueの時のみ動作する.コマンドラインから起動制御する場合は-OオプションでFalseになる.意外と便利だ.

リスト関連

代入とコピー

  • "="演算子は参照をコピーする.よって,代入先で要素を更新すると,代入元も更新される.値のコピーをしたい場合はcopy, list(), [:]のいずれかを使う.スライスで値をコピーできるのは色々便利.
a = [1,2,3,4,5]
b = a.copy()
c = list(a)
d = a[:]

集合の差分

  • Rubyのように配列の差によって,集合演算のようなことはできない.setという組込みデータ構造があるので,一旦setに入れて,必要ならlistで配列に戻す,というやり方.

:スライス

  • a[1:], a[:3]nとかで配列の一部を取り出せる.注意点として,a[i:k]は,「a[i]から,"a[k-1]"」まで.対象じゃないので注意する.

::スライス

  • 配列をN個飛ばしでスライスするときは2つ:を付ける.これを使えば,配列の偶数番目,奇数番目を取り出すループは次のように書ける.また,珍しいところでは[::-1]でreverseしたコピーリストを作れる.
for even, odd in zip(arr[::2], arr[1::2]):
 brabrabra

クラス

親のコンストラクタを呼ぶ

  • 子クラスで親のコンストラクタを明示的に呼ぶ方法.(ここで親のインスタンス変数が生成される?)
class Child(Parent):
    def __init__(self): 
        SuperClass.__init__( self )

スクリプトとして,テストとして実行する場合

  • Rubyで言う,if FILE = $0
if __name__ == '__main__' :

ループ

  • each_with_indexはenumerate
  • timesはrangeでfor
a = [1,2,3,4,5]
for i, e in enumerate(a):
  print 'a[%s] = ' % i, e

for i in range(10):
  print i # i:0,1,2,...9

ファイルに関して

  • Rubyみたいにwhile buf=f.gets的な1行ずつの処理はできない。readlinesで全部読み込んで1行ずつ処理する。ただし、これだとある行にマッチしたら次の行をxxxする、とかが素直に書けない。readlineで1行ずつやろうかと思うと、do-whileが無いのでこのreadlineの1行ずつのが終了判定がwhile無限ループのbreak脱出になって何だか汚い気持ち。
# 単純に1行ずつ処理したい場合
for line in open('hoge.txt') :
   print line

# 明示的にファイルを開く場合
fin = open('hoge.txt')
lines = fin.readlines() # 一気に読み込む
for line in lines:
   print line
fin.close()

# 1行ずつ読込ながら,時にはスキップしたりしたい.do-whileはないのでこうやるしかない
fin = open('hoge.txt')
line = fin.readline() # 1行読込
while line:
   print line
   line = fin.readlines()
fin.close()

# Rubyで書いてた方法と一番にているかも?
fin = open('hoge.txt')
while True:
  line = fin.readline()
  if not line: break
  print line

# ファイルポインタを持ち歩かないなら,withで自動的にクローズする方が良いかもしれない.
with open('hoge.txt') as fin:
   line = fin.readline()

# 書き込む時
fout = open('hoge.txt', 'w')
fout.write('hello world')    # 基本的にwriteを使う
print >> fout, 'hello world' # print先を一時的にリダイレクト
fout.close()

chomp

  • ファイルをロードした時とかに末尾の’\n’を削除したい場合。Rubyで言うところのchomp。
line = fin.readline()
line.rstrip()

ディレクトリが無い場合に作る

if not os.path.exists('dir_name'):
    os.mkdir('dir_name')

print出力

  • カンマでの連続出力で空白が嫌なら先に文字列として連結して出力する。またはprint "%s%s" %(str1, str2)みたいな書式付きで出力する。
  • でもこれだとせっかくのprintのポリモーフィズムが生かされないのが嫌だ."hell {}".format('Bob')とかが良いかもしれない.
  • 改行が不要な場合は最後にもカンマを入れる
  • rubyで言うppみたいなものとして、pprint (import pprint)がある。

正規表現

  • Rubyで言う正規表現リテラルオペランドは無い。よって、愚直に正規表現を作って、それを通して、みたいなことをやることになる。
  • compileで一回作っておくと,何度も使う場合には高速化が期待できる.
  • rを付けるとバックスラッシュをそのまま書ける
  • patternにカッコを入れると,そこをgroup(i)で後方参照できる.Rubyで言う$i.
  • ここで、正規表現の種類がmatch, search, findall, finditerがある。これもそれぞれが微妙に異なっていて綺麗じゃない。
    • match :先頭からのみマッチする。返り値はマッチオブジェクト。マッチしていないとNone.
    • search :先頭だけでなく、途中からもマッチ。返り値はmatchと同じ。
    • findall :searchと同じく途中からもマッチするけど、複数取り出す。返り値は文字列配列。
    • finditer:findallと似ているけど返り値がマッチオブジェクトのイテレータイテレータの空判定はそのままできないので、len(list(m_iter))でやる。
import re
str = '123456789123456789'
pattern = re.compile('(123)(\d+)')
# matchまたはsearchの場合
m = pattern.match(str)
if m:
  print 'match'
  print m.gropu(2) #  456789123456789
else:
  print 'unmatch'

# findallの場合
ret = pattern.match(str)
if len(ret) !=0 :
  print 'match'
  print m.gropu(2) 
else:
  print 'unmatch'

# finditerの場合
miter = pattern.match(str)
if len(lit(miter) !=0 :
  print 'match'
  for m in miter:
    print m.gropu(0) 

高階関数

  • λ式はlambda x, y: x+y みたいな書式
  • +などの基本オペレータはoperetorパッケージをインストールしてaddなどで渡す.
a = [1,2,3,4,5]
map(lambda x: 2*x, a) #=> [2,4,6,8,10]
reduce(lambda x,y: x+y, a) #=> 15

内包表記

  • 基本は,[expr for item in iterator].[]ならリスト内包表記,{}ならset/辞書.ただし,()でタプル内包表記は出来ないので注意.
l1 = [x*x for x in range(5)] #=> [0,1,4,9,16]
l2 = [x for x in range(10) if x %2 == 0] # 偶数のみ
word = "hogehoge"
letter_counts = {letter: word.count(letter) for letter in word}

*1:1,'a'),(2,'b'),(3,'c'