Python メモ

2019年5月15日

モジュールパス

モジュールパスの設定は、環境変数 PYTHONPATH で行う。

export PYTHONPATH=~/mymodule:$PYTHONPATH

モジュールのパスは sys.path で取得できる。

モジュールのキャッシュを作成させない

モジュールをインポートしたときに作成されるキャッシュを作成させないようにするには、Python をオプション "-B" を指定して起動するか、環境変数 PYTHONDONTWRITEBYTECODE に 1 (値はなんでもよい) を設定すればよい。

できてしまったキャッシュを削除するには、Linux なら以下のようにする。

$ find -name __pycache__ | xargs rm -r

ソースコードの文字コード

文字コードに UTF-8 以外を用いるときは、ファイルの先頭に以下のように書く。

# -*- coding: shift-jis -*-

main

if __name__ == "__main__":
    main()

コマンドライン引数

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

スクリプトの場所の取得

from pathlib import Path
path = Path(__file__).resolve().parent

__file__ にはスクリプト実行時のカレントディレクトリからの相対パスが入り、resolve() は関数実行時のカレントディレクトリのパスをくっつけるので、カレントディレクトリが変更されていないことが前提になる。

末尾の空白文字を削除

# line は文字列
line = line.rstrip() # 末尾の空白文字を削除
line = line.lstrip() # 先頭の空白文字を削除
line = line.strip()  # 先頭と末尾の空白文字を削除

ファイルから 1 行読み込んだときに改行文字を削除する場合は rstrip() を使えば良い。

文字を指定することもできる。たとえば、"xxx" から両側の引用符を取り除くには次のようにする。

line = line.strip("\"")

辞書のキーと値のリストの取得

# d は辞書
key = list(d.keys())
value = list(d.values())

パスの結合

import os
os.path.join(path1, path2)

あるいは

from pathlib import Path
Path(path1).joinpath(path2)

ディレクトリ名とベース名の取得

import os
dirname, basename = os.path.split(path)
dirname = os.path.dirname(path)
basename = os.path.basename(path)

あるいは

from pathlib import Path
dirname = Path(path).parent
basename = Path(path).name

拡張子の取得

import os
basename, ext = os.path.splitext(path)

あるいは

from pathlib import Path
basename = Path(path).stem
ext = Path(path).suffix

正規表現

import re
re.search(pattern, str) # 検索
re.sub(pattern, replace, str) # 置換

ファイルの読み込み

f = open(filename, "r")

for line in f:
    line = line.rstrip()
    print(line)

f.close()

あるいは

with open(filename, "r") as f:
    for line in f:
        line = line.rstrip()
        print(line)

ファイルの最後の行だけ取り出し

with open(file, "r") as f:
    lines = f.readlines()
    line = lines[-1].rstrip()
    print(line)

CSV ファイルの読み込み

import csv

with open(filename, "r") as f:
    reader = csv.reader(f)
    header = next(reader)
    for line in reader:
        print(line)

テキストファイルのコピー

from pathlib import Path

basename = Path(filename).stem
ext = Path(filename).suffix
filename_new = basename + "-new" + ext

with open(filename, "r") as f1:
    with open(filename_new, "w") as f2:
        for line in f1:
            f2.write(line)

テキストの検索と置き換え

from pathlib import Path
import re

filename = "test.txt"

basename = Path(filename).stem
ext = Path(filename).suffix
filename_new = basename + "-new" + ext

with open(filename, "r") as f1:
    with open(filename_new, "w") as f2:
        for line in f1:
            if re.search("adelie penguin", line) is not None:
                line = re.sub("adelie penguin", "emperor penguin", line)
            f2.write(line)

"adelie penguin" を "emperor penguin" に置き換える。

カレントディレクトリのファイルのリストを得る

カレントディレクトリのファイルのリストを得るにはつぎのようにする。

import glob
files = glob.glob("*")

たとえば、CSV ファイルのリストが欲しい場合は、"*.csv" とする。"*" ではファイルが対象になるが、"*/" とするとディレクトリが対象になる。recursive オプションを True とすると、サブディレクトリも対象になる。"**/" とするとサブディレクトリも含めたディレクトリのリストが得られる。recursive=True かつ "**" とすると、サブディレクトリ内も含めた全ファイルのリストが得られる。

あるいは

from pathlib import path
files = list(Path().glob("*"))

"**" を指定すると、サブディレクトリも含めたディレクトリのリストが得られる。"**/*" とすると、サブディレクトリ内も含めた全ファイルのリストが得られる。

カレントディレクトリ以下のファイルの巡回

import os

for root, dirs, files in os.walk("."):
   print(root)

   for file in files:
        print(os.path.join(root, file))

あるいは

import glob

for path in glob.glob("**", recursive=True):
    print(path)

あるいは

from pathlib import Path

for path in list(Path().glob("**/*")):
    print(path)

カレントディレクトリ以下のファイルのテキストの置き換え

import os
import re

