プロジェクト

全般

プロフィール

10章学習記録 » 履歴 » バージョン 1

Tatsuya ISHIGAKI, 2025/07/11 09:50

1 1 Tatsuya ISHIGAKI
# 第10章 汎用 OS・ランタイムサービス
2
3
## 10.1 OS の機能を利用する os
4
5
- 実行中のプロセス属性の操作
6
7
  |プロセス属性|関数|
8
  |---|---|
9
  |環境変数|`environ()`, `getenv()`, `setenv()`, ...|
10
  |ユーザーID|`getuid()`, `setuid()`, `geteuid()`, `seteuid()`, ...|
11
  |グループID|`getgid()`, `setgid()`, `getgroups()`, `setgroups()`, ...|
12
  |プロセスID|`getpid()`, `getpgid()`, `getppid()`, ...|
13
  |スケジューリング優先度|`getpriority()`, `setpriority()`, ...|
14
15
- ファイルとディレクトリの操作
16
  - `pathlib` モジュールの方がおすすめ
17
18
  |関数|解説|戻り値|pathlib の同等関数|
19
  |---|---|---|---|
20
  |`chdir(path)`|作業ディレクトリ設定|None||
21
  |`chmod(path, mod, *, dirfd=None, follow_symlinks=True)`|モード変更|None|`Path.chmod()`|
22
  |`chown(path, uid, gid, *, dir_fd=None, follow_symlinks=True)`|所有者、グループの変更|None||
23
  |`getcwd()`|現在のディレクトリを取得|str|`Path.cwd()`|
24
  |`listdir(path='.')`|ディレクトリ内のファイル、ディレクトリをリスト出力|list|`Path.iterdir()`|
25
  |`makedir(path, mode=0o777, *, dir_fd=None)`|ディレクトリ作成|None|`Path.mkdir()`|
26
  |`makedirs(name, mode=0o777, exist_od=False)`|中間ディレクトリを含めてディレクトリ作成|None|`Path.mkdir()`|
27
  |`remove(path, *, dir_fd=None)`|ファイルを削除 (ディレクトリの場合は OSError)|None|`Path.unlink()`|
28
  |`removedirs(name)`|再帰的ディレクトリ削除|None||
29
  |`rename(src dst, *, src_dir_fd=None, dst_dir_fd=None)`|名前変更|None|`Path.rename()`|
30
  |`renames(old, new)`|中間ディレクトリ削除・作成を含めた名前変更|None||
31
  |`rmdir(path, *, dir_fd=None)`|ディレクトリを削除|None|`Path.rmdir()`|
32
  |`symlink(src, dst, target_is_directory=False, *, dir_fd=None)`|src を指すシンボリックリンクを dst のファイル名で作成|None|`Path.symlink_to()`|
33
34
  - ファイルパス関連定数
35
    |定数名|解説|戻り値|
36
    |---|---|---|
37
    |`curdir`|現在のディレクトリ|str|
38
    |`pardir`|親ディレクトリ|str|
39
    |`sep`|パス名の区切り文字列|str|
40
    |`extsep`|ファイル名と拡張子を分ける文字|str|
41
    |`linesep`|行の終端文字列|str|
42
43
- さまざまなシステム情報へのアクセス
44
45
  |関数名、辞書名|解説|戻り値|
46
  |---|---|---|
47
  |`confstr(name)`|システム設定値の文字列取得|str|
48
  |`confstr_names`|confstr() に渡すことのできる値を定義した辞書|dict|
49
  |`sysconf(name)`|システム設定値の整数取得|int|
50
  |`sysconf_names()`|sysconf() に渡すことのできる値を定義した辞書|dict|
51
  |`cpu_count()`|CPU数の取得<br>取得できなくても None 返すだけ|int|
52
  |`getloadavg()`|過去1分間、5分間、15分間の load average をタプルで返す|(float, float, float)|
53
54
  - `os.cpu_count()` に似た動作の関数に `multiprocessing.cpu_count()` がある
55
    - 違いは、CPU数を取得できなかった (Python が解決できなかった) 場合の挙動
56
    - `os.cpu_count()` None を返す
57
    - `multiprocessing.cpu_count()` 例外 NotImplementedError を送出
58
59
- ランダムな文字列の生成
60
  - `os.urandom()` **OS が提供する乱数生成機能を用いて** 生成したランダムな bytes オブジェクトを返す
61
    - `random` モジュールの疑似乱数より、セキュリティ面では `os` または `secrets` モジュールの乱数生成が推奨されている
62
63
- システム情報取得に使われるサードパーティ製パッケージ psutil
64
  - `psutil.cpu_times()` CPU時間を求める
65
  - `psutil.virtual_memory()` メモリ使用率に関する統計情報を求める
66
  - `psutil.disk_partitions()` マウント済みのディスクパーティション情報を取得
67
  - `psutil.net_ioi_counters()` ネットワーク I/O に関する統計情報を求める
68
69
## 10.2 ストリームを扱う io
70
open() で開いたファイル同様に扱う、ストリームオブジェクト、file-like オブジェクトについて
71
72
- インメモリなテキストストリームを扱う StringIO
73
  - オブジェクト作成 `StringIO(initial_value='', newline='\n')`
