出力整形
reprlib
, pprint
, textwrap
, locale
など
import reprlib
import pprint
import textwrap
import locale
# reprlibはrepr()の別バージョンで、巨大なコンテナお部ジェクトを省略して表示する
charset = reprlib.repr(set('supercalifragilisticexpialidocious'))
print(charset)
# {'a', 'c', 'd', 'e', 'f', 'g', ...}
# pprintはデータ構造を分かりやすく表示してくれる
t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta', 'yellow'], 'blue']]]
pprint.pprint(t, width=30)
# [[[['black', 'cyan'],
# 'white',
# ['green', 'red']],
# [['magenta', 'yellow'],
# 'blue']]]
# textwrap.fill()は各段落を指定の幅におさまるように折り返してくれる
doc = """The wrap() method is just like fill() except that it returns a list of strings instead of one big string with newlines to separate the wrapped lines."""
print(textwrap.fill(doc, width=40))
# The wrap() method is just like fill()
# except that it returns a list of strings
# instead of one big string with newlines
# to separate the wrapped lines.
# localeは国ごとの表現(単位など)を呼び出すことができる
locale.setlocale(locale.LC_ALL, 'English_United States.1252')
conv = locale.localeconv()
x = 1234567.8
print(locale.format("%d", x, grouping=True))
# 1,234,567
print(locale.format_string("%s%.*f", (conv['currency_symbol'], conv['frac_digits'], x), grouping=True))
# $1,234,567.80
テンプレート
ポイント
-
Template
モジュールを使うと置き換え記号($)を使ったテンプレート文字列を実装することができる - $の後に英数字、アンダースコアを用いた数字を続けられる
- $は$でエスケープ可能
- $のあとに{}を続けるとスペースを入れなくても英数字、アンダースコアを続けることが可能
from string import Template
t = Template('${village}folk send $$10 to $cause.')
sentence = (t.substitute(village='Nottingham', cause='the ditch func'))
print(sentence)
# Nottinghamfolk send $10 to the ditch func.
# substituteメソッドはプレースホルダをディクショナリか
# キーワード引数を渡さないとKeyErrorとなるので、
# safe_substituteメソッドの方が安全な場合がある
# データがなければプレースホルダはそのまま出力される
t = Template('Return the $item to $owner.')
d = dict(item='unladen swallow')
sentence = t.safe_substitute(d)
print(sentence)
# Return the unladen swallow to $owner.
Templateのサブクラスでは$の代わりに、区切り文字を変えることもできる
ファイル目の変更
import time, os.path
from string import Template
photofiles = ['img_1074.jpg', 'img_1076.jpg', 'img_1077.jpg']
class BatchRename(Template):
delimiter = '%'
fmt = input('どのようにリネームしますか (%d- 日付 %n- 番号 %f- 形式): ')
# どのようにリネームしますか (%d- 日付 %n- 番号 %f- 形式): Ashley_%n%f
t = BatchRename(fmt)
date = time.strftime('%d%b%y')
for i, filename in enumerate(photofiles):
base, ext = os.path.splitext(filename)
newname = t.substitute(d=date, n=i, f=ext)
print('{0} --> {1}'.format(filename, newname))
# img_1074.jpg --> Ashley_0.jpg
# img_1076.jpg --> Ashley_1.jpg
# img_1077.jpg --> Ashley_2.jpg
バイナリデータレコードの処理
struct
モジュールのpack()
とunpack()
を利用して、可変長のバイナリレコードを処理することが出来る
zipファイルの各ヘッダ情報にループをかける例
import struct
# rb: バイナリでread
with open('myfile.zip', 'rb') as f:
data = f.read()
start = 0
for i in range(3): # 先頭から3つのファイルのヘッダを示す
start += 14
fields = struct.unpack('<IIIHH', data[start:start+16])
crc32, comp_size, uncomp_size, filenamesize, extra_size = fields
start += 16
filename = data[start:start+filenamesize]
start += filenamesize
extra = data[start:start+extra_size]
print(filename, hex(crc32), comp_size, uncomp_size)
start += extra_size + comp_size # 次のヘッダまでスキップ
マルチスレッド
ポイント
-
threading
モジュールを利用することで、メインプログラムを走らせたままバックグラウンド処理ができる
import threading, zipfile
class AsyncZip(threading.Thread):
def __init__(self, infile, outfile):
threading.Thread.__init__(self)
self.infile = infile
self.outfile = outfile
def run(self):
f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
f.write(self.infile)
f.close()
print('Finished background zip of:', self.infile)
background = AsyncZip('mydata.txt', 'myarchive.zip')
background.start()
print('メインプログラムは実行中です')
background.join() # バックグラウンドタスクの終了を待つ
print('メインプログラムはバックグラウンド処理の終了まで待っていました')
- マルチスレッドアプリケーションにおけるタスク協調においては単一のメインスレッドにリソースへのアクセスを集中させておいて、ほかのスレッドからのリクエストは
queue
モジュールを使ってメインスレッドに食わせる、というアプローチがよい - スレッド間通信にはQueueオブジェクトを使うと設計しやすく可読性も上がる
ログ取り
ポイント
-
logging
モジュールでは柔軟なログ記録システム - デフォルトではDEBUGメッセージとINFOメッセージが抑制されている
- デフォルトでは出力先は標準エラー出力になっている
- 出力オプションとしてはほかにeメール、データグラム、ソケット、HTTPサーバへの転送がある
- メッセージの優先度毎に出力先を選ぶこともできる
import logging
logging.debug('Debugging information')
logging.info('Informational message')
logging.warning('Warning: config file %s not found', 'server.conf')
logging.error('Error occurred')
logging.critical('Critical error -- shutting down')
# WARNING:root:Warning: config file server.conf not found
# ERROR:root:Error occurred
# CRITICAL:root:Critical error -- shutting down
弱参照
-
weakref
を用いると参照を生成せずにオブジェクトを追跡することができる - 不要になったオブジェクトは自動的に弱参照表から除かれ、弱参照オブジェクトへのコールバックが起きる
import weakref, gc
class A:
def __init__(self, value):
self.value = value
def __repr__(self):
return str(self.value)
a = A(10) # 参照を生成する
d = weakref.WeakValueDictionary()
d['primary'] = a # 参照を生成しない
print(d['primary']) # オブジェクトが生きていれば取ってくる
10
del a # 参照を削除
gc.collect() # ガベージコレクションを実行
d['primary'] # エントリは自動的に削除されている
# Traceback (most recent call last):
# File ".\weakref_sample.py", line 17, in <module>
# d['primary'] # エントリは自動的に削除されている
# File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.7_3.7.1520.0_x64__qbz5n2kfra8p0\lib\weakref.py", line 137, in __getitem__
# o = self.data[key]()
# KeyError: 'primary'
リスト操作のツール
-
array
モジュールは、同室のデータのみを収めるリスト類似のオブジェクトarray
を提供する
from array import array
a = array('H', [4000, 10, 700, 22222])
print(sum(a))
# 26932
print(a[1:3])
# array('H', [10, 700])
-
collections
モジュールは左端部へのappend
やpop
はリストより高速だが、中央部の参照は低速であるdeque
オブジェクトをもたらす - キューや幅優先ツリー検索を実装するときに便利
from collections import deque
d = deque(["task1", "task2", "task3"])
d.append("task4")
print("Handling", d.popleft())
unsearched = deque([starting_node])
def breadth_first_search(unsearched):
node = unsearched.popleft()
for m in gen_moves(node):
if is_goal(m):
return m
unsearched.append(m)
- ソート済みリストを操作する関数を持つ
bisect
モジュールなども備えている -
heapq
モジュールは通常のリストをベースにヒープを実装する関数を提供する
10進数の浮動小数点計算
-
decimal
モジュールは浮動小数点10進数で計算するためのデータ型Decimal
を提供する -
float
型より厳密な計算が可能