def main():
    workdir = os.getcwd()

    for root, dirs, files in os.walk("."):
    	print(root)

    	for file in files:
    		basename, ext = os.path.splitext(file)

    		if ext == ".txt":
    			filename1 = os.path.join(root, file)
    			filename2 = os.path.join(root, basename + ".new" + ext)

    			print(filename1)

    			f1 = open(filename1, "r")
    			f2 = open(filename2, "w")

    			for line in f1:
    				if re.search("adelie penguin", line) != None:
    					line = re.sub("adelie penguin", \
    						      "emperor penguin", line)
    				f2.write(line)

    			f1.close()
    			f2.close()

    			os.remove(filename1)
    			os.rename(filename2, filename1)


if __name__ == "__main__":
    main()

カレントディレクトリ以下の ".txt" ファイルの中にある文字列 "adelie penguin" を "emperor penguin" に置き換える。

ファイルの操作

import os
os.path.exists(path) # ファイルの存在を調べる
os.remove(path) # ファイルの削除
os.rename(src, dist) # ファイル名の変更

コマンドの存在の有無

import shutil as su
su.which("ls")

時刻表示を足す

"00:00:00" の形の時刻表示どうしを足し合わせる。

def add_time(t1, t2):
    t1 = t1.split(":")
    t2 = t2.split(":")

    r = []
    for i in range(len(t1)):
    	r.append(int(t1[i]) + int(t2[i]))

    if r[2] > 60:
    	r[2] -= 60
    	r[1] += 1

    if r[1] > 60:
    	r[1] -= 60
    	r[0] += 1

    r = "%d:%d:%d" % tuple(r)

    return r

CSV から HTML のテーブルを作る

csv2table.py

import sys
import csv

def main():
    argv = sys.argv
    argc = len(argv)

    if argc < 2:
        print("usage: csv2table.py <CSV file>")
        exit()

    filename = argv[1]

    with open(filename, "r") as f:
        reader = csv.reader(f)
        header = next(reader)

        print("<html>")
        print("<body>")

        print("<table border="1">")
        print("<thead>")

        print("<tr>", end="")

        for r in header:
            r = r.strip()
            print("<th>%s</th>" % r, end="")

        print("</tr>")

        print("</thead>")
        print("<tbody>")

        for line in reader:
            print("<tr>", end="")

            for r in line:
                r = r.strip()
                print("<td>%s</td>" % r, end="")

            print("</tr>")

        print("</tbody>")
        print("</table>")

        print("</body>")
        print("</html>")


if __name__ == "__main__":
    main()

画像処理

画像の読み込みと表示

from PIL import Image
image = Image.open("image.jpg")
image.show()

image.show() はデフォルトのビューアーで表示される。Jupyter Notebook 内で表示するには、変数名だけ打てばよい。

image

あるいは、matplotlib を利用することもできる。

%matplotlib inline
from matplotlib import pyplot as plt
import numpy as np

fig, ax = plt.subplots()
ax.axis("off")
plt.imshow(np.array(image))

画像のサイズ

w, h = image.size

座標の色を取得

image.getpixel((0, 0))

2値化

image2 = image.convert('1')

グレースケール変換

image2 = image.convert('L')

画像のクリップ

image2 = image.crop((x1, y1, x2, y2))

画像の作成

image = Image.new("RGB", (w, h), (255, 255, 255))

画像の貼り付け

image.paste(image1, (x, y))

画像の保存

image.save("image.png")

画像の結合

from PIL import Image

w = 640
h = 320

image1 = Image.open("image1.jpg")
image2 = Image.open("image2.jpg")

image = Image.new("RGB", (w*2, h), (255, 255, 255))
image.paste(image1, (0, 0))
image.paste(image2, (w, 0))

image.save("image.jpg")1

画像への文字の書き込み

from PIL import Image, ImageDraw, ImageFont

w = 200
h = 50

image = Image.new("RGB", (w, h), (255, 255, 255))

draw = ImageDraw.Draw(image)
draw.font = ImageFont.truetype("Helvetica", 40)

text = "Penguin"
tw, th = draw.textsize(text)
draw.text(((w-tw)/2, (h-th)/2), text, (0, 0, 0))
image.show()

バックトレースの表示

import traceback
traceback.print_exc()

形態素解析

janome を使う。

$ pip install janome

名詞を取り出す。

from janome.tokenizer import Tokenizer
from janome.analyzer import Analyzer
from janome.charfilter import *
from janome.tokenfilter import *

s = """趙の邯鄲の都に住む紀昌という男が、天下第一の弓の名人になろうと志を立てた。己の師と頼むべき人物を物色するに、当今弓矢をとっては、名手・飛衛に及ぶ者があろうとは思われぬ。百歩を隔てて柳葉を射るに百発百中するという達人だそうである。紀昌は遥々飛衛をたずねてその門に入った。"""

char_filters = [UnicodeNormalizeCharFilter()]
token_filters = [
    CompoundNounFilter(),
    POSKeepFilter(["名詞"]),
    ExtractAttributeFilter("surface"),
]

a = Analyzer(char_filters=char_filters, token_filters=token_filters)

noun = set()
for token in a.analyze(s):
    noun.add(token)

noun

実行結果

{'都', '名手', '志', '人物', '邯鄲', '柳葉', '百歩', '物色', '男', '天下', '名人', 'そう', '紀昌', '者', '百発百中', '師', '己', '一', '門', '趙', '達人', '飛衛', '当今弓矢', '弓'}

配列の文字列としての連結

>>> ",".join(["a", "b"])
'a,b'