74
    - `initial_value` 初期値となる文字列
75
    - `newline` 改行文字
76
77
  - `StringIO` クラスのメソッド
78
    |メソッド名|解説|戻り値|
79
    |---|---|---|
80
    |`read(size=-1)`|ストリームの現在オフセットから指定サイズの文字列を返す<br>size が負の値または None なら EOF まで|str|
81
    |`write(s)`|ストリームに文字列を書き込む|int|
82
    |`tell()`|現在のオフセットを返す|int|
83
    |`seek(offset, whence=SEEK_OUT)`|オフセットを指定位置に移動する (詳細省略)|int|
84
    |`getvalue()`|ストリームが保持しているすべての内容を文字列で返す (オフセット位置に依らない、オフセットの移動もなし)|str|
85
    |`close()`|ストリームを閉じる|None|
86
87
    ```python
88
    >>> import io
89
    >>> stream = io.StringIO("this is test\n")  # 初期値を渡すことができる
90
    >>> stream.read(10)  # ストリームから指定サイズだけ読み出す
91
    'this is te'
92
    >>> stream.tell()  # 現在のオフセットを返す
93
    10
94
    >>> stream.seek(0, io.SEEK_END)  # オフセットをストリームの末尾に変更する
95
    13
96
    >>> stream.write('test')  # ストリームに文字列を書き込む
97
    4
98
    >>> print(stream.getvalue())  # ストリームが保持するすべての内容を返す
99
    this is test
100
    test
101
    >>> stream.close()  # ストリームを閉じる
102
    >>> stream.write('test')  # 閉じたあとに書き込もうとすると例外を送出する
103
    Traceback (most recent call last):
104
      File "<stdin>", line 1, in <module>
105
    ValueError: I/O operation on closed file
106
    >>> with io.StringIO() as stream:  # withブロックを使うことで暗黙的にclose()を呼ぶこともできる
107
    ...     stream.write('test')
108
    ...
109
    4
110
    >>> the_zen_of_python = """The Zen of Python, by Tim Peters
111
    ... Beautiful is better than ugly.
112
    ... Explicit is better than implicit.
113
    ... Simple is better than complex.
114
    ... Complex is better than complicated.
115
    ... """
116
    >>> stream = io.StringIO(the_zen_of_python)
117
    >>> for line in stream:  # for文で1行ずつ読み込むこともできる
118
    ...     line
119
    ...
120
    'The Zen of Python, by Tim Peters\n'
121
    'Beautiful is better than ugly.\n'
122
    'Explicit is better than implicit.\n'
123
    'Simple is better than complex.\n'
124
    'Complex is better than complicated.\n'
125
    ```
126
127
- インメモリなバイナリストリームを扱う BytesIO
128
  - オブジェクト作成 `BytesIO([initial_value])`
129
    - `initial_value` 初期値の bytes オブジェクト
130
131
    |メソッド名|解説|戻り値|
132
    |---|---|---|
133
    |`read(size=-1)`|ストリームの現在オフセットから指定サイズのバイト列を返す<br>size が負の値または None なら EOF まで|bytes|
134
    |`write(s)`|ストリームにバイト列を書き込む|int|
135
    |`tell()`|現在のオフセットを返す|int|
136
    |`seek(offset, whence=SEEK_OUT)`|オフセットを指定位置に移動する (詳細省略)|int|
137
    |`getbuffer()`|バッファーの内容を返す<br>この値は読み込みおよび書き込みが可能なビューで、値を更新するとバッファーの内容も更新される|memoryview|
138
    |`getvalue()`|バッファーの内容を返す<br>この値を更新ができない|bytes|
139
    |`close()`|ストリームを閉じる|None|
140
141
- io モジュールをユニットテストで活用する
142
  - ファイルオブジェクトの代わりに使用
143
  - 標準出力などをキャプチャして比較
144
  - `unittest.mock.patch` でうまく使用できる
145
146
## 10.3インタープリターに関わる情報を取得、操作する sys
147
Python インタープリターが使用する変数、インタープリター動作に関する関数
148
149
- コマンドライン引数を取得する argv
150
  - `sys.argv` 実行時の引数がリストで保持されている
151
    - `argv[0]` は、指定ファイル名 (実行時に指定したままの文字列)
152
153
    ```python
154
    # exampe.py
155
    
156
    import sys
157
    print(sys.argv)
158
    ```
159
160
    ```python
161
    > python example.py -a AAA -b -c 5
162
    ['example.py', '-a', 'AAA', '-b', '-c', '5']
163
    ```
164
165
- ライブラリのインポートパスを操作する path
166
  - `sys.path` インポート対象のライブラリやパッケージを検索するパスを格納したリスト
167
    - ファイルパスを追加することで、import 可能なパッケージやモジュールを動的に変更できる
168
    - 初期化は以下の順に行われる
169
      - 実行された Python スクリプトのあるパス or 空文字列 (対話モード)
170
      - 環境変数 `PYTHONPATH` に設定されたパス
171
      - Python のインストール先
