Pythonのsubprocessモジュール徹底解説!プロセスの基本から実践的な使い方まで
プロセスとは何か
Windows、Mac、Linuxなどの環境でプログラムを作成して実行すると、オペレーティングシステム(OS)は「プロセス」という単位を生成します。プロセスは、CPU、RAM、ディスク容量といったシステムリソースを使用し、OSカーネル内のデータ構造にもアクセスします。また、各プロセスは互いに分離されており、他のプロセスが何をしているのかを覗き見たり、干渉したりすることはできません。
注意: 本記事のコードはLinux/Unix系システムを想定しています。Windows環境で実行すると例外が発生する場合がありますのでご注意ください。
オペレーティングシステムの役割
OSには大きく分けて2つの目的があります。1つ目はプロセス間で作業を公平に分配すること、2つ目はユーザーの操作に素早く応答することです。これらは、実行中のすべてのプロセスを追跡し、それぞれに短い実行時間を与えては別のプロセスへ切り替えることで実現されています。Windowsなら「タスクマネージャー」、macOSなら「アクティビティモニタ」、Linuxなら「top」コマンドなどを使えば、現在のプロセスの状態を確認できます。
プログラマーであれば、自分のプログラムから直接プロセス情報へアクセスすることも可能です。方法は簡単で、Python標準ライブラリの「os」モジュールを使うだけです。以下にいくつか例を示します。
# このスクリプトはLinux/Unixでのみ動作します
import os
print(f" *** プロセスID - {os.getpid()}")
print(f" *** ユーザーID - {os.getuid()} / グループID - {os.getgid()} ")
print(f" *** 現在の作業ディレクトリ - {os.getcwd()}")新しいシステムプロセスを起動・実行できることは、特定のOSタスクを自動化したい開発者やシステム管理者にとって非常に有用です。
Pythonには「subprocess」モジュールが用意されており、これを使うことで新しいプロセスの生成、プロセスとの情報の送受信、エラーや戻り値(リターンコード)の処理が可能になります。
Python公式ドキュメントでも、システムコマンドへのアクセスにはこのsubprocessモジュールの使用が推奨されています。
subprocessのcall()関数は、呼び出したコマンドが完了し、出力を読み終わるまで待機する仕組みです。以下では、システムのディスク容量情報を取得する具体例をいくつか紹介していきます。
例1:df -hコマンドでディスク容量を取得する
次のコードは「df -h」コマンドを実行してディスク情報を取得し、その出力をpandasのデータフレームに格納することで、後続のデータ処理に活用できるようにしたものです。
# Linux上でdf -hを使ってディスク容量を抽出するサブプロセスを作成するPythonコード
from io import StringIO
import pandas as pd
import subprocess
import ast
diskspace = "df"
diskspace_arg = "-h"
sp = subprocess.Popen([diskspace, diskspace_arg], stdout=subprocess.PIPE)
b = StringIO(sp.communicate()[0].decode('utf-8'))
df = pd.read_csv(b, sep=",")
print(df)出力結果
Filesystem Size Used Avail Use% Mounted on 0 devtmpfs 7.8G 0 7.8G 0% /dev 1 tmpfs 7.8G 0 7.8G 0% /dev/shm 2 tmpfs 7.8G 33M 7.8G 1% /run 3 tmpfs 7.8G 0 7.8G 0% /sys/fs/... 4 /dev/xvda2 20G 16G 4.3G 79% / 5 /dev/xvdb 246G 16G 218G 7% /tdm 6 tmpfs 1.6G 0 1.6G 0% /run/use...
より詳細なシステム情報を出力したい場合は、以下のコードを参考にしてください。ここでは「uname」コマンドでカーネル情報を取得しつつ、「pydf」コマンドの出力をcheck_output()で受け取り、文字列として加工しています。
例2:unameとpydfで詳細なシステム情報を取得する
from io import StringIO
import pandas as pd
import subprocess
def uname_func():
uname = "uname"
uname_arg = "-a"
user_info = subprocess.call([uname, uname_arg])
return user_info
def disk_func():
diskspace = "pydf"
diskspace_arg = "-a"
discinfo_df = diskspace
stdout = subprocess.check_output([diskspace, diskspace_arg])
return stdout
def main():
userinfo = uname_func()
discinfo = disk_func()
print("値を表示します... ")
print(discinfo.decode('utf-8'))
print(type(discinfo.decode('utf-8')))
content = discinfo.decode('utf-8').split("\n")
print(content)
main()出力結果
Linux ip-00-000-00-000.xxxx.xxxx.xx.xx 0.00.0-000.el7.x86_64 #1 SMP Tue Aug 18 14:50:17 EDT 2020 x86_64 x86_64 x86_64 GNU/Linux 値を表示します... Filesystem Size Used Avail Use% Mounted on /dev/xvda2 20G 16G 4318M 78.9 [#####.] / devtmpfs 7918M 0 7918M 0.0 [......] /dev hugetlbfs 0 0 0 - [......] /dev/hugepages mqueue 0 0 0 - [......] /dev/mqueue tmpfs 7942M 32M 7909M 0.4 [......] /run tmpfs 1588M 0 1588M 0.0 [......] /run/user/1000 /dev/xvdb 246G 16G 218G 6.4 [......] /tdm
主な関数の違いをおさらい
subprocessモジュールには用途に応じて複数の関数が用意されています。
- call(): コマンドを実行し、完了するまで待機します。戻り値はリターンコードのみです。
- check_output(): コマンドを実行し、標準出力の内容をバイト列として返します。エラー時には例外を発生させます。
- Popen(): より柔軟な制御が可能で、communicate()メソッドと組み合わせることで入出力のやり取りを行えます。
これらを使い分けることで、シェルコマンドの自動化やシステム監視ツールの構築など、幅広いタスクをPythonから効率的に実行できます。
-
PythonのTkinterでウィンドウのタイトルバーを編集・カスタマイズする方法
Tkinterでは、プログラムを実行するとウィンドウやフレームが画面に表示されます。Tkinterの関数やモジュールはそれぞれ独立して構成されているため、特定の関数を使ってウィンドウの属性を柔軟にカスタマイズすることが可能です。Tkinterは、アプリケーションごとにデフォルトのルートウィンドウを自動的に作成します。このデフォルトのタイトルを変更・編集したい場合は、以下のメソッドを使用します。title(text= 任意のタイトル)それでは、実際にTkinterフレームのオブジェクトを生成してウィンドウを作成し、そのタイトルを編集してみましょう。サンプルコード# ライブラリをインポート fro
-
PythonのTkinterでスレッドを使う方法|threadingモジュールによる非同期処理の基本
Tkinterでは、スレッド(Threading)を活用することで、複数の関数を同時に実行できます。これにより、アプリケーション内の処理を非同期で動かすことが可能になります。 Pythonでスレッドを使用するには、まずthreadingモジュールをインポートし、そのThreadクラスを継承した新しいクラスを定義します。そして、クラス内でrunメソッドをオーバーライドし、実行したい処理をその中に記述します。 つまり、スレッドを使えば複数の作業を並行して進めることができます。Tkinterアプリケーションでスレッドを実現する際は、Thread()関数を利用します。 ここでは、「一定時間スリープした