『退屈なことはPythonにやらせよう』その13(15章:時間制御、自動実行)
Python初心者です。『退屈なことはPythonにやらせよう』を走っています。
13回目の今回は、15章をやっていきます~。
CSVファイル、JSONファイルをいじった前回の記事はこちら↓
今回の目次
1. Pythonで時間を扱う(time, datetimeモジュール)
timeモジュール
timeモジュールは、Python上でコンピュータに搭載された時計を利用するためのモジュールです。以前Webスクレイピングの章(記事はこちら)で、ウェブサイトの画面が切り替わるのを待つためにtime.sleep(5)とかやったときに活躍したモジュールですね。ここではtimeモジュールで重要な二つのメソッドを見ていきます。すなわち、
- time.time()
- time.sleep()
の二つです。
time.time()関数はUNIXエポックからの経過秒数を浮動小数点数で返す
UNIXエポックというのは1970年1月1日 0:00 (協定世界時)の時刻のことをさします。この瞬間から、何秒経過したかを返してくれる関数です。また、返してくれる数字は、整数ではなく浮動小数点数(要はfloat)なので、「コンマ~~秒」みたいなところまでの解像度がある時間になります。そしてこの時間をエポックタイムスタンプと呼ぶそうです。time.time()を呼び出した瞬間の時間が返ります。
使い方としては、動かすプログラムの前後をtime.time()で挟んでやることで、そのプログラムの実行時間が分かるとかいうところです。
time.sleep()関数はプログラムを指定時間停止することができる
time.sleep()で、引数として渡した秒数だけ、プログラムの実行を一時停止します。Webスクレイピングなどを行う時は、ページの読み込み待ちのためだけでなく、サーバーに負荷をかけすぎないようにするためにも活用していく必要がありますね。
datetimeモジュール
datetimeというデータ型を生成し時間を扱うためのモジュールです。標準モジュールなので、importさえすれば使用することができます。
主に使う機能を下に書き出しておきます。さきほどのtimeモジュールはUNIXエポックからの秒数で、人間が見てもちょっと分かりにくい形でした。datetimeモジュールでは、(2020, 5, 21, ~~)のように、人間が見て理解しやすい形の時間を返してくれます。
- datetime.datetime.now() : 現在時刻を取得
- datetime.datetime.fromtimestamp() : UNIXエポックの時間をdatetimeオブジェクトに変換
datetimeモジュールはdatetime.timedeltaとすると、期間を表すことができます。datetimeオブジェクトの足し算や引き算はtimedeltaオブジェクトを使うことになります。timedeltaオブジェクトには、引数としてweeks, days, hours, minutes, secondsなどを取ることができます。secondsより細かいやつも大丈夫です。ですが、monthsとyearsは期間が一定でないため、引数として渡すことができません。ここは注意が必要です。
datetimeオブジェクトを文字列に変換する方法としてstrftime()メソッドがあります。「datetimeオブジェクト.strftime(“欲しいフォーマット”)」という感じで渡します。公式ドキュメントにて、strftimeに渡せる引数の型一覧がありますので、ぜひそちらもご参照ください。(リンクはこちら)
逆に、文字列をdatetimeオブジェクトに変換するのはstrptime()メソッドです。「datetime.datetime.strptime(“文字列”, “型の説明”)」という感じで使います。型の説明というのは、年-月-日で書かれてますとか、月-日-時間:分:秒で書かれてますとかそういう風にして、渡した文字列がどういうものなのかを説明するということです。この時にも、strftime()メソッドと同じように “%Y/%m/%d %H:%M:%S”みたいな書き方をする必要があります。
2. Pythonから他のプログラムを実行する(threading, subprocessモジュール)
threadingモジュールはマルチスレッドのプログラムを作れる
threadingモジュールをインポートし、threading.Thread()の引数として、マルチスレッド的に処理する場所をいれる→Threadオブジェクト
「Threadオブジェクト.start()」とすると、Threadオブジェクトに格納された処理が始まる。その処理とは別に、下に書かれたコードの処理も進む。
Threadオブジェクトへの格納は以下のような形です。
import threading
thread_obj = threading.Thread(target = "<関数>",
args=["関数に渡す引数"],
kargs=["関数に渡す引数(オプションみたいなやつ)"])
thread_obj.start() #ここでThreadオブジェクト内のプログラムが走り始める。
スレッド同士がぶつかったりしてデバッグも難しくなるらしいので、乱用には気を付けましょう…
subprocessモジュール
Popen()関数
Popen関数はPython以外のプログラムを動かすために使えるモジュールです。引数として、以下のものを渡すことが出来ます。
- 「.exe」(ロックマンではない)
- リスト → [“実行したいプログラム”, “コマンドライン引数として渡したいもの”]
- アプリを開く → subprocess.Popen([“start”, “実行したいファイル”], shell = True)
Macの場合はstartじゃなくてopen、Linuxはsee。
pythonスクリプトを実行したい場合は以下のようになります。
import sys, subprocess
subprocess.Popen([sys.executable, "yourAwesomePythonScript.py"])
3. 15章:演習プロジェクト
ストップウォッチの整形
ストップウォッチプログラムを綺麗に整形した形でテキストに書き出す。その後、書き出したテキストをクリップボードにコピーできるようにする。
rjustを活用して、かなり良い感じに出来ました。
#! python3
# stopwatch.py - シンプルなストップウォッチプログラム
import time, pyperclip
#プログラムの説明を表示する
print("Enterを押すと開始します。その後、Enterを押せば経過時間を表示します。Ctrl-Cで終了します。")
input()
print("スタート")
start_time = time.time()
last_time = start_time
lap_num = 1
#ラップタイムを表示する
try:
text_list = []
while True:
input()
now = time.time()
lap_time = round(now - last_time, 2)
total_time = round(now - start_time, 2)
tex = "ラップ #"+ str(lap_num).rjust(2) + ":" + str(total_time).rjust(6) + " (" +str(lap_time).rjust(6) + ")"
print("ラップ #"+ str(lap_num).rjust(2) + ":" + str(total_time).rjust(6) + " (" +str(lap_time).rjust(6) + ")", end="")
text_list.append(tex)
lap_num += 1
last_time = now
except KeyboardInterrupt:
#Ctrl-C例外を処理してエラーメッセージを表示しないようにする。
pyperclip.copy("\n".join(text_list))
print("\n終了")
工夫した点はそんなにないです… pyperclipにはリストオブジェクトを渡すことはできないので、.join()を使って文字列として張り付けています。もし改行したくない場合は、「”,”」とか「” “」でjoinするようにすれば良いですね。
クリップボードにコピーされたのは以下のものになります。(時間はEnterカチカチのタイミング次第です)
ラップ # 1: 2.05 ( 2.05)
ラップ # 2: 3.67 ( 1.61)
ラップ # 3: 6.59 ( 2.92)
ラップ # 4: 9.8 ( 3.21)
ラップ # 5: 15.07 ( 5.26)
ラップ # 6: 15.93 ( 0.86)
ラップ # 7: 19.3 ( 3.37)
今回はタスクスケジューラはスキップしたいと思います……
4. 感想
今回のやつは、まだ「ここに使おう!」というやつがあまり見つかりませんでした…ただ、timeモジュールやdatetimeモジュールに関しては時系列データを扱ったりするのに便利なモジュールなので、そういう方面で活用できそうですね。threadingモジュールに関してはちょっとまだピンと来ていないです……subprocessモジュールも、なんとなく使えそうな気もするのですが、まだ活用例が思いついていないですね。
手抜きで書いちゃった次の記事はこちら↓