172
    - モジュールはリストの先頭のパスから順に検索され、最初に見つかったものがインポートされる (つまり、同名モジュールがあっても、リストの後ろにあるとインポートされない)
173
174
- プログラムを終了する exit()
175
  - `sys.exit()` 呼び出した時点で Python スクリプトの実効を終了する関数
176
  - `exit([arg])`
177
    - `arg` 数値または任意のオブジェクト
178
      - 数値を指定すると、それを終了コードとする (未指定だと 0 扱い)
179
      - 数値以外を指定すると、オブジェクトを文字列として `sys.stderr` へ出力し、終了コードは 1 となる
180
181
- コンソールへの入出力を扱う stdin, stdout, stderr
182
  
183
  |オブジェクト|解説|タイプ|
184
  |---|---|---|
185
  |`sys.stdin`|標準入力|読み込み専用|
186
  |`sys.stdout`|標準出力|書き込み専用|
187
  |`sys.stderr`|標準エラー出力|書き込み専用|
188
189
  ```python
190
  >>> sys.stdout.write('standard output message\n')
191
  standard output message  # 標準出力された文字列
192
  24  # write()メソッドの戻り値
193
  >>> sys.stderr.write('standard error message\n')
194
  standard error message  # 標準エラー出力された文字列
195
  23  # write()メソッドの戻り値
196
  >>> sys.stdin.write('standard input message?\n')
197
  Traceback (most recent call last):  # 標準入力オブジェクトは読み込み専用のため、書き込みは失敗する
198
    File "<stdin>", line 1, in <module>
199
  io.UnsupportedOperation: not writable
200
  >>> sys.stdin.read()
201
  standard input message  # 端末に任意の文字列を入力して改行
202
  'standard output message\n'  # Ctrl+D(EOF)が入力されると、read()が受け取った値を返す (Windows だと Ctrl+Z か)
203
  ```
204
205
- breakpoint() 実行時のフック関数 breakpointhook()
206
  - `sys.breakpointhook()`
207
  - 組み込み関数 `breakpoint()` でデバッグを開始した際に呼ばれるフック関数
208
    - (breakpoint() : 第17章)
209
210
- Python のバージョン番号を調べる version_info
211
  - `sys.version_info` バージョン番号を表す 5 要素タプル
212
    - `major` `minor` `micro` `releaselevel` `serial`
213
    - `releaselevel` 以外は整数 (releaselevel は基本的に文字列か)
214
215
## 10.4 コマンドラインオプション、引数を扱う argparse
216
217
- コマンドラインオプションを扱う
218
  - `ArgumentParser()`
219
    |引数名|解説|デフォルト値|
220
    |---|---|---|
221
    |`prog`|プログラム名|`sys.args[0]`|
222
    |`usage`|プログラム利用方法|パーサー指定した引数から自動生成|
223
    |`description`|引数のヘルプの前に表示される文字列|`None`|
224
    |`epilog`|引数のヘルプの後に表示される文字列|`None`|
225
    |`parents`|ArgumentParser オブジェクトのリストを指定すると、そこに含まれる引数が追加される|`[]`|
226
    |`formatter_class`|ヘルプとして表示されるフォーマットをカスタマイズするためのクラス|`argparse.HelpFormatter`|
227
    |`prefix_chars`|引数の先頭の文字を指定する|`-`|
228
    |`fromfile_from_chars`|引数をファイル指定して読み込む際に、フファイルの前に付ける文字を指定|`None`|
229
    |
230
231
  - `add_argument()`
232
  - `parse_args()`
233
234
```python
235
# repeat.py
236
237
import argparse
238
239
# パーサーのインスタンスを作成
240
parser = argparse.ArgumentParser(description='Example command')
241
# 文字列を受け取る-sオプションを定義
242
parser.add_argument('-s', '--string', type=str, help='string to display', required=True)
243
# 数値を受け取る-nオプションを定義
244
parser.add_argument('-n', '--num', type=int, help='number of times repeatedly display the string', default=2)
245
# 引数をパースし、得られた値を変数に格納する
246
args = parser.parse_args()
247
248
# パースによって得られた値を扱う
249
print(args.string * args.num)
250
```
251
252
- 実行例
253
  - `-h` オプションは、`ArgumentParser()` によって自動生成される
254
  - 必須オプションが無いとエラーが発生する
255
256
    ```powershell
257
    > python repeat.py
258
    usage: repeat.py [-h] -s STRING [-n NUM]
259
    repeat.py: error: the following arguments are required: -s/--string
260
    > python repeat.py -h
261
    usage: repeat.py [-h] -s STRING [-n NUM]
262
    
263
    Example command
264
    
265
    options:
266
      -h, --help           show this help message and exit
267
      -s, --string STRING  string to display
268
      -n, --num NUM        number of times repeatedly display the string
269
    ```
270
271
  - 引数指定実行
272
273
    ```powershell
274
    > python repeat.py -s "Hey! "
275
    Hey! Hey!
276
    > python repeat.py -s "Hey! " -n 5
277
    Hey! Hey! Hey! Hey! Hey!
278
    ```