Python メモ2022年3月16日 | |
モジュールパスモジュールパスの設定は、環境変数 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) コマンドライン引数の処理ArgumentParser でコマンドライン引数の処理を行える。
from argparse import ArgumentParser
def get_args():
parser = ArgumentParser()
parser.add_argument("path", type=str, help="file path")
parser.add_argument("--enable_opt", action="store_true",
help="enable option")
return parser.parse_args()
def main(args):
path = args.path
enable_opt = args.enable_opt
...
if __name__ == "__main__":
args = get_args()
main(args)
スクリプトの場所の取得import sys from pathlib import Path path = Path(sys.argv[0]).resolve().parent sys.argv[0] にはスクリプト実行時のカレントディレクトリからの相対パスが入り、resolve() は関数実行時のカレントディレクトリのパスをくっつけるので、カレントディレクトリが変更されていないことが前提になる。sys.argv[0] の代りに __file__ を用いる方法もあるが、Cython を用いた時にうまくいかない。 末尾の空白文字を削除# line は文字列 line = line.rstrip() # 末尾の空白文字を削除 line = line.lstrip() # 先頭の空白文字を削除 line = line.strip() # 先頭と末尾の空白文字を削除 ファイルから 1 行読み込んだときに改行文字を削除する場合は rstrip() を使えば良い。 文字を指定することもできる。たとえば、"xxx" から両側の引用符を取り除くには次のようにする。
line = line.strip("\"")
改行文字だけを取り除きたい場合は、次のようにすればよい。
line = line.strip("\r\n")
辞書のキーと値のリストの取得# 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 r = re.search(pattern, str) たとえば、次のように使う。
>>> s = '<a href="xxx">xxx</a>'
>>> r = re.search('href=".+"', s)
>>> r.group(0)
'href="xxx"'
href の値を取り出すには次のようにする。
>>> r = re.search('href="(.+)"', s)
>>> r.group(0)
'href="xxx"'
>>> r.group(1)
'xxx'
検索では、最も長いものが取られる。
>>> r = re.search('<.+>', s)
>>> r.group(0)
'<a href="xxx">xxx</a>'
短いものを取るには、"?" をつける。
>>> r = re.search('<.+?>', s)
>>> r.group(0)
'<a href="xxx">'
何度も同じ検索を行うなら、コンパイルも使える。
>>> m = re.compile('href="(.+)"')
>>> r = m.search(s)
>>> r.group(1)
'xxx'
置換も行える。 str2 = re.sub(pattern, replace, str) 次のようになる。
>>> re.sub('href="(.+)"', 'href="yyy"', s)
'<a href="yyy">xxx</a>'
検索にマッチしたグループをそのまま使うこともできる。
>>> re.sub('href="(.+)"', r'href="\g<1>2"', s)
'<a href="xxx2">xxx</a>'
ファイルの読み込み
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)
文字コードを指定するには次のようにする。 f = open(filename, "r", encoding="utf-8") Windows のShift-JIS を扱いたい場合は、"sjis" ではなく "cp932" を指定したほうがよい。 f = open(filename, "r", encoding="cp932") ファイルの最後の行だけ取り出し
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)
区切り文字を指定する場合は、次のようにする。 reader = csv.reader(f, delimiter=";") テキストファイルのコピー
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 os
files = os.listdir(".")
あるいは
from pathlib import Path
files = Path(".").iterdir()
フィルターをかけたい場合は、次のようにする。
import glob
files = glob.glob("*")
たとえば、CSV ファイルのリストが欲しい場合は、"*.csv" とする。"*" だと Linux/Mac のドットファイルが無視されるので、ドットファイルも含みたい場合は ".*"とする。"*" ではファイルが対象になるが、"*/" とするとディレクトリが対象になる。recursive オプションを True とすると、サブディレクトリも対象になる。"**/" とするとサブディレクトリも含めたディレクトリのリストが得られる。recursive=True かつ "**" とすると、サブディレクトリ内も含めた全ファイルのリストが得られる。 あるいは
files = list(Path().glob("*"))
"**" を指定すると、サブディレクトリも含めたディレクトリのリストが得られる。"**/*" とすると、サブディレクトリ内も含めた全ファイルのリストが得られる。 ディレクトリかどうかパスがディレクトリかどうかどうか調べるには、次のようにする。 os.path.isdir(path) あるいは Path(path).is_dir() カレントディレクトリ以下のファイルの巡回
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) # ファイル名の変更 あるいは from pathlib import Path Path(path).exists() # ファイルの存在を調べる Path(path).unlink() # ファイルの削除 Path(path).rename(new_path) # ファイル名の変更 ファイルのコピー
import shutil
shutil.copyfile("file1.txt", "file2.txt")
時刻現在時刻の取得
>>> from datetime import datetime
>>> str(datetime.now())
'2019-12-02 15:24:14.583495'
>>> "{:%Y-%m-%d %H:%M:%S}".format(datetime.now())
2019-12-02 15:28:02
UTC の変換
>>> from datetime import datetime
>>> dt = datetime.strptime("2019-07-30T00:00:00.000Z", "%Y-%m-%dT%H:%M:%S.%fZ")
>>> dt.strftime("%Y/%m/%d")
'2019/07/30'
GMT の変換
>>> from datetime import datetime
>>> dt = datetime.strptime("Tue, 09 Jun 2020 08:01:04 GMT", "%a, %d %b %Y %X %Z")
>>> print(dt)
2020-06-09 08:01:04
日付の表記の変換
>>> from datetime import datetime
>>> dt = datetime.strptime("2021年9月27日", "%Y年%m月%d日")
>>> dt.strftime("%Y-%m-%d")
'2021-09-27'
翌日>>> import datetime >>> datetime.datetime(2020, 10, 30) + datetime.timedelta(days=1) datetime.datetime(2020, 10, 31, 0, 0) >>> datetime.datetime(2020, 10, 31) + datetime.timedelta(days=1) datetime.datetime(2020, 11, 1, 0, 0) 翌月
>>> from datetime import datetime
>>> from dateutil.relativedelta import relativedelta
>>> dt = datetime.strptime("202212", "%Y%m")
>>> dt += relativedelta(months=1)
>>> dt
datetime.datetime(2023, 1, 1, 0, 0)
特定の日付を超えているか調べる>>> import datetime >>> dt0 = datetime.datetime.now() >>> dt0 datetime.datetime(2019, 12, 14, 15, 22, 26, 404201) >>> dt1 = datetime.datetime(2019, 12, 16) >>> dt1 - dt0 datetime.timedelta(days=1, seconds=31053, microseconds=595799) >>> dt1 = datetime.datetime(2019, 12, 15) >>> dt1 - dt0 datetime.timedelta(seconds=31053, microseconds=595799) >>> dt1 = datetime.datetime(2019, 12, 14) >>> d = dt1 - dt0 datetime.timedelta(days=-1, seconds=31053, microseconds=595799) >>> dt1 = datetime.datetime(2019, 12, 13) >>> d = dt1 - dt0 datetime.timedelta(days=-2, seconds=31053, microseconds=595799) ある日付の 0:00 を超えているか調べたければ、時刻どうしを引いて days の符号が負かどうかを調べればよい。 ファイルの日付チェックファイルを変換するかどうかをタイムスタンプを比較して判断したりする場合。
from datetime import datetime
from pathlib import Path
files = ["fig01", "fig02", "fig03"]
for file in files:
p_pdf = Path("%s.pdf" % file)
p_png = Path("%s.png" % file)
if p_png.exists():
dt0 = datetime.fromtimestamp(p_pdf.stat().st_ctime)
dt1 = datetime.fromtimestamp(p_png.stat().st_ctime)
if(dt1 > dt0):
continue
... 変換処理 ...
時刻表示を足す"00:00:00" の形の時刻表示どうしを足し合わせる。
>>> import datetime
>>> dt1 = datetime.datetime.strptime("01:45:00", "%H:%M:%S")
>>> dt2 = datetime.datetime.strptime("0:20:00", "%H:%M:%S")
>>> dt = dt1 + datetime.timedelta(hours=dt2.hour, minutes=dt2.minute)
>>> dt.strftime("%H:%M:%S")
'02:05:00'
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")
画像への文字の書き込み
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()
画像サイズの変更w, h = image.size size = (int(w*0.25), int(h*0.25)) image.resize(size, Image.ANTIALIAS) 画像のアスペクト比を維持したままの縮小の場合は、次のようにもできる。 w, h = image.size size = (w*0.25, h*0.25) image.thumbnail(size, Image.ANTIALIAS) バックトレースの表示import traceback traceback.print_exc() 配列を文字列として連結>>> ",".join(["a", "b"]) 'a,b' 文字列処理文字列の正規化
import unicodedata
s = unicodedata.normalize("NFKC", s)
アルファベット文字列かどうかチェック
def check_alphabet(s):
alphabet = {chr(i) for i in range(ord("A"), ord("z")+1)}
ss = set(s)
if ss & alphabet == ss:
return True
else:
return False
ひらがな文字列かどうかチェック
def check_hiragana(s):
hiragana = {chr(i) for i in range(ord("ぁ"), ord("ん")+1)}
ss = set(s)
ss -= {"ー"}
if ss & hiragana == ss:
return True
else:
return False
ひらがなをカタカナに変換する
def convert_hira_to_kata(s):
r = ""
for c in s:
i = ord("ァ") + ord(c) - ord("ぁ")
if ord("ァ") <= i <= ord("ン"):
r += chr(i)
else:
r += c
return r
文字コードを変換するShift-JIS に変換する (s は文字列)。
s.encode("shift-jis").decode("shift-jis")
gnuplot を呼ぶ
import subprocess
with open(plot_file, "w") as f:
# gnuplot のコマンドを書く
...
command = ["gnuplot", "-persist"]
proc = subprocess.Popen(command, stdin=subprocess.PIPE)
command = 'load "%s"\n' % plot_file
proc.stdin.write(command.encode("utf-8"))
proc.stdin.flush()
Ctrl-C を捕捉する
try:
...
except KeyboardInterrupt:
...
環境変数環境変数を参照する >>> import os >>> os.environ["MYENV"] 環境変数があるかどうか調べる。 >>> "MYENV" in os.environ ソケットserver.py
import socket
host = socket.gethostname()
port = 4321
buffer_size = 1024
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.bind((host, port))
except OSError as e:
print_log(e)
exit()
s.listen(1)
print("waiting...")
try:
while True:
(c, address) = s.accept()
with c:
print("connect from %s:%s" % address)
while True:
msg = c.recv(buffer_size)
if not msg:
break
msg = msg.decode()
print("message: %s" % msg)
if msg == "end":
break
except KeyboardInterrupt:
print("exit")
server.py (Windows 用)
import socket
host = socket.gethostname()
port = 4321
buffer_size = 1024
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.bind((host, port))
except OSError as e:
print_log(e)
exit()
s.listen(1)
print("waiting...")
s.settimeout(1)
try:
while True:
try:
(c, address) = s.accept()
except IOError:
continue
with c:
print("connect from %s:%s" % address)
while True:
msg = c.recv(buffer_size)
if not msg:
break
msg = msg.decode()
print("message: %s" % msg)
if msg == "end":
break
except KeyboardInterrupt:
print("exit")
client.py
import socket
host = socket.gethostname()
port = 4321
buffer_size = 1024
try:
while True:
msg = input("message: ")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
s.send(msg.encode())
if msg == "end":
break
except KeyboardInterrupt:
print("exit")
ホスト名の取得host = socket.gethostname() IP アドレスの取得address = socket.gethostbyname(host) ソースコードを調べるモジュールのソースコードを見ることができる。 import mymod import inspect print(inspect.getsource(mymod)) ただし、Cython を使うと見えなくなる。 UUID を作成するimport uuid id = str(uuid.uuid4()) MAC アドレスを取得するimport uuid mac = uuid.uuid1().hex[-12:] ZIP ファイルを展開するファイル名が Shif-JIS のファイルを含む ZIP ファイルの展開 (パスワード対応)。 unzip.py
import sys
from zipfile import ZipFile
from getpass import getpass
def main(args):
if len(args) <= 1:
print("usage: unzip.py
使い方 $ python unzip.py filename サイクルリスト
class CycleList:
def __init__(self, lst, nitems=1):
self.list = lst
self.nitems = nitems
def iterator(self, n=-1):
i = 0
while True:
items = []
for j in range(i, i + self.nitems):
k = j % len(self.list)
items.append(self.list[k])
if len(items) == 1:
yield items[0]
else:
yield tuple(items)
i += 1
if i == n:
break
使い方
c = CycleList([0, 1, 2], 2)
for i in c.iterator(3):
print(i)
出力 (0, 1) (1, 2) (2, 0) ソートしたリストを得るsorted_list = sorted(unsorted_list) 大文字小文字関係なしで並び替える。 sorted_list = sorted(unsorted_list, key=str.casefold) "unsorted_list.sort()" という方法もあるが、これだとリストそのものの内容が変更されるので注意。 コマンドを呼ぶ
import sys
import subprocess as sp
import threading
def run_command(command, silent=False, func_log=None, background=False):
proc = sp.Popen(command,
shell=True, stdout=sp.PIPE, stderr=sp.PIPE)
def wait():
stdout_data, stderr_data = proc.communicate()
if not silent:
if func_log is None:
sys.stdout.write(stdout_data.decode())
else:
func_log(stdout_data.decode())
if proc.wait() != 0:
if func_log is None:
sys.stderr.write(stderr_data.decode())
else:
func_log(stderr_data.decode())
raise OSError("Command execution faied: %s" % command)
if background:
threading.Thread(target=wait).start()
else:
wait()
def run_command_with_output(command):
proc = sp.Popen(command,
shell=True, stdout=sp.PIPE, stderr=sp.PIPE)
while True:
line = proc.stdout.readline()
if not line:
break
line = line.decode().rstrip("\n")
yield line
if proc.wait() != 0:
while True:
line = proc.stderr.readline()
if not line:
break
line = line.decode().rstrip("\n")
yield line
raise OSError("Command execution faied: %s" % command)
run_command は、func_log に関数が設定されていたら、その関数を用いて出力を行う。run_command_with_output は、出力を for 文で処理する。 コマンドの存在の有無
import shutil as su
su.which("ls")
JSONJSON ファイルの書き出し
import json
d = {
"a": "v",
"b": "w",
}
with open("d.json", "w") as f:
json.dump(d, f, ensure_ascii=False, indent=" ")
| |
| PENGUINITIS | |