Python: 02. 標準ライブラリ - ikymrkw/pydepot GitHub Wiki
実行環境 (sys)
sys.stdin # 標準入力ストリーム
sys.stdout # 標準出力ストリーム
sys.stderr # 標準エラー出力ストリーム
コマンドライン引数
import sys
argvs = sys.argv # 引数リスト
# 引数リストには python コマンドの引数が格納される。
# 0にスクリプト名、1、2、……に引数。
#
# 細かく言うと:
# - python abc.py x y z と実行した場合、
# argvs[0] == "abc.py", argvs[1] == "x", ... となる。
# - Unix-like OS で shell bang を使い、./abc.py x y z と実行した場合、
# argvs[0] == "./abc.py", argvs[1] == "x", ... となる。
argparseモジュールを使うともっといろいろできる。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("infile", type=file)
parser.add_argument("--foo")
args = parser.parse_args()
lines = read_lines(args.infile)
終了
sys.exit(exitcode)
プログラムの終了時に関数を呼びたいときは、atexitモジュールを使う(かつては sys.exitfunc だったが、2.4以降では deprecated)。Ctrl-Cで終了された場合も呼ばれる。
import time
import atexit
def finisher():
print "Finished!"
atexit.register(finisher)
while True:
print "waiting..."
time.sleep(1)
サブプロセス
コマンドの実行結果(標準出力、エラー出力)を受け取る。
import subprocess
p = subprocess.Popen(['cmd', 'arg1', 'arg2'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(s_stdout, s_stderr) = p.communicate()
if p.returncode==0:
print s_stdout
p.communicate() はサブプロセスが終了するまで待機する。
p.communicate() 時の標準入力・出力・エラー出力はデフォルトでは Python のプロセスのものが使われる。 したがって、出力は python を実行したシェルに出力されたりする。出力したくない場合は、上記のように PIPE に接続する。入力も同様で、PIPE につなげば communicate(input) の引数が入力に使われる(文字列型?)
ファイル操作
ビルトイン
f = open('foo.txt', 'r')
data = f.read()
なお、モードを 'rU' とすることで改行文字の違いを無視できる。'rb' ならバイト読み出し。
1行ずつ読み込み
for line in f: ...
for line in f.readlines(): ... # in f と同じ?
for line in sys.stdin: ... # 標準入力の場合
ioモジュール
import io
f = io.StringIO(text)
lines = f.readlines()
# ただしこれと同じことが以下でできる:
lines = text.splitlines()
osモジュール
https://docs.python.org/ja/3/library/os.html
chdir('path')
getcwd()
remove('path')
rename('before', 'after')
mkdir('path'[, 'mode'])
makedirs('path'[, 'mode'][, exist_ok=True]) # 中間ディレクトリも作る。exist_ok=Trueなら既存でもOK
rmdir('path')
removedirs('path')
listdir('path')
walk('path'[, topdown=True][, onerror=None]) # ジェネレータを返す。
# 要素は (ディレクトリ名, 子ディレクトリのリスト, ファイルのリスト) の三つ組(タプル)。
os.path.exists('path')
os.path.isfile('path')
os.path.isdir('path')
文字・文字列・コンソール出力
オブジェクトの文字列化一般
s = str(obj)
オブジェクトの __str__() メソッドを定義することで str() が返す文字列を制御することができる。
str() は人間が(デバッグ用に)読む文字列を返すことが期待されている。
一方、repr() という関数もあり、__repr__() メソッドに対応している。こちらは eval() で元に戻せる文字列が期待されている。
フォーマッティング
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
Pretty Print (pprint)
import pprint
pprint.pprint(obj)
s = pprint.pformat(obj)
フォーマット済み文字列リテラル
s = f"Results of the {year} {event}"
中括弧内には式を書ける。
str.format() メソッド
s = "Results of the {} {}".format(year, event)
中括弧内に番号を書くことで、引数の位置を指定できる。
s = "{1} and {0}".format("egg", "chicken")
中括弧内にキーワード引数名で指定することもできる。
s = "This {food} is {adjective}".format(food='soup', adjective='hot')
中括弧内には書式指定を書くこともできる。
s = "{1:2d} {0:3d} {2:.4f}".format(id, count, probability)
文字符号化
文字列からの変換でよければ str.encode() メソッドでできる。
'ABC'.encode('utf-8') # = b'ABC' # デフォルトは 'utf-8'
'ABC'.encode('utf-16') # = b'\xff\xfeA\x00B\x00C\x00'
# 文字符号化以外に hex も使える
'ABC'.encode('hex') # = '414243'
'414243'.decode('hex') # = 'ABC'
# str.decode() はない。
# codecs.encode(s, encoding) や .decode(s, encoding) のほうが汎用性は高い
ストリームを使いたい場合は codecs パッケージを使う。
codecs.getreader("UTF-8")(sys.stdin) # ストリームからUTF-8で読み込む
codecs.open("filename", "r", "UTF-8") # ファイルからUTF-8で読み込むためのファイルストリームを生成
なお、Python 3 では文字列(文字ストリーム)とバイト列(バイトストリーム)は厳密に区別されるようになったため、文字ストリームを返す sys.stdin をデコードすることはできない。sys.stdin.detach() とするとバイトストリームを得られるので、こちらを使うと良い。
Base64 と uuencode
'abc'.encode('base64')
'abc'.encode('uu')
正規表現
re パッケージを使う。[https://docs.python.org/3/library/re.html#module-re]
import re
m = re.match("re", input)
if m:
print m.group(1)
m = re.search("re", input)
pattern = re.compile("re")
re.split(',', 'abc,def,ghe') # = ('abc', 'def', 'ghi')
copy
copy.copy(obj) shallow copy
copy.deepcopy(obj) deep copy
双方向キュー (deque)
http://docs.python.jp/2.5/lib/deque-objects.html
from collections import deque
q = deque() # or deque(iterable)
first = q[0] # リストと同様のアクセスも可能
tail = q.pop()
head = q.popleft()
q.append(x)
q.appendleft(y)
q.extend(iterable)
q.extendleft(iterable)
ただし、q[1:2]のようなスライスはできない模様。
時間
time --- 簡易な方法
POSIXタイムスタンプ(epochからの秒数、ただしタイムゾーンによって異なる)を得るには
import time
time.time()
=> 1445241301.727 # ローカル時間のPOSIXタイムスタンプ(システム依存の浮動小数点)
time.ctime()
=> 'Mon Oct 19 16:58:38' # ローカル時間の文字列
# time.asctime(time.localtime()) と同じ
# ctime() や localtime() はタイムスタンプを与えることもできる
time パッケージはローカル時間(とローカルタイムゾーン)しか扱えないので、
UTC時間が欲しい場合は自分で計算する必要がある。もしくは、下記の datetime を使う。
datetime の取得
from datetime import datetime
t1 = datetime.now() # ローカル時間での現在時刻の datetime オブジェクト(tz情報なし)
t2 = datetime.now(tz) # 指定タイムゾーンでの現在時刻の datetime オブジェクト(指定したtz情報あり)
t3 = datetime.utcnow() # UTCでの現在時刻の datetime オブジェクト(tz情報なし)
t1.timestamp() # datetimeオブジェクトからPOSIXタイムスタンプへ
# ローカル時刻のタイムスタンプから datetime オブジェクトを得る
datetime.fromtimestamp(timestamp) # (1) ローカル時刻 timestamp がローカルTZでは何時か
datetime.fromtimestamp(timestamp, tz) # (2) ローカル時刻 timestamp が tz では何時かを示す
datetime.utcfromtimestamp(timestamp) # (3) ローカル時刻 timestamp が UTCでは何時かを示す
# 注: (1)と(3)はタイムゾーン情報のない datetime オブジェクトを返すことに注意
# UTC時刻のタイムスタンプから UTC での datetime オブジェクトを得る
from datetime import timezone
datetime.fromtimestamp(utc_timestamp).replace(tzinfo=timezone.utc)
# さらに
# .astimezone() をすればローカルTZでの時刻に、
# .astimezone(tz) とすれば目的のTZでの時刻に、
# それぞれ変換できる。
タイムゾーンを得る方法:
from datetime import datetime, timezone, timedelta
# A. UTCのタイムゾーン
tz_utc = timezone.utc
# B. ローカルのタイムゾーン(システムに依存する)
tz_local = datetime.now().astimezone().tzinfo # astimezone() はローカル時刻とみなしてTZ情報を付ける
# C. 数値指定のタイムゾーン
tz_there = timezone(timedelta(hours=-9))
# D. 名前指定のタイムゾーン
# Python標準では名前は未対応。外部パッケージ pytz を使うのが一般的
文字列化:
from datetime import datetime, timezone
# こだわりがなければ ISO format がわかりやすい。タイムゾーンには注意。
dt1 = datetime.now()
print(dt1.isoformat()) # => '2024-05-30T11:22:33.234567' # 暗黙的にローカルTZ
dt2 = dt1.astimezone() # 引数なしはローカルTZ情報を付ける
print(dt2.isoformat()) # => '2024-05-30T11:22:33.234567+09:00' # 明示的にローカルTZ
その他の操作
差分を取るには、time.time()を引き算してもよいが、datetimeなら差分オブジェクトになる。
from datetime import datetime
x = datetime.utcnow()
...
y = datetime.utcnow() # 差だけを見るなら x, y ともに now() でも構わない
d = y - x # d は timedelta オブジェクト(日, 秒, マイクロ秒のみ保存されている)
d.days # 日部分
d.seconds # 秒部分
d.microseconds # マイクロ秒部分
d.total_seconds() # 日・秒・マイクロ秒を秒換算した浮動小数点数を返す
sleep するには
import time
time.sleep(1.5) # 単位は秒
マルチスレッド (threading)
import threading
def main():
worker = threading.Thread(target = f, args = ("abc", ))
worker.start()
def f(msg):
while True:
print msg
time.sleep(1)
Thread生成時に daemon を指定できるが、いきなり止まるので推奨されない。 Eventなどを使って適切に処理すべき。
ev = threading.Event()
ev.is_set()
ev.set()
ev.clear()
乱数
random モジュールに含まれる。
randint(a, b) # a <= x <= b のランダムな整数 x を返す
uniform(a, b) # randint と同様だが、実数を返す
random() # 0以上1以下の実数を返す
randrange(start, end, step) # range と同様だが、ランダムに並べ替えたシーケンスを返す
choice(シーケンス) # シーケンスからランダムに選んだ一つを返す
shuffle(シーケンス, 関数) # シーケンス自身をシャッフルする。関数は省略可だが、random()同様の乱数関数を指定する。
sample(シーケンス, n) # シーケンスからn個選んで返す。同じ要素は重複して選ばない。
seed(x) # シードする。xは省略可。randomモジュールが読まれた時点で呼ばれている。
ただし、これらは暗号学的安全ではない。必要なら PyCrypto モジュールの Crypto.Random を使う(後述)。
各種データの入出力
シリアライゼーション (Pickle)
Pickle はシリアライゼーションのためのモジュール。
obj = range(100)
from cPickle import dump
output = open('obj.pkl', 'wb')
dump(obj, output, -1)
output.close()
from cPickle import load
input = open('obj.pkl', 'rb')
obj = load(input)
input.close()
CSV
読み込み
import csv
f = open("abc.csv", "rb")
for row in csv.reader(f):
print row # row は文字列のリスト
XML
xml.etree.ElementTree を使う。[http://docs.python.jp/2/library/xml.etree.elementtree.html]
import xml.etree.ElementTree as ET
tree = ET.parse('filepath')
root = tree.getroot()
root.find('.//customer') # XPathサブセットで要素を指定
名前空間については、名前空間のマップを指定して検索することができるらしいが、 自分のマシンに入っていたETでは未対応だった。この場合、"{namespaceuri}tagname" というように 中括弧で囲って名前空間URIを書くしかないらしい。
JSON
import json
text = json.dumps(data)
text = json.dumps(data, indent=4, sort_keys=True)
# data は、基本は Python のリスト/タプルまたはディクショナリだが、
# 文字列を渡すと JSON エンコードしてくれる。
# dumps のフォーマッティングには jinja2 が必要かもしれない。
data = json.loads(jsontext)
バイトデータ
メッセージダイジェスト (hashlib)
import hashlib
hashlib.md5('abc').hexdigest() # 16進文字列を返す。他に sha1(), sha256() など。
バイト列 (bytes, bytearray)
Python 2 では文字列型がバイトの列なので、バイト列を文字列型として扱うこともできるが、その要素は文字(要素数1の文字列)なので整数としての扱いが少々不便(chrやordを入れないといけない)。
bytes と bytearray は 0~255 の int の配列として使える。ほぼ文字列型と同様のメソッドが利用可能。 両者の違いは bytes が不変 (str や tuple と同様)、bytearray が可変 (list と同様) なことで、 それ以外はほぼ同様の操作が可能。
# 生成
bytearray()
bytearray([1, 2, 3, 255])
bytearray.fromhex('abcd')
# 参照
bb[1]
bb[1:3]
# 結合
bb1 + bb2
bb1 * 4
# 文字列化
''.join(["%02x" % b for b in bb]) # 16進数表現。hex()は使えない。
str(bb) # バイト文字列
Enum
from enum import Enum
class Land(Enum):
HOKKAIDO = 0
HONSHU = 1
SHIKOKU = 2
KYUSHU = 3 # 値は整数じゃなくてもよい。文字列などでもなんでもよい。
start = Land.HOKKAIDO
from enum import Enum, auto
class X(Enum):
A = auto()
B = auto()
from enum import Enum
Language = Enum('Language', 'EN JP FR')
lang = Language.EN