Python3 入門
Kivy による GUI アプリケーション開発，
サウンド入出力，
ウェブスクレイピング

第 3.2.18 版

Copyright © 2017-2024, Katsunori Nakamura

中村勝則
2024 年 10 月 11 日

免責事項
本書の内容は参考的資料であり，掲載したプログラムリストは全て試作品である．本書の使用に伴って発生した不利益，損害の一切の責任を筆者ならびに IDEJ 出版は負わない．

目次
1

2

はじめに

1

1.1

Python でできること . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1

1.2

本書の内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1

1.3

本書の読み方 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1

1.4

処理系の導入（インストール）と起動の方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2

1.4.1

Python 処理系のディストリビューション（配布形態） . . . . . . . . . . . . . . . . . . . . .

2

1.4.2

Python 処理系の起動 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2

1.4.3

対話モード

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

1.4.3.1

ヒストリ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

1.4.3.2

直前の値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3

1.5

本書で取り扱う GUI ライブラリ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4

1.6

表記に関する注意事項

4

1.7

Python に関する詳しい情報. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Python の基礎

45

スクリプトの実行 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5

2.1.1

プログラム中に記述するコメント . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6

2.1.2

プログラムのインデント. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7

2.2

文を分割して／連結して記述する方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7

2.3

変数とデータの型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

8

2.3.1

日本語の変数名の使用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

2.3.2

変数名に関する注意 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

2.3.3

イコール「=」の連鎖（Multiple Assignment） . . . . . . . . . . . . . . . . . . . . . . . . .

10

2.3.4

変数の解放（廃棄） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

2.3.5

変数が値を保持する仕組みの概観 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10

2.1

2.3.5.1
2.3.6

識別値に関する注意事項. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

数値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.6.1

整数：

int 型

2.3.6.2

巨大な整数値を扱う際の注意 . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.6.3

浮動小数点数：

2.3.6.4

アンダースコア「 」を含む数値リテラルの記述

2.3.6.5

基数の指定： 2 進数，8 進数，16 進数

2.3.6.6

複素数：

2.3.6.7

最大値，最小値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.6.8

浮動小数点数の誤差と丸め2.3.6.9

数学関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

12. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
13ﬂoat 型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

complex 型

2.3.6.10 特殊な値：inf, nan. . . . . . . . . . . . . . . . . . . 15

. . . . . . . . . . . . . . . . . . . . . . . . 15

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
16

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1717

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

2.3.6.11 多倍長精度の浮動小数点数の扱い . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.3.7

2.3.6.12 分数の扱い. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.3.6.13 乱数の生成. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

文字列 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

2.3.7.1

エスケープシーケンス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

2.3.7.2

raw 文字列（raw string） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

2.3.7.3

複数行に渡る文字列 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.7.4

文字列の長さ（文字数）

2.3.7.5

文字列リテラルの連接 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

I

31

2.3.7.6

文字列の分解と合成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

2.3.7.7

文字列の置換 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

2.3.7.8

文字の置換

2.3.7.9

英字，数字の判定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
34

2.3.7.10 大文字／小文字の変換と判定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.3.7.11 文字列の含有検査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.3.7.12 文字列の検索 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.3.7.13 両端の文字の除去 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.3.7.14 文字コード，文字の種別に関すること . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.3.8

真理値（bool 型） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3.9

ヌルオブジェクト：2.3.10 型の変換

39

None . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

2.3.10.1 各種の値の文字列への変換（str，repr） . . . . . . . . . . . . . . . . . . . . . . . 40
2.3.11 型の検査

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

2.3.11.1 ﬂoat の値が整数値かどうかを検査する方法 . . . . . . . . . . . . . . . . . . . . . . 42
2.3.12 基数の変換 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.3.12.1 n 進数→ 10 進数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.3.12.2 10 進数→ n 進数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.3.13 ビット演算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.3.13.1 ビット演算の累算代入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.3.13.2 整数値のビット長を求める方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.3.14 バイト列
2.4

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

データ構造 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

リスト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

2.4.1.1

空リスト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

2.4.1.2

リストの要素へのアクセス

2.4.1.3

リストの編集 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4.1.4

リストによるスタック，キューの実現：

2.4.1.5

リストに対する検査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

50

2.4.1.6

例外処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

51

2.4.1.7

要素の個数のカウント . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

51

2.4.1.8

要素の合計：

2.4.1.9

要素の整列 (1)：sort メソッド . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

2.4.1.10 要素の整列 (2)：sorted 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

2.4.1

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
47

pop メソッド . . . . . . . . . . . . . . . 49

sum 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

2.4.1.11 要素の順序の反転 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.4.1.12 リストの複製 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.4.1.13 リストか否かの判定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.4.1.14 リストの内部に他のリストを展開する方法 . . . . . . . . . . . . . . . . . . . . . . 56
2.4.2

2.4.3

タプル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

2.4.2.1

リストとタプルの違い . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

2.4.2.2

括弧の表記が省略できるケース . . . . . . . . . . . . . . . . . . . . . . . . . . . .

57

2.4.2.3

特殊なタプル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

57

2.4.2.4

タプルの要素を整列（ソート）する方法

2.4.2.5

タプルか否かの判定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

58

セット . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

58

2.4.3.1

セットの要素となるオブジェクト . . . . . . . . . . . . . . . . . . . . . . . . . . .

58

2.4.3.2

セットの生成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59

2.4.3.3

セットに対する各種の操作. . . . . . . . . . . . . . . . . . . . . . . 57

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
II

2.4.42.4.3.4

集合論の操作 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

61

2.4.3.5

セットか否かの判定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62

2.4.3.6

frozenset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

辞書型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62

2.4.4.1

空の辞書の作成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

2.4.4.2

エントリの削除 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

2.4.4.3

get メソッドによる辞書へのアクセス . . . . . . . . . . . . . . . . . . . . . . . . . 63

2.4.4.4

辞書に対する pop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4.4.5

辞書の更新. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

2.4.4.6

辞書の結合. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

2.4.4.7

辞書を他の辞書の内部に展開する方法 . . . . . . . . . . . . . . . . . . . . . . . . .

65

2.4.4.8

キーや値の列を取り出す方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

66

2.4.4.9

エントリの数を調べる方法

64. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

2.4.4.10 リストやタプルから辞書を生成する方法. . . . . . . . . . . . . . . . . . . . . . . 66

2.4.4.11 辞書の全エントリを列として取り出す方法 . . . . . . . . . . . . . . . . . . . . . . 67
2.4.4.12 辞書の複製. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

2.4.4.13 エントリの順序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.4.4.14 辞書の整列. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

2.4.4.15 辞書の同値性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.4.4.16 辞書か否かの判定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.4.5

添字（スライス）の高度な応用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

2.4.5.1

添字の値の省略 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

2.4.5.2

スライスオブジェクト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

69

2.4.5.3

逆順の要素指定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

70

2.4.5.4

不連続な部分の取り出し. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

2.4.6

データ構造の変換 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.4.7

データ構造の要素を他のデータ構造の中に展開する方法 . . . . . . . . . . . . . . . . . . . . 71

2.4.8

データ構造に沿った値の割当て（分割代入） . . . . . . . . . . . . . . . . . . . . . . . . . .

72

2.4.8.1

応用例： 変数の値の交換 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

2.4.8.2

データ構造の選択的な部分抽出 . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

データ構造のシャッフル，ランダムサンプリング . . . . . . . . . . . . . . . . . . . . . . . .

73

2.4.9

70

2.4.10 データ構造へのアクセスの速度について . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.5制御構造 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.5.1

繰り返し (1)：75

for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

2.5.1.1

イテラブルなオブジェクト

2.5.1.2「スイート」の概念 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

75

2.5.1.3

スイートが 1 行の場合の書き方 . . . . . . . . . . . . . . . . . . . . . . . . . . . .

76

2.5.1.4

range 関数，range オブジェクト

2.5.1.5

辞書の for 文への応用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.5.1.6

for 文における else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

2.5.1.7

for を使ったデータ構造の生成（要素の内包表記） . . . . . . . . . . . . . . . . . . 78

2.5.1.8

イテレータ

2.5.1.9

分割代入を用いた for 文 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

. . . . . . . . . . . . . . . . . . . . . . . . . . . 76
77

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
80

2.5.1.10 zip 関数と zip オブジェクト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
2.5.1.11 enumerate によるインデックス情報の付与 . . . . . . . . . . . . . . . . . . . . . . 82
2.5.2

繰り返し (2)：2.5.3

繰り返しの中断とスキップ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.5.4

条件分岐

while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
83

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
III

2.6

入出力

2.6.1

2.6.2

2.6.3

2.5.4.1

条件式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

84

2.5.4.2

比較演算子の連鎖 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

85

2.5.4.3

各種の「空」値に関する条件判定 . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

2.5.4.4

is 演算子による比較 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

2.5.4.5値の型の判定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

88. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
標準出力

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

2.6.1.1

出力データの書式設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6.1.2

sys モジュールによる標準出力の扱い . . . . . . . . . . . . . . . . . . . . . . . . . 92

標準入力

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

2.6.2.1

input 関数による入力の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

2.6.2.2

sys モジュールによる標準入力の扱い . . . . . . . . . . . . . . . . . . . . . . . . . 94

ファイルからの入力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

89

94

2.6.3.1

ファイル，ディレクトリのパスについて

2.6.3.2

扱うファイルのエンコーディング，改行コードの指定 . . . . . . . . . . . . . . . . . 96

2.6.3.3

テキストファイルとバイナリファイルについて . . . . . . . . . . . . . . . . . . . . 98

2.6.3.4

バイト列の扱い . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6.3.5

バイト列のコード体系を調べる方法 . . . . . . . . . . . . . . . . . . . . . . . . . . 100

2.6.3.6

指定したバイト数だけ読み込む方法 . . . . . . . . . . . . . . . . . . . . . . . . . . 100

2.6.3.7

ファイルの内容を一度で読み込む方法 . . . . . . . . . . . . . . . . . . . . . . . . . 100

2.6.3.8

ファイルをイテラブルとして読み込む方法 . . . . . . . . . . . . . . . . . . . . . . 101

2.6.3.9

readlines メソッドによるテキストファイルの読み込み . . . . . . . . . . . . . . . . 101. . . . . . . . . . . . . . . . . . . . . . . 95

98

2.6.3.10 データを読み込む際のファイル中の位置について . . . . . . . . . . . . . . . . . . . 102
2.6.4

ファイルへの出力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102

2.6.4.1

print 関数によるファイルへの出力 . . . . . . . . . . . . . . . . . . . . . . . . . . 102

2.6.4.2

writelines メソッドによる出力

2.6.4.3

出力バッファの書き出し. . . . . . . . . . . . . . . . . . . . . . . . . . . . 103. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

2.6.5

標準エラー出力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

2.6.6

標準入出力でバイナリデータを扱う方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105

2.6.7

パス（ファイル，ディレクトリ）の扱い：その１ - os モジュール

2.6.8. . . . . . . . . . . . . . . 105

2.6.7.1

カレントディレクトリに関する操作 . . . . . . . . . . . . . . . . . . . . . . . . . . 105

2.6.7.2

ホームディレクトリの取得

2.6.7.3

ディレクトリ内容の一覧 (1) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

2.6.7.4

ディレクトリ内容の一覧 (2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

2.6.7.5

ファイルのサイズの取得

2.6.7.6

ファイル，ディレクトリの検査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

2.6.7.7

ファイル，ディレクトリの削除 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

2.6.7.8

実行中のスクリプトに関する情報 . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

2.6.7.9

パスの表現に関すること. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

パス（ファイル，ディレクトリ）の扱い：その２ - pathlib モジュール . . . . . . . . . . . . . 109

2.6.8.1

パスオブジェクトの生成

2.6.8.2

カレントディレクトリ，ホームディレクトリの取得 . . . . . . . . . . . . . . . . . . 109

2.6.8.3

パスの存在の検査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

2.6.8.4

ファイル，ディレクトリの検査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

2.6.8.5

ディレクトリの要素を取得する . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

2.6.8.6

ディレクトリ名，ファイル名，拡張子の取り出し . . . . . . . . . . . . . . . . . . . 110

2.6.8.7

パスの連結

2.6.8.8

ファイルシステム毎のパスの表現 . . . . . . . . . . . . . . . . . . . . . . . . . . . 111. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

IV2.6.8.9

URI への変換 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

2.6.8.10 ファイルのオープン . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
2.6.8.11 ファイル入出力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
2.6.8.12 ディレクトリの作成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
2.6.8.13 ファイル，ディレクトリの削除 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
2.6.9

コマンド引数の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

2.6.10 入出力処理の際に注意すること . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
2.6.11 CSV ファイルの取り扱い： csv モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

2.7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

2.6.11.2 CSV ファイルの入力. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117関数の定義 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

2.7.1

引数について . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

2.7.1.1

引数に暗黙値を設定する方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123

2.7.1.2

仮引数のシンボルを明に指定する関数呼び出し（キーワード引数） . . . . . . . . . . 123

2.7.1.3

引数の個数が不定の関数

2.7.1.4

実引数に ‘*’ を記述する方法

2.7.1.5

キーワード引数を辞書として受け取る方法 . . . . . . . . . . . . . . . . . . . . . . 124

2.7.1.6

実引数に ‘**’ を記述する方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

2.7.1.7

引数に与えたオブジェクトに対する変更の影響 . . . . . . . . . . . . . . . . . . . . 125

2.7.1.8

引数に関するその他の事柄. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

2.7.2

変数のスコープ（関数定義の内外での変数の扱いの違い） . . . . . . . . . . . . . . . . . . . 128

2.7.3

関数の再帰的定義 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

2.7.4

2.7.5
2.8

2.6.11.1 CSV ファイルの出力

2.7.3.1

再帰的呼び出しの回数の上限 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

2.7.3.2

再帰的呼び出しを応用する際の注意 . . . . . . . . . . . . . . . . . . . . . . . . . . 131

内部関数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

2.7.4.1

内部関数におけるローカル変数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

2.7.4.2

内部関数はいつ作成されるのか . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

2.7.4.3

内部関数の応用：クロージャ，エンクロージャ . . . . . . . . . . . . . . . . . . . . 133

定義した関数の削除 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

オブジェクト指向プログラミング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

2.8.1

クラスの定義 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

2.8.1.1

コンストラクタとファイナライザ . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

2.8.1.2

インスタンス変数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

2.8.1.3

メソッドの定義 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

2.8.1.4

クラス変数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

2.8.2

クラス，インスタンス間での属性の関係 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

2.8.3

setattr，getattr による属性へのアクセス . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

2.8.4

組み込みの演算子や関数との連携 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

2.8.4.1

各種クラスのコンストラクタに対するフック . . . . . . . . . . . . . . . . . . . . . 144

2.8.4.2

算術演算子，比較演算子，各種関数に対するフック . . . . . . . . . . . . . . . . . . 145

2.8.4.3

累算代入演算子に対するフック . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

2.8.5

コンテナのクラスを実装する方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

2.8.6

イテレータのクラスを実装する方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

2.8.7

カプセル化

2.8.8

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

2.8.7.1

変数の隠蔽

2.8.7.2

アクセサ（ゲッタ，セッタ）. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

オブジェクト指向プログラミングに関するその他の事柄 . . . . . . . . . . . . . . . . . . . . 152

2.8.8.1

クラス変数，インスタンス変数の調査 . . . . . . . . . . . . . . . . . . . . . . . . . 152

V

2.9

2.8.8.2

クラスの継承関係の調査

2.8.8.3

インスタンスのクラスの調査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153

2.8.8.4

属性の調査（プロパティの調査） . . . . . . . . . . . . . . . . . . . . . . . . . . . 153

2.8.8.5

多重継承におけるメソッドの優先順位 . . . . . . . . . . . . . . . . . . . . . . . . . 153

2.8.8.6

静的メソッド（スタティックメソッド） . . . . . . . . . . . . . . . . . . . . . . . . 155

データ構造に則したプログラミング

2.9.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

map 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
2.9.1.1

複数の引数を取る関数の map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

2.9.1.2

map 関数に zip オブジェクトを与える方法 . . . . . . . . . . . . . . . . . . . . . . 158

2.9.2

lambda と関数定義 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159

2.9.3

ﬁlter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

2.9.4

3 項演算子としての if〜else… . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161

2.9.5

all, any による一括判定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161

2.9.6

高階関数モジュール：functools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

2.9.6.1
2.10 代入式

reduce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

2.11 構造的パターンマッチング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
2.11.1 構造的なパターン . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
2.11.2 条件付きのパターンマッチング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
2.11.3 クラスのインスタンスに対するパターンマッチング . . . . . . . . . . . . . . . . . . . . . . . 167
3

Kivy による GUI アプリケーションの構築
3.1

3.2

Kivy の基本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
3.1.1

アプリケーションプログラムの実装 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

3.1.2

GUI 構築の考え方 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
3.1.2.1

Widget（ウィジェット） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

3.1.2.2

Layout（レイアウト）

3.1.2.3

Screen（スクリーン） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

3.1.3

ウィンドウの扱い . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

3.1.4

マルチタッチの無効化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

基本的な GUI アプリケーション構築の方法

3.2.1

イベント処理（導入編）

3.2.1.1

3.3

169. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

イベントハンドリング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174

3.2.2

アプリケーション構築の例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175

3.2.3

イベント処理（コールバックの登録による方法） . . . . . . . . . . . . . . . . . . . . . . . . 178

3.2.4

ウィジェットの登録と削除 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179

3.2.5

アプリケーションの開始と終了のハンドリング . . . . . . . . . . . . . . . . . . . . . . . . . 180

各種ウィジェットの使い方

3.3.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180

ラベル：Label . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181

3.3.1.1

リソースへのフォントの登録 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182

3.3.2

ボタン：Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183

3.3.3

テキスト入力：TextInput . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183

3.3.4

チェックボックス：CheckBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

3.3.5

進捗バー：ProgressBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

3.3.6

スライダ：Slider

3.3.7

スイッチ：Switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

3.3.8

トグルボタン：ToggleButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

3.3.9

画像：Image. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

VI

3.3.9.1
3.4

Canvas グラフィックス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
3.4.1

3.4.2

3.4.3

3.5

Graphics クラス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
3.4.1.1

Color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187

3.4.1.2

Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187

3.4.1.3

Rectangle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187

3.4.1.4

Ellipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

サンプルプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

3.4.2.1

正弦関数のプロット . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

3.4.2.2

各種図形，画像の表示 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

フレームバッファへの描画 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190

3.4.3.1

ピクセル値の取り出し . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

3.4.3.2

イベントから得られる座標位置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

スクロールビュー（ScrollView） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192

3.5.1

ウィジェットのサイズ設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193

3.5.2

マウスのドラッグによるスクロール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193

3.6ウィンドウサイズを固定（リサイズを禁止）する設定 . . . . . . . . . . . . . . . . . . . . . . . . . 193

3.7

Kivy 言語による UI の構築 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
3.7.1

3.8
3.9

Kivy 言語の基礎 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
3.7.1.1

サンプルプログラムを用いた説明 . . . . . . . . . . . . . . . . . . . . . . . . . . . 194

3.7.1.2

Python プログラムと Kv ファイルの対応 . . . . . . . . . . . . . . . . . . . . . . . 196

時間によるイベント . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

3.8.1

時間イベントのスケジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

GUI 構築の形式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
3.9.1

4

サンプルプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

スクリーンの扱い：

Screen と ScreenManager . . . . . . . . . . . . . . . . . . . . . . . . 197

3.9.1.1

ScreenManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

3.9.1.2

Screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198

3.9.2

アクションバー：

3.9.3

タブパネル：

TabbedPanel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201

3.9.4

スワイプ：

Carousel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202

ActionBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199

実用的なアプリケーション開発に必要な事柄

4.1

日付と時間に関する処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204

4.1.1

4.1.2

4.1.3
4.2

204

日付と時刻の取り扱い： datetime モジュール . . . . . . . . . . . . . . . . . . . . . . . . . 204

4.1.1.1

datetime オブジェクトの分解と合成

4.1.1.2

文字列を datetime オブジェクトに変換する方法

4.1.1.3

datetime オブジェクトの差：

4.1.1.4

日付，時刻の書式整形 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206

4.1.1.5

datetime のプロパティ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206

4.1.1.6

タイムゾーンについて . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207. . . . . . . . . . . . . . . . . . . . . . . . . 204. . . . . . . . . . . . . . . . . . . 205

timedelta . . . . . . . . . . . . . . . . . . . . . . . 205

time モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
4.1.2.1

基本的な機能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

4.1.2.2

日付，時刻を表す文字列表現 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

4.1.2.3

応用例：datetime オブジェクトとの間の変換 . . . . . . . . . . . . . . . . . . . . . 212

4.1.2.4

時間の計測

4.1.2.5

プログラムの実行待ち . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

timeit モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

ロケール（locale） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217

VII

4.3

4.2.1

ロケール設定の確認 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217

4.2.2

使用できるロケールの調査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218

4.2.3

その他 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

4.3.2

4.3.3

4.2.3.2

通貨の書式整形 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

パターンの検索 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220

4.3.1.1

正規表現を用いた検索 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222

4.3.1.2

検索パターンの和結合 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

4.3.1.3

正規表現を用いたパターンマッチ . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

4.3.1.4

行頭や行末でのパターンマッチ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225

置換処理：

re.sub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226

4.3.2.1

複数行に渡る置換処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226

4.3.2.2

パターンマッチのグループを参照した置換処理 . . . . . . . . . . . . . . . . . . . . 227

文字列の分解への応用：

re.split . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227

マルチスレッドとマルチプロセス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

4.4.1

4.4.2

4.4.3

4.4.4
4.5

現在のエンコーディングの調査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

文字列検索と正規表現

4.3.1

4.4

4.2.3.1

マルチスレッド . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

4.4.1.1

スレッドの実行状態の確認

4.4.1.2

実行中のスレッドのリストを取得する方法 . . . . . . . . . . . . . . . . . . . . . . 230

4.4.1.3

スレッド間の排他制御 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229

マルチプロセス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233

4.4.2.1

プロセスごとに実行されるモジュール . . . . . . . . . . . . . . . . . . . . . . . . . 234

4.4.2.2

プロセスの実行状態の確認

4.4.2.3

実行中プロセスのリストを取得する方法

4.4.2.4

プロセスの強制終了 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235

4.4.2.5

共有メモリと排他制御 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234. . . . . . . . . . . . . . . . . . . . . . . 235

concurrent.futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
4.4.3.1

ProcessPoolExecutor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243

4.4.3.2

プロセスの実行状態と戻り値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243

4.4.3.3

同時に実行されるプロセスの個数について . . . . . . . . . . . . . . . . . . . . . . 245

4.4.3.4

プロセス終了の同期 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245

マルチスレッドとマルチプロセスの実行時間の比較 . . . . . . . . . . . . . . . . . . . . . . . 246

非同期処理： asyncio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248

4.5.1

コルーチン

4.5.2

コルーチンとタスクの違い . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

4.5.2.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248

複数のタスクの並行実行. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

4.5.3

await によるタスクの一時停止と切替え . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249

4.5.4

タスク登録の簡便な方法

4.5.5

イベントループと run 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251

4.5.6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250

4.5.5.1

スレッド毎に実行されるイベントループ

4.5.5.2

実行中のイベントループを調べる方法 . . . . . . . . . . . . . . . . . . . . . . . . . 252. . . . . . . . . . . . . . . . . . . . . . . 251

理解を深めるためのサンプル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252

4.5.6.1

非同期処理とイベントループの概観 . . . . . . . . . . . . . . . . . . . . . . . . . . 253

4.5.7

スレッドを非同期処理で管理する方法

4.5.8

非同期のコンソール入力を実現するためのライブラリ：aioconsole . . . . . . . . . . . . . . . 256

4.5.9

永続するイベントループ上でのタスク管理 . . . . . . . . . . . . . . . . . . . . . . . . . . . 257. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254

4.5.9.1

永続するイベントループ

4.5.9.2

タスクの一覧取得とタスクのキャンセル. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257

VIII. . . . . . . . . . . . . . . . . . . . . . . 258

4.5.10 非同期のイテレーション. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260

4.5.10.1 非同期のイテラブル . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
4.5.11 非同期のファイル入出力：aioﬁles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
4.5.11.1 サンプルプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
4.6

処理のスケジューリング . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

4.6.1

4.6.2

4.7

4.8

sched モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
4.6.1.1

基本的な使用方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

4.6.1.2

イベントを独立したスレッドで実行する方法 . . . . . . . . . . . . . . . . . . . . . 265

4.6.1.3

イベントの管理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267

schedule モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
4.6.2.1

一定の時間間隔で処理を起動する方法 . . . . . . . . . . . . . . . . . . . . . . . . . 268

4.6.2.2

指定した時刻に処理を起動する方法 . . . . . . . . . . . . . . . . . . . . . . . . . . 269

ジェネレータ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270

4.7.1

ジェネレータ関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270

4.7.2

ジェネレータ式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271

4.7.3

ジェネレータの入れ子 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271

モジュール，パッケージの作成による分割プログラミング . . . . . . . . . . . . . . . . . . . . . . . 272

4.8.1

モジュール

4.8.1.1
4.8.2

単体のソースファイルとしてのモジュール . . . . . . . . . . . . . . . . . . . . . . 272

パッケージ（ディレクトリとして構成するライブラリ） . . . . . . . . . . . . . . . . . . . . 273

4.8.2.1

4.9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272

モジュールの実行 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274

4.8.3

モジュールが配置されているディレクトリの調査 . . . . . . . . . . . . . . . . . . . . . . . . 274

4.8.4

init .py について . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275

ファイル内でのランダムアクセス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277

4.9.1

ファイルのアクセス位置の指定（ファイルのシーク）

4.9.2

サンプルプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277. . . . . . . . . . . . . . . . . . . . . 277

4.10 オブジェクトの保存と読込み： pickle モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
4.11 バイナリデータの作成と展開： struct モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
4.11.1 バイナリデータの作成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
4.11.2 バイナリデータの展開 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
4.11.3 バイトオーダーについて. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282

4.12 バイナリデータをテキストに変換する方法： base64 モジュール . . . . . . . . . . . . . . . . . . . . 284
4.12.1 バイト列→ Base64 データ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
4.12.2 Base64 データ→バイト列 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
4.12.3 サンプルプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
4.13 編集可能なバイト列：bytearray. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285

4.13.1 bytearray の作成方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
4.13.2 他の型への変換 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
4.13.3 ファイルへの出力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
4.14 exec と eval . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
4.14.1 名前空間の指定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
4.14.2 eval 関数. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287

4.15 collections モジュール. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288

4.15.1 キュー： deque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
4.15.1.1 要素の追加と取り出し： append，pop . . . . . . . . . . . . . . . . . . . . . . . . 288
4.15.1.2 要素の順序の回転： rotate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
4.15.2 要素の集計： Counter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
4.15.2.1 出現頻度の順に集計結果を取り出す . . . . . . . . . . . . . . . . . . . . . . . . . . 289
IX4.15.3 namedtuple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
4.16 itertools モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
4.16.1 イテラブルの連結： chain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
4.16.2 無限のカウンタ： count . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
4.16.3 イテラブルの繰り返し： cycle. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292

4.16.4 オブジェクトの繰り返し： repeat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
4.16.5 連続要素のグループ化： groupby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
4.16.6 直積集合： product . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
4.16.7 組合せ： combinations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
4.16.8 順列： permutations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
4.17 列挙型：

enum モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295

4.17.1 Enum 型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
4.17.2 定数の取り扱いを実現する方法の例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
4.17.3 IntEnum. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297

4.17.4 auto 関数による Enum 要素への値の割り当て. . . . . . . . . . . . . . . . . . . . . . . . . 297

4.17.4.1 非数値要素への auto 関数による値の割り当て（参考事項） . . . . . . . . . . . . . . 298
4.18 例外（エラー）の処理. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299

4.18.1 エラーメッセージをデータとして取得する方法：

traceback モジュール . . . . . . . . . . . 299

4.18.2 例外を発生させる方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
4.18.3 例外オブジェクト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
4.18.3.1 例外オブジェクトのクラス階層 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
4.19 使用されているシンボルの調査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
4.20 with 構文 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
4.21 デコレータ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
4.21.1 引数を取るデコレータ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
4.22 データ構造の整形表示：

pprint モジュール. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309

4.23 処理環境に関する情報の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
4.23.1 Python のバージョン情報の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
4.23.2 platform モジュールの利用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
4.23.3 実行中のプログラムの PID の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
4.23.4 環境変数の参照 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
4.24 ファイル，ディレクトリに対する操作： shutil モジュール . . . . . . . . . . . . . . . . . . . . . . . 313
4.24.1 ファイルの複製 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
4.24.2 ディレクトリ階層の複製. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313

4.24.3 書庫ファイル（アーカイブ）の取り扱いと圧縮処理に関すること . . . . . . . . . . . . . . . . 313
4.24.3.1 書庫（アーカイブ）の作成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
4.24.3.2 書庫（アーカイブ）の展開 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
4.25 ZIP 書庫の扱い： zipﬁle モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
4.25.1 ZIP 書庫ファイルを開く. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314

4.25.2 書庫へのメンバの追加 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
4.25.3 書庫の内容の確認 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
4.25.4 書庫のメンバの読み込み. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315

4.25.5 書庫の展開 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
4.25.5.1 パスワードで保護された ZIP 書庫へのアクセス . . . . . . . . . . . . . . . . . . . . 316
4.26 コマンド引数の扱い：

argparse モジュール. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317

4.26.1 コマンド引数の形式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
4.26.2 使用方法

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317

4.26.2.1 オプション引数の設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
X4.26.2.2 位置引数の設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
4.26.2.3 コマンドラインの解析処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
4.26.3 サンプルプログラムに沿った説明 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
4.26.3.1 ヘルプ機能. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319

4.26.3.2 コマンド引数の型の指定
4.26.4 サブコマンドの実現方法. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320

4.27 スクリプトの終了（プログラムの終了） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
4.27.1 sys.exit 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
4.27.2 os. exit 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
4.27.3 スクリプト終了時に実行する処理： atexit モジュール . . . . . . . . . . . . . . . . . . . . . 322
4.28 Python の型システム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
4.28.1 型の階層（クラス階層）. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323

4.28.1.1 スーパークラス，サブクラスを調べる方法 . . . . . . . . . . . . . . . . . . . . . . 324
5TCP/IP による通信
5.1

5.2

socket モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
5.1.1

ソケットの用意 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326

5.1.2

サーバ側プログラムの処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326

5.1.3

クライアント側プログラムの処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327

5.1.4

送信と受信

5.1.5

サンプルプログラム：最も基本的な通信 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327

5.1.6

実用的な通信機能を実現する方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329

5.2.2

5.1.6.1

socket ライブラリと asyncio ライブラリの併用 . . . . . . . . . . . . . . . . . . . . 329

5.1.6.2

asyncio ライブラリのみで通信を実現する方法

5.1.6.3

通信の処理において注意すべき例外 . . . . . . . . . . . . . . . . . . . . . . . . . . 334

5.2.1.1

リクエストの送信に関するメソッド . . . . . . . . . . . . . . . . . . . . . . . . . . 335

5.2.1.2

取得したコンテンツに関するメソッド . . . . . . . . . . . . . . . . . . . . . . . . . 335

5.2.1.3

Session オブジェクトに基づくアクセス . . . . . . . . . . . . . . . . . . . . . . . . 336

Beautiful Soup ライブラリ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
BS における HTML コンテンツの扱い . . . . . . . . . . . . . . . . . . . . . . . . 337

外部プログラムとの連携

6.1. . . . . . . . . . . . . . . . . . . . 331

requests ライブラリ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335

5.2.2.1339

外部プログラムを起動する方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339

6.1.1

標準入出力の接続 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339

6.1.1.1

7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327

WWW コンテンツ解析 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
5.2.1

6

326

外部プログラムの標準入力のクローズ . . . . . . . . . . . . . . . . . . . . . . . . . 342

6.1.2

非同期の入出力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342

6.1.3

外部プロセスとの同期（終了の待機）

6.1.4

外部プログラムを起動する更に簡単な方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . 344. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344

サウンドの入出力346

7.1

基礎知識 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346

7.2

WAV 形式ファイルの入出力：wave モジュール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
7.2.1

WAV 形式ファイルのオープンとクローズ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
7.2.1.1

WAV 形式データの各種属性について . . . . . . . . . . . . . . . . . . . . . . . . . 347

7.2.2

WAV 形式ファイルからの読込み . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347

7.2.3

サンプルプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347

7.2.4

量子化ビット数とサンプリング値の関係 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348

XI

7.3

7.2.5

読み込んだフレームデータの扱い . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348

7.2.6

WAV 形式データを出力する例 (1)：リストから WAV ファイルへ

7.2.7

WAV 形式データを出力する例 (2)：NumPy の配列から WAV ファイルへ . . . . . . . . . . . 351

7.2.8

サウンドのデータサイズに関する注意点 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351. . . . . . . . . . . . . . . 350

サウンドの入力と再生：PyAudio ライブラリ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353

7.3.1

ストリームを介したサウンド入出力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353

7.3.2

WAV 形式サウンドファイルの再生 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
7.3.2.1

7.3.3

サウンド再生の終了の検出. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356

音声入力デバイスからの入力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356

A Python に関する情報

359

A.1 Python のインターネットサイト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
A.2 Python のインストール作業の例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
A.2.1 PSF 版インストールパッケージによる方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
A.2.2 Anaconda による方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360
A.3 Python 起動のしくみ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
A.3.1 PSF 版 Python の起動. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361

A.3.2 Anaconda Navigator の起動 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
A.3.3 Anaconda Prompt の起動 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
A.3.3.1

conda コマンドによる Python 環境の管理 . . . . . . . . . . . . . . . . . . . . . . . 363

A.4 PIP によるライブラリ管理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363
A.4.1 PIP コマンドが実行できない場合の解決策 . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
B Kivy に関する情報

365

B.1 Kivy 利用時のトラブルを回避するための情報 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
B.1.1 Kivy が使用する描画 API の設定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
B.1.2 SDL について . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
B.2 GUI デザインツール . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
C Tkinter：基本的な GUI ツールキット

366

C.1 基本的な扱い方 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
C.1.1 使用例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
C.1.1.1

ウィンドウサイズ変更の可否の設定 . . . . . . . . . . . . . . . . . . . . . . . . . . 368

C.1.2 ウィジェットの配置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
C.2 各種のウィジェット . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
C.2.1 チェックボタンとラジオボタン . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370
C.2.1.1

Variable クラス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370

C.2.2 エントリ（テキストボックス）とコンボボックス . . . . . . . . . . . . . . . . . . . . . . . . 372
C.2.2.1

プログラムの終了 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373

C.2.3 リストボックス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373
C.2.4 テキスト（文字編集領域）とスクロールバー . . . . . . . . . . . . . . . . . . . . . . . . . . 375
C.2.5 スケール（スライダ）とプログレスバー . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
C.2.5.1

Variable クラスのコールバック関数設定. . . . . . . . . . . . . . . . . . . . . . . 377

C.3 メニューの構築 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
C.4 Canvas の描画. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379

C.4.1 描画メソッド（一部） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
C.4.1.1

使用できるフォントを調べる方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . 380

C.4.2 図形の管理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
C.5 イベントハンドリング. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
XII

C.5.1 時間を指定した関数の実行 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
C.6 複数のウィンドウの表示 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
C.7 ディスプレイやウィンドウに関する情報の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
C.8 メッセージボックス（messagebox） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
C.8.1 アプリケーション終了のハンドリング. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390

C.9 ウィジェットの親，子を調べる方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
D curses392

D.1 curses 使用の流れ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
D.2 画面に対する出力，制御 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
D.2.1 色の設定と適用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
D.2.2 装飾の適用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
D.2.3 テキストカーソルの設定. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394

D.2.4 画面の消去，更新 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394
D.2.5 警告表現

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394

D.3 キーボード入力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
D.3.1 文字列の入力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
D.3.2 raw モード入力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
D.4 ウィンドウのリサイズ. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397

D.5 画面の内容の採取 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
D.5.1 文字コードや属性情報の採取 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
D.5.2 画面の中の文字列の採取. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400

E psutil ライブラリ

402

E.1 CPU 関連の情報の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
E.1.1 CPU の構成：cpu count 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
E.1.2 CPU のクロック周波数：cpu freq 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
E.1.3 CPU 時間：cpu times 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
E.1.4 CPU 使用率：cpu percent 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
E.2 メモリ関連の情報の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
E.2.1 仮想記憶の状況：virtual memory 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
E.2.2 スワップ領域の使用状況：swap memory 関数. . . . . . . . . . . . . . . . . . . . . . . . . 403

E.3 ディスク関連の情報の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
E.3.1 パーティションの構成：disk partitions 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . 404
E.3.2 ディスクの使用状況：disk usage 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
E.3.3 ディスクの I/O 状況：disk io counters 関数. . . . . . . . . . . . . . . . . . . . . . . . . . 405

E.4 ネットワーク関連の情報の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
E.4.1 ネットワークの I/O 状況：net io counters 関数 . . . . . . . . . . . . . . . . . . . . . . . . . 405
E.4.2 現在の通信状況：net connections 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
E.5 プロセス関連の情報の取得 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
E.5.1 実行中のプロセス：pids 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
E.5.2 Process クラス . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
E.5.2.1

メモリの使用状況の調査：memory info . . . . . . . . . . . . . . . . . . . . . . . . 408

E.5.2.2

CPU 使用率：cpu percent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409

E.5.2.3

CPU 時間：cpu times . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410

E.5.2.4

開いているファイルの調査：open ﬁles . . . . . . . . . . . . . . . . . . . . . . . . 410

E.5.2.5

プロセスの通信状況：net connections

E.5.2.6

プロセスの終了：terminate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411

XIII. . . . . . . . . . . . . . . . . . . . . . . . 410

E.5.3 サンプルプログラム：プロセスの監視F. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411

ライブラリの取り扱いについて

413

F.1 ライブラリの読込みに関すること . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
F.1.1 ライブラリ読込みにおける別名の付与. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413

F.1.2 接頭辞を省略するためのライブラリの読込み . . . . . . . . . . . . . . . . . . . . . . . . . . 413
F.1.2.1

接頭辞を省略する際の注意（名前の衝突） . . . . . . . . . . . . . . . . . . . . . . 414

F.1.3 ライブラリのパス：sys.path. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414

F.1.4 既に読み込まれているライブラリの調査：

sys.modules. . . . . . . . . . . . . . . . . . . 414

F.1.5 The Zen of Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
F.2 ライブラリ情報の取得. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415

F.2.1 pkg resources による方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
F.2.2 pkgutil，importlib による方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
F.3 各種ライブラリの紹介. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418

G 対話モードを使いやすくするための工夫

419

G.1 警告メッセージの抑止と表示 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
G.2 メモリの使用状態の管理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
G.2.1 オブジェクトのサイズの調査 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
H 文書化文字列と関数アノテーション

422

H.1 関数アノテーション（Function Annotations） . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
I

サンプルプログラム

I.1

リスト／セット／辞書のアクセス速度の比較 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424

I.1.1

スライスに整数のインデックスを与える形のアクセス

I.1.2

メンバシップ検査に要する時間 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425. . . . . . . . . . . . . . . . . . . . . 424

I.2

ライブラリ使用の有無における計算速度の比較 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428

I.3

os.walk 関数の応用例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431

I.4

pathlib の応用例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432

I.5

浮動小数点数と 2 進数の間の変換 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433

I.5.1
I.6
J

424

mpmath を用いた例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434

全ての Unicode 文字の列挙 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435

その他

436

J.1

演算子の優先順位 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436

J.2

アスキーコード表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437

XIV

はじめに

1

Python はオランダのプログラマであるグイド・ヴァンロッサム（Guido van Rossum）によって 1991 年に開発されたプログラミング言語であり，言語処理系は基本的にインタプリタである．Python は多目的の高水準言語であり，言語そのものの習得とアプリケーション開発に要する労力が比較的に少ないとされる．しかし，実用的なアプリケー
ションを開発するために必要とされる多くの機能が提供されており，この言語の有用性の評価が高まっている．

Python の言語処理系（インタプリタ）は多くのオペレーティングシステム（OS）に向けて用意されている．Python
で記述されたプログラムはインタプリタ上で実行されるために，C や Java と比べて実行の速度は遅いが，C 言語など
他の言語で開発されたプログラムとの連携が容易である．このため，Python に組み込んで使用するための各種の高速なプログラムがライブラリ（モジュール，パッケージ）の形で多数提供されており，それらを利用することができる．

Python 用のライブラリとして利用できるものは幅広く，言語そのものの習得や運用の簡便性と相俟って，情報工学や情報科学とは縁の遠い分野の利用者に対してもアプリケーション開発の敷居を下げている．
本書で前提とする Python の版は 3（3.6 以降）である．

1.1

Python でできること

Python は汎用のプログラミング言語である．また，世界中の開発コミュニティから多数のライブラリが提供されている．このため，Python が利用できる分野は広く，特に科学，工学系分野のためのライブラリが豊富である．それら
ライブラリを利用することで，情報処理技術を専門としない領域の利用者も手軽に独自の情報処理を実現することができる．特に次に挙げるような処理を実現する上で有用なライブラリが揃っている．

• 機械学習• ニューラルネットワーク• データサイエンス• GUI / Web アプリケーション開発

1.2

本書の内容

本書は Python でアプリケーションプログラムを開発するために必要な最小限の事柄について述べる．本書の読者としては，Python 以外の言語でプログラミングやスクリプティングの基本を学んだ人が望ましい．本書の内容を概略として列挙すると次のようなものとなる．

• Python 処理系の導入の方法
インタプリタとライブラリのインストール方法など• Python の言語としての基本事項
文法など• 実用的なアプリケーションを作成するために必要なこと
通信やマルチスレッド，マルチプロセスプログラミングに関すること特に重要なライブラリに関すること• GUI アプリケーションを作成するために必要なこと
GUI ライブラリの基本的な扱い方など• サウンドの基本的な扱い
WAV ファイルの入出力や音声のサンプリングと再生

1.3

本書の読み方

Python を初めて学ぶ方には，言語としての基礎的な内容について解説している章「1 はじめに」（この章）「2 Python の基礎」
を読むことをお勧めする．その後，実用的なプログラミングにおいて重要となる事柄に関して解説した章「4 実用的なアプリケーション開発に必要な事柄」

1

を読むことをお勧めする．その他の章については，学びの初期においては必ずしも必要とはならないこともあり，読者の事情に合わせて利用されたい．

1.4

処理系の導入（インストール）と起動の方法

Python の処理系（インタプリタ）は Python ソフトウェア財団（以後 PSF と略す）が開発，維持しており，当該財団の公式インターネットサイト https://www.python.org/ から入手することができる．Microsoft 社の Windows やApple 社の Mac 1 には専用のインストールパッケージが用意されており，それらを先のサイトからダウンロードしてインストールすることで Python 処理系が使用可能となる．Linux をはじめとする UNIX 系 OS においては，OS のパッケージ管理機能を介して Python をインストールできる場合が多いが，先のサイトから Python のソースコードを入手して処理系をビルドすることもできる．

1.4.1

Python 処理系のディストリビューション（配布形態）

Python 処理系は C 言語により記述されており，C 言語処理系によってビルドすることができるが，コンパイル済
みのインストールパッケージ（前述）を利用するのが便利である．インストールパッケージとしては PSF が配布するもの以外に Anaconda, Inc. 2 が配布する Anaconda が有名である．

PSF のインストールパッケージや Anaconda で Python 処理系を導入すると，各種のライブラリを管理するためのツールも同時に導入されるので，Python を中心としたソフトウェア開発環境を整えるための利便性が大きい．ただし注意すべき点として，PSF の管理ツールと Anaconda ではライブラリの管理方法や，Python 自体のバージョン管理の方法が異なるため，Python の処理環境を導入する際は，ディストリビューション（PSF か Anaconda か）を統一すべきである．
※ 巻末付録「A.2 Python のインストール作業の例」（p.359）でインストール方法を概略的に紹介している．
参考．Windows 環境で UNIX 系ツールを利用するための MSYS/MinGW があるが，MSYS/MinGW 環境下でもPython 処理系を利用することができる．ただし，本書では MSYS/MinGW については触れない．

本書では PSF のインストールパッケージによって Python を導入した処理環境を前提とするが，言語としてのPython の文法はディストリビューションに依らず共通であり，各種のライブラリも導入済みの状態であれば，使用方法は原則として同じである．

1.4.2

Python 処理系の起動

基本的に Python は OS のコマンドを投入することで起動する．Windows ではコマンドプロンプトウィンドウから

py コマンド（PSF 版 Python）を，Linux や Mac ではターミナルウィンドウから python コマンドを投入3 すること
で次の例のように Python インタプリタが起動する．
例．Windows のコマンドプロンプトから Python を起動する例
C:￥Users￥katsu> py

Enter← py コマンドの投入

Python 3.12.1 (tags/v3.12.1:2305ca5, Dec 7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>← Python プログラムの入力待ち

注 1）本書で例示する操作を Anaconda 環境下で実行するには，巻末付録「A.3.3 Anaconda Prompt の起動」
（p.361）に示す方法で Python 処理系を起動する．
注 2）本書では JupyterLab や IPython，Google Colaboratory 4 といった対話環境については言及しない．
JupyterLab の基本的な使用方法に関しては別冊の「Python3 ライブラリブック」で解説しているのでそちらを参照のこと．
1 Apple 社の Macintosh 用の OS の呼称は「Mac OS X」,「OS X」,「macOS」と変化している．本書ではこの内「OS X」,「macOS」

を暗に前提としている．
2 https://www.anaconda.com/
3 Apple 社 の Mac では Python 2.7 が基本的にインストールされている場合があり，python コマンドを投入するとこの版（2.7）が起動することがある．本書で前提とする Python3 をインストールして起動する場合は python3 コマンドを投入すると良い．ただし，詳細に関しては利用する環境の導入状態を調べること．Anaconda 環境では Anaconda Prompt 下で python コマンドを発行する．
4 Google 社が提供するオンラインの Python 実行環境．

2

1.4.3

対話モード

先の例の最後の行で「>>>」と表示されているが，これは Python のプロンプトであり，これに続いて Python の文や式を入力することができる．この状態を Python の対話モードと呼ぶ．処理系を終了するには exit() と入力する．
例．Python の終了
Enter>>> exit()

C:￥Users￥katsu>← Python 終了← Windows のコマンドプロンプトに戻る

この他にも，quit() の実行，あるいは Ctrl + Z などの終了方法がある．
対話モードでは，入力された Python の文や式が逐一実行されて結果が表示される．そして再度プロンプト「>>>」が表示されて，次の入力を受け付ける．また，キーボードのカーソルキー ↑ ， ↓ ， ← ， → で入力途中の行の編集ができるだけでなく，入力のヒストリを呼び出すこともできる．

1.4.3.1

ヒストリ

Python 処理系の対話モードでは，入力した文や式が記録されており，再度呼び出して使用することができる．例えば次のように print 関数を入力する場合を考える．
例．print 関数を 3 回実行する>>> print(’1 番目の入力’)
1 番目の入力Enter>>> print(’2 番目の入力’)
2 番目の入力Enter>>> print(’3 番目の入力’)
3 番目の入力

Enter←次の入力を促すプロンプト>>>

この例では 3 つの print 関数を入力しているが，それらはヒストリに記録されており，次の例のようにキーボードのカーソルキー ↑ を押すことで再度呼び出すことができる．
例．実行済みの行を再度呼び出す（先の例の続き）>>> ↑プロンプトに対して上矢印のカーソルキーを押すと↓↓↓↓>>> print(’3 番目の入力’)

直前の入力が再度表示される

このように ↑ ， ↓ で以前に入力されたものを呼び出すことができる．
テキストファイルに書き並べた Python の文や式をスクリプトとしてまとめて実行することもできるが，この方法については「2.1 スクリプトの実行」（p.5）で説明する．
異なる複数のバージョンの Python 処理系を導入し，それらを選択して起動することもできる．これに関しては「A.3

Python 起動のしくみ」（p.361）で解説する．
1.4.3.2

直前の値（次の例参照）
値を返す式を対話モードで評価（実行）した場合，その値はアンダースコア「 」に保持される．
例．評価結果の値の保持>>> 2 + 3
5
>>>
5

Enter

Enter

←足し算の式を評価（足し算の実行）←評価結果（計算結果）←上の値を保持する「 」を確認
←値が保持されている

この場合のアンダースコア「 」は変数5 であり，別の式の中で参照することができる．

5 「変数」については後の「2.3 変数とデータの型」（p.8）で解説する．

3

例．「 」を別の式の中で参照する（先の例の続き）

>>>
10
>>>
10

1.5

* 2

Enter

Enter

←先の評価結果の値を 2 倍する式
←評価結果（計算結果）←上の値を保持する「 」を確認
←値が更新されている

本書で取り扱う GUI ライブラリ

グラフィカルユーザインターフェース（GUI）を備えたアプリケーションプログラムを構築するには GUI を実現するためのプログラムライブラリを入手して用いる必要がある．GUI のためのライブラリには様々なものがあり，Python
処理系に標準的に提供されている Tkinter をはじめ，GNOME Foundation が開発した GTK+，Qt Development

Frameworks が開発した Qt，Julian Smart 氏（英）が開発した wxWidgets，Kivy Organization が開発した Kivy な
ど多くのものが存在している．具体的には，それら GUI のライブラリを Python から使用するために必要となるライ
ブラリを導入し，Python のプログラムから GUI ライブラリを呼び出すための API を介して GUI を構築する．
本書では，比較的新しく開発され，携帯情報端末（スマートフォンやタブレットなど）でも動作する GUI アプリ
ケーションを構築することができる Kivy を主として6 取り上げる．

1.6

表記に関する注意事項

本書内では多数のサンプルプログラムや実行例を示すが，実行する計算機環境によって日本円記号「￥」がバックスラッシュ「＼」として表示されることがある．あるいは，バックスラッシュの入力によって日本円記号が表示される場合がある．このことを留意して，適宜読み替えていただきたい．

1.7

Python に関する詳しい情報

本書で説明していない情報に関しては，参考となる情報源（インターネットサイトなど）を巻末の付録に挙げるので，そちらを参照のこと．

6 Tkinter に関しても，付録「C Tkinter：基本的な GUI ツールキット」（p.366）で簡単に紹介する．

4

Python の基礎

2

他のプログラミング言語の場合と同様に，Python でも変数，制御構造，入出力の扱いを基本とする．Python の文
や式はインタプリタのプロンプトに直接与えること（対話モードでの実行）もできるが，文や式をテキストファイルに書き並べて（スクリプトとして作成して）まとめて実行することもできる．

2.1

スクリプトの実行

例えば次のようなプログラムが test01.py というファイル名のテキストデータとして作成されていたとする．
プログラム：test01.py
1
2# coding : utf -8
print ( ’ 私 の 名 前 は P y t h o n で す ． ’ )これを実行するには OS のターミナルウィンドウから，

python test01.py

Enter（Mac, Linux, Anaconda の場合7 ）と入力するか，あるいは，

py test01.py

Enter（Windows 用 PSF 版の場合）と入力する．するとターミナルウィンドウに「私の名前は Python です．
」と表示される．
このプログラム例 test01.py の中に print で始まる行がある．これは print 関数 というもので端末画面（標準出力）への出力の際に使用する関数であり8 ，今後頻繁に使用する．

《 print 関数 》
書き方：

print( 出力内容 )「出力内容」はコンマ「,」で区切って書き並べることができ，それら内容はスペースで区切った形で出力される．
この際の区切りを「sep=’ 区切り’」で明に指定することができる．
出力処理の後は改行されるが「end=”」（単引用符 2 つ）を与えると行末の改行出力を抑止できる．これは出力の終端処理を指定するものであり，終端に出力するものを「end=’ 終端に出力する内容’」として明に与えることもできる．

‘end=’，‘sep=’ はキーワード引数と呼ばれるものであるが，これに関しては「2.7 関数の定義」（p.122）で説明する．
注意） print は関数なので9 出力内容を必ず括弧 ’(...)’ で括る（引数として与える）必要がある．

print 関数の区切り出力に関するサンプルプログラムを printTest02.py に示す．
プログラム：printTest02.py
1
2
3
4
5

# coding : utf -8
print ( ’ p r i n t 関 数 に 複 数 の 引 数 を 与 え る 例 を 示 し ま す ． ’)print ( ’ 区 切 り 文 字 ’ , ’ を ’ , ’ 指 定 し な い ’ , ’ 例 で す ． ’ )print ( ’ 区 切 り 文 字 を ’ , ’ コ ロ ン に ’ , ’ し た ’ , ’ 例 で す ． ’ , sep = ’: ’ )print ( ’ 区 切 り 文 字 ’ , ’ な し に ’ , ’ し た ’ , ’ 例 で す ． ’ , sep = ’ ’ )このプログラムを実行すると次のように表示される．
print 関数に複数の引数を与える例を示します．
区切り文字 を 指定しない 例です．
区切り文字を:コロンに:した:例です．
区切り文字なしにした例です．

print 関数の行末処理に関するサンプルプログラムを printTest01.py に示す．
7 python3 としなければならない場合もあるので注意されたい．
8 print 関数はファイルに対する出力の機能も持つ．これに関しては後の「2.6.4.1 print 関数によるファイルへの出力」（p.102）で解説する．
9 Python2 までは print は文であった事情から括弧は必要なかったが，Python3 からは仕様が変わり，print は関数となった．

このため括弧が必須となる．

5

プログラム：printTest01.py
1
2
3
4
5
6
7
8
9

# coding : utf -8
print ( ’ こ れ は ’ )print ( ’ p r i n t 関 数 が ’ )print ( ’ 改 行 す る 様 子 の ’ )print ( ’ テ ス ト で す ． ’ , end = ’\ n \n ’ )print ( ’ し か し ， ’ , end = ’ ’ )print ( ’ キ ー ワ ー ド 引 数 end =\ ’\ ’ を 与 え る と ’ , end = ’ ’ )print ( ’ p r i n t 関 数 は ’ , end = ’ ’ )print ( ’ 改 行 し ま せ ん ． ’ )このプログラムを実行すると次のように表示される．
これはprint 関数が改行する様子のテストです．
しかし，キーワード引数 end=’’ を与えると print 関数は改行しません．

このプログラムの 5 行目に「end=’\n\n’」という記述があるが，これは改行を意味するエスケープシーケンス10 であり，「\n」を 2 つ指定することで行末で 2 回改行する．
注）表示する端末によってはバックスラッシュ「\」11 が「￥」と表示されることがある．

2.1.1

プログラム中に記述するコメント「#」で始まる部分は行末までがコメントと見なされ，Python の文とは解釈されずに無視される．ただし，先のプ
ログラムの冒頭にある# coding:

utf-8

は，プログラム（スクリプトのファイル）を記述するための文字コード体系12 （エンコーディング）を指定するもの
であり，コメント行が意味を成す特別な例である．エンコーディングとしては utf-8 が一般的であるが，この他にも
表 1 に示すようなエンコーディングを使用してプログラムを記述することができる．

エンコーディング

表 1: 指定できるエンコーディング（一部）coding:の指定 エンコーディング coding:の指定 エンコーディング

UTF-8

utf-8

EUC

euc-jp

UTF-8(BOM 付き)

utf-8-sigJIS

iso2022-jp

シフト JIScoding:の指定
shift-jis, cp932∗∗ マイクロソフト標準キャラクタセットに基づく指定

coding:に指定するものは大文字／小文字の区別はなく，ハイフン ’-’ とアンダースコア ’ ’ のどちらを使用してもよい13 ．また，エンコーディング指定のコメント行を記述する際，# -*- coding:

utf-8 -*-と記述することがあるが，この ”-*-” は Emacs 14 で用いられる表現であり，省略しても問題はない．
■ 文字列の中に記述する「#」文字列の中に記述した「#」はコメントとは見做されない．
例．文字列中の「#」>>> s = ’abc#def’>>> print(s)abc#defEnter←「#」の記述があるが…

Enter←コメントではなく文字列として扱われる

10 出力の制御に関するもの．詳しくは「2.3.7.1 エスケープシーケンス」（p.29）で解説する．
11 Apple 社の Macintosh の機種によってはOption +￥ と入力しなければならないことがある．

12 ここで言う「文字コード体系」とは，対象の文字とそれを計算機内部で表現するためのバイト列との対応を規定するものである．

「文字コード体系」に関しては後の「2.3.7.14 文字コード，文字の種別に関すること」（p.37）で更に詳しく解説する．
13 若干の例外もある．詳しくは PSF の公式インターネットサイトの「標準エンコーディング」に関する codecs モジュールのドキュメントを参照のこと．
14 Emacs Lisp による編集が行える高機能なテキストエディタである．

6

プログラムのインデント

2.1.2

Python ではプログラムを記述する際のインデント（行頭の空白）に特別な意味があり，不適切なインデントをしてはならない．例えば次のような複数の行からなるプログラム test02.py は正常に動作するが，不適切なインデントを施したプログラム test02-2.py は実行時にエラーとなる．
正しいプログラム：test02.py
12
3
4# coding : utf -8
print ( ’1. 私 の 名 前 は P y t h o n で す ． ’ )print ( ’2. 私 の 名 前 は P y t h o n で す ． ’ )print ( ’3. 私 の 名 前 は P y t h o n で す ． ’ )間違ったプログラム：test02-2.py
12
3
4# coding : utf -8
print ( ’1. 私 の 名 前 は P y t h o n で す ． ’ )print ( ’2. 私 の 名 前 は P y t h o n で す ． ’ )print ( ’3. 私 の 名 前 は P y t h o n で す ． ’ )test02-2.py を実行すると次のようになる．
File "C:￥Users￥katsu￥Python￥test02-2.py", line 3
print( ’2. 私の名前は Python です．’ )IndentationError: unexpected indent
インデントが持つ意味については「2.5 制御構造」（p.75）のところで解説する．

文を分割して／連結して記述する方法

2.2

1 つの文や式を複数の行に分割して記述するには行末に「￥」15 を記述する．
例．1 つの式 1+2+3 を複数の行に分割して記述する例（対話モードでの例）>>> 1 ￥ Enter... + ￥ Enter... 2 ￥ Enter... + ￥ Enter
... 3
Enter
6

←計算結果

複数の文や式を 1 つの行に書き並べるにはセミコロン「;」で区切る．
例．2 つの文を 1 行に記述する例（対話モードでの例）>>> print(’2 つの文で’,end=’’) ; print(’ 表示しました．’)
2 つの文で表示しました．

Enter

←実行結果

15 これは先に説明したバックスラッシュと同じもので，Apple 社の Macintosh の機種によっては

7

Option +￥ と入力する．

変数とデータの型

2.3

変数はデータを保持するものであり，プログラミング言語の最も基本的な要素である．変数の記号に値を割り当てるにはイコール「=」を使用する．
例．変数記号 x に値 10 を割り当てる

x = 10
変数に割り当てる（代入する）値には数値（整数，浮動小数点数）や文字列といった様々な型がある．C 言語や Java
では，使用する変数はその使用に先立って明に宣言する必要があり，変数を宣言する際にデータの型を指定しなければならず，宣言した型以外のデータをその変数に割り当てることはできない．この様子を指して「C 言語や Java は静的な型付けの言語処理系である」と表現する．これに対して Python は動的な型付けの言語処理系であり，1 つの変数に割り当てることができる値の型に制約は無い．すなわち，ある変数に値を設定した後で，別の型の値でその変数の内容を上書きすることができる．また Python では，変数の使用に先立って変数の確保を明に宣言する必要は無い．
例えば次のような例について考える．
例．変数への値の代入>>> x = 2

Enter

←変数 x に整数の 2 を代入>>> y = 3

Enter

←変数 y に整数の 3 を代入>>> z = x + yEnter← x と y の値を加算したものを変数 z に代入>>> print(z)Enter←変数 z の内容を出力する処理
←出力結果

5

これは Python の処理系を起動して変数 x, y に整数の値を設定し，それらの加算結果を表示している例である．変数への値の設定（代入）にはイコール記号 ’=’ を使う．引き続いて次のように Python の文を与える．
例．既存の変数に値を上書きする（先の例の続き）>>> x = "2"Enter←変数 x に文字列の値”2”を代入>>> y = "3"Enter←変数 y に文字列の値”3”を代入>>> z = x + yEnter← x と y の値を連結したものを変数 z に代入>>> print(z)Enter←変数 z の内容を出力する処理
←出力結果

23

この例は x, y に代入された文字列を，加算ではなく連結するものであり，同じ変数に異なる型の値が上書きされていることがわかる．ただし，変数に代入される値の型の扱い（演算など）に関しては厳しい扱いが求められる．例えば
数値と文字列を加算しようとすると次のような結果（エラー）となる．
例．数値と文字列を加算する試み>>> 12 + "34"

←数値と文字列の加算の試み

Enter

Traceback (most recent call last):←異なる型同士の演算が許されない16
File "<stdin>", line 1, in <module>
旨のエラーメッセージ
TypeError: unsupported operand type(s) for +: ’int’ and ’str’← ‘TypeError’
ある変数に割当てられている値を別の変数に代入することができる．
例．変数の値を別の変数に割当てる>>> a = 3

Enter

←変数 a に割当てられた値を>>> b = aEnter

←変数 b に割当てることができる>>> print(b)Enter←変数 b の値を確認

3「b = a」で変数 b に対して変数 a の値を代入している．これに対して「a = 3」の右辺にあるように直接的に「3」と記述したものをリテラルという．
16 Python 以外では（例えば JavaScript など），異なる型の値同士の演算が許される言語も存在する．

8

例．リテラル5’apple’2.3.1： 整数リテラルの 5： 文字列リテラルの ’apple’

日本語の変数名の使用

Python3 では日本語の変数名が使用できる．
例．日本語の変数名>>> あ = ’ いうえお’
>>> あ

2.3.2

←変数「あ」の値を確認

Enter’ いうえお’←変数名に「あ」を使用

Enter←値が保持されている変数名に関する注意

変数名として使用できない，あるいは使用してはならない名前があることに注意すること．変数名はアルファベッ
トもしくは Unicode の全角文字から始める．あるいはアンダースコア ’ ’ も変数名に含めて（先頭に使用して）も良い．ただしハイフン ’-’ は減算の記号であるため変数名には使用できない．その他，特殊記号も変数名に使用できな
いものが多いので注意すること．
例．変数名に使用できる／できない記号>>> a = 12

Enter
Enter

>>> print( a )12>>> n!

= 34←アンダースコアを使用した変数名が使用できる←感嘆符 ’!’ を使用した変数名は

Enter

File "<stdin>", line 1
使用できない（エラーとなる）
n! = 34^
SyntaxError: invalid syntax
Python の予約語17 は変数名には使用できない．
例．予約語を変数名に使用する試み>>> class = ’A’Enter←予約語「class」を変数名に使用すると…

File "<stdin>", line 1←エラー（例外）が発生する
class = ’A’^
SyntaxError: invalid syntax←文法エラーとなっている
これは，予約語「class」を変数名として使用する試みの例であるが，このような場合はエラー（例外）が発生する．また予約語以外のものであっても，システムが標準的に提供するオブジェクトの名前（関数名など）は変数として使用してはならない．
例．「print」を変数名として用いる試み>>> print( ’Python’ )Python>>> print = ’ あいうえお’>>> print( ’Python’ )Enter← print 関数の使用←正常に動作している←「print」という語を変数名として値を与え，

Enter
Enter

← print を関数名として使用すると…

Traceback (most recent call last):←エラー（例外）が発生する
File "<stdin>", line 1, in <module>
TypeError: ’str’ object is not callable
これは，既存の print 関数の名前を変数名として使用し，それに値を代入した例である．特に注意すべきこととして，この段階ではエラー（例外）が発生しないという点が重要である．この例では，以後「print」は関数として使用できなくなるが，変数名となった記号「print」を del 文によって解放すると再度「print」は関数名として使用可能となる．
（次の例）
17 予約語：Python 言語の基本的な文を構成する要素．

9

例．変数名としての「print」を解放する（先の例の続き）>>> del print←変数名「print」の解放Enter>>> print( ’Python’ )PythonEnter← print を関数名として使用する←正常に動作している

print 以外の関数についても，誤って変数名として使用した際は同様の方法で回復を試みる必要があるが，回復できな
い場合は Python 言語処理系を再起動しなければならない．

2.3.3

イコール「=」の連鎖（Multiple Assignment）

イコール「=」の連鎖によって，1 つの値を複数の変数に割り当てることができる．
例．変数 a, b, c に値 12 を設定する

Enter>>> a = b = c = 12

変数への値の割り当て方法はこの他にもある．後の「2.4.8 データ構造に沿った値の割当て（分割代入）」（p.72）で更に高度な方法について説明する．

2.3.4

変数の解放（廃棄）（次の例）
値を保持している変数を解放する（変数を廃棄する）には del 文を使用する．
例．変数への値の設定と廃棄

>>> a

←値の確認

Enter

←結果表示

123
>>> del a>>> a←変数への値の設定

Enter>>> a = 123

Enter←変数の解放（廃棄）
←値の確認

Enter

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name ’a’ is not defined←エラーメッセージ←変数に何も設定されていない

これは，値の設定された変数 a が del 文によって解放される例である．Python では，値が設定されていない（未使用の）変数を参照しようとすると上の例のようなエラー（NameError）が発生する．
変数記号が値を持っているかどうか（シンボルが定義されているか未定義か）を調べる方法については「4.19 使用されているシンボルの調査」（p.301）を参照のこと．

2.3.5

変数が値を保持する仕組みの概観

言語処理系が扱う値（データ）はコンピュータの主記憶上に確保されたオブジェクトであり，変数に値を割当てる（代入する）行為は，当該オブジェクトに変数記号を結びつける処理であると見ることができる．また，データを格納するオブジェクトは具体的な値の情報の他に，その値のデータ型（type）を始めとする各種の情報も保持する．

Python 言語処理系では，データを格納するオブジェクトのデータ型を type 関数で調べる（p.41「2.3.11 型の検査」
で説明する）ことができる．また，メモリ上のオブジェクトの識別情報（識別値18 ）を id 関数で調べることができる．
（次の例）
例．オブジェクトのデータ型と識別情報を調べる>>> x = 3.14

Enter>>> type(x)Enter<class ’float’>>>> id(x)Enter2125365768816←変数への値の割当て←変数が持つオブジェクトの値の型を調べる←浮動小数点数（ﬂoat）であることがわかる←変数が持つオブジェクトの識別情報を調べる←当該オブジェクトのための一意の値

18 CPython 実装系では当該オブジェクトのメモリアドレスである．

10

この例ではオブジェクトの識別値は 2125365768816 となっているがこれは一例であり，実際には Python 処理系がオブジェクト作成時に決定する．
上の例の実行後の変数とオブジェクトの概観を図 1 に示す．

x 変数記号
メモリ上のオブジェクト

id: 2125365768816
type: float

value: 3.14

図 1: メモリ上のオブジェクトに変数記号が結び付けられている様子
同じ値のリテラルを別の変数に割当てると，基本的にそれは別のオブジェクトとして扱われる．
（次の例）
例．数値リテラル 3.14 を別の変数に割当てる（先の例の続き）>>> y = 3.14

←別の変数に先と同じリテラル値を割当てる

Enter>>> type(y)Enter<class ’float’>←識別値は別のものになっている>>> id(y)Enter2125365765232

この処理の後の変数とオブジェクトの概観を図 2 に示す．

x 変数記号

y 変数記号

id: 2125365768816

id: 2125365765232

type: float

type: float

value: 3.14

value: 3.14

図 2: 変数 x, y はそれぞれ別のオブジェクトを指す
同じ 3.14 という値を持つ 2 つの変数 x, y はそれぞれ別のオブジェクトを指していることがわかる．しかし，既存の変数が持つ値を別の変数に割当てると，同一のオブジェクトを指すことに注意すべきである．
（次の例）
例．既存の変数の値を別の変数に割当てる（先の例の続き）>>> z = xEnter

←既存の変数 x の値を別の変数 z に割当てる>>> type(z)Enter<class ’float’>>>> id(z)Enter2125365768816←識別値はx と同じものになっている

この処理の概観を図 3 に示す．

x 変数記号

z 変数記号

id: 2125365768816
type: float

value: 3.14

図 3: 変数 x, z は同一のオブジェクトを指す

1 つのオブジェクトが 2 つの変数記号に結び付けられている様子がわかる．この様子を指して「オブジェクトの参照カウントが 2 である」という．参照カウントが 0 になったオブジェクトは基本的にはガベージコレクション（GC）の対象となり廃棄される．

11

2.3.5.1

識別値に関する注意事項

整数値のオブジェクトの扱いは浮動小数点数の場合と異なる．先の処理例において，変数 x，y に 3.14 の替わりに整数値を与えるケースを試みられたい．この他にも id 関数が返す識別値に関しては注意すべきことがいくつかある．

Python 処理系がプログラムを解釈する際，対話モードによる実行の場合とスクリプトの実行の場合で動作が異なることがある．次に示すサンプルプログラム idTest01.py について考える．
プログラム：idTest01.py
1
2
3
4
5

# coding : utf -8
x = 3.14;
y = 3.14# 同じ浮動小数点数を別々の変数に代入
print ( ’x = ’ ,x , ’ , y = ’,y )print ( ’ id ( x ) = ’ , id ( x ) )print ( ’ id ( y ) = ’ , id ( y ) )このプログラムをスクリプトとして CPython 3.12.1 で実行すると次のような結果となる．
実行例．Windows 環境の CPython 3.12.1 による実行
C:￥Users￥katsu>py idTest01.py

Enter←コマンドプロンプトで実行

x = 3.14 , y= 3.14
id(x) = 2362509509744
id(y) = 2362509509744← x と y の識別値が同じになっている

対話モードで同様の処理を行った場合と結果が異なり，変数 x と y の識別値が同じになっていることがわかる．
上の例に示したように，実行時の状況や処理系の実装ごとに値やオブジェクトの識別値が異なることがあるので，id関数の使用においては注意が必要である．

2.3.6

数値

Python では整数（int 型），浮動小数点数（ﬂoat 型），複素数（complex 型）を数として扱う．また，数に対する基本的な演算（算術演算など）の表記を表 2 に示す．
表 2: 数に対する基本的な演算（算術演算など）
表記
意味

表記

意味

a+b

a と b の加算

a−b

減算

a∗b

a と b の乗算a/b

除算

a // b

除算（小数点以下切り捨て）

a%b

剰余（a を b で割った余り）a ∗ ∗b冪乗（a の b 乗ba ）この他にも累算代入19 の演算子が使える．例えば，

a += ba *= ba %= ba //= bはははは

a = a + b と同等， a -= ba = a * b と同等， a /= ba = a % b と同等， a **= ba = a // b と同等

ははは

a = a - b と同等，
a = a / b と同等，
a = a ** b と同等といった演算である．
各種演算子の優先順位に関しては巻末付録「J.1 演算子の優先順位」（p.436）を参照のこと．

2.3.6.1

整数：

int 型

整数としては長い桁の値が扱える．
（次の例）
例．21000 を計算する>>> 2**1000

Enter

107150860718626732094842504906000181056140481170553360744375038837035105112493612249319837881569585
812759467291755314682518714528569231404359845775746985748039345677748242309854210746050623711418779
541821530464749835819412673987675591655439460770629145711964776865421676604298316526243868372056680
69376
19 再帰代入と呼ぶこともある．

12補足） Python インタプリタのプロンプトに対して直接に計算式や値を入力して Enter を押すと，その式の計算結果（値）がそのまま出力される．

■ 整数値の表記上の注意
整数の値を記述する際，基本的には先頭に余分な 0 を記述してはならないが，00 の記述は問題ない．
例．整数値の表記の注意>>> 01←前に 0 を記述して 1 を入力する試み

Enter

File "<stdin>", line 1←エラーとなる01^
SyntaxError: leading zeros in decimal integer literals are not permitted;
use an 0o prefix for octal integers>>> 0002.3.6.2←ただし，00 は
問題ない

Enter

巨大な整数値を扱う際の注意

巨大な（桁数の大きい）整数値を扱う際には注意しなければならないことがある．
例．104299 の算出と出力
>>> x

Enter

← 104299 の算出

Enter>>> x = 10**4299←内容確認10000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000：（途中省略）：
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000

この例では 104299 の値を計算しており，それが 4,299 個のゼロを含む 4,300 桁の値となることがわかる．次に 104300の値を計算する例を示す．
例．104300 の算出と出力の試み>>> x = 10**4300
>>> x

Enter

Enter

← 104300 の算出は可能，しかし…

←値を出力して確認しようとすると…

Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
ValueError: Exceeds the limit (4300) for integer string conversion;use sys.set int max str digits() to increase the limit
巨大な整数値を算出することはできるが，それを出力しようとすると ValueError というエラーが発生することがこの例からわかる．またエラーメッセージの内容から，4,300 桁を超える整数値を出力する際にエラーが発生する20 ことがわかる．この上限値を超える桁数の値を出力するには sys モジュール21 の set int max str digits 関数を用いて出力桁数の上限値を変更すると良い．
（次の例）
例．出力桁数の上限値を大きくする（先の例の続き）>>> import sys

Enter← sys モジュールの読み込み>>> sys.set int max str digits(4301)
>>> x

Enter

Enter

←出力上限桁数を 4,301 に設定する←内容確認

10000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000：（途中省略）：
00000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000←出力できている

20 この制限は 2022 年 9 月に導入された．それ以前の版の Python ではこの制限はない．
21 システムパラメータの取得や設定などに関するモジュール13

■ 整数値の桁数（10 進数表現）を調べる方法
整数値の桁数（10 進数表現）を調べるには対数関数を応用する方法がある．
例．大きな整数値の桁数を調べる>>> import mathEnter

←必要なモジュールの読み込み>>> x = 3**100

Enter← 3100 の算出

>>> x
Enter
←値の確認
515377520732011331036461129765621272702107522001>>> math.floor(math.log10(abs(x)))+1Enter48← 48 桁であることがわかる← 3100 の値←桁数を調べる

これは x = 0 の場合に log10 |x| + 1 で整数部の桁数を算出する例で，使用した math モジュールに関しては後の「2.3.6.9 数学関数」（p.17）で解説する．

2.3.6.3

浮動小数点数：ﬂoat 型

浮動小数点数は IEEE-754 で定められる倍精度（double）で表現される．
例．1.00000000001100000000000 を求める

Enter>>> 1.00000000001 ** 100000000000
2.71828205335711

ﬂoat 型の値の記述には指数表記が使える．指数表記は非常に大きな数や，非常に小さな数を表現する際に用いられる表現であり，仮数部 m と指数部 n から成る m × 10n という表記であるが，Python では，menと表記する．
例．指数表記による小さな数，大きな数の表記>>> NA = 6.02214076e23←非常に小さな数

Enter>>> me = 9.1093837015e-31←非常に大きな数Enter>>> print(’ 電子の質量 (Kg):’,me)Enter
電子の質量 (Kg): 9.1093837015e-31

←内容確認
←結果表示

>>> print(’ アボガドロ定数:’,NA)
アボガドロ定数: 6.02214076e+23

←内容確認
←結果表示

Enter

注）値の大小に関係なく指数表記は使用できる．
例．指数表記の例>>> 0.31415e1
3.1415← 0.31415 × 101
←結果表示

Enter

ﬂoat 型で扱える値の精度は限定されており，それらに関する情報は sys モジュール22 を用いて参照することができ
る．ﬂoat で扱える正の最大値は ﬂoat info.max ，正の最小値は ﬂoat info.min を参照すると得られる．
例．ﬂoat 型で扱える数に関する情報>>> import sys

Enter← sys モジュールの読込み>>> sys.float info.max
Enter← ﬂoat 型で扱える正の最大値
1.7976931348623157e+308←これが正の最大値>>> sys.float info.min
Enter← ﬂoat 型で扱える正の最小値
2.2250738585072014e-308←これが正の最小値（正規化数23 ）※ 高い精度の（仮数部の桁数の大きい）浮動小数点数を扱う方法については後の「2.3.6.11 多倍長精度の浮動小数点数の扱い」（p.21）を参照のこと．

22 システムパラメータの取得や設定などに関するモジュール
23 本書では解説を割愛する．

14

2.3.6.4

アンダースコア「 」を含む数値リテラルの記述

数値の記述の中にあるアンダースコア「 」は無視される．
例．アンダースコアを含む数値の記述>>> 1 000 000
1000000Enter←記述例 1←実際の値>>> 2 345.67
2345.67

Enter←記述例 2
←実際の値

Enter

>>> 9 8 7 6 5 4 3 2 1987654321←記述例 3←実際の値

ただし，小数点の記号と連接するとエラーが発生する．
例．誤った形でアンダースコアを数値の中に記述した例>>> 3. 14
Enter←誤った記述File "<stdin>", line 1←エラーメッセージ
3. 14^
SyntaxError: invalid syntax←文法エラーを意味する
2.3.6.5

基数の指定： 2 進数，8 進数，16 進数

数を記述する際に表 3 に示すような接頭辞を付けることで 2 進法，8 進法，16 進法の表現ができる．

接頭辞

表 3: 基数（n 進法）の接頭辞
表現
例

0b（ゼロビー）

2 進法

0b1011011 （= 9110 ）0o（ゼロオー）

8 進法

0o1234567 （= 34239110 ）0x（ゼロエックス） 16 進法

0x7b4f（= 3156710 ）例．2 進数，8 進数，16 進数>>> 0b111
7Enter← 2 進数表現の数値←得られた値（10 進数表現）>>> 0o7777
4095

Enter

← 8 進数表現の数値←得られた値（10 進数表現）>>> 0xff
255← 16 進数表現の数値←得られた値（10 進数表現）

Enter

この例のように，接頭辞を付けたものが直接に数値として扱われる．

2.3.6.6

複素数：

complex 型

Python では複素数が扱える．この際，虚数単位は j で表す．
例．(1 + i)(1 − i) の計算を Python で実行する>>> (1+1j)*(1-1j)(2+0j)

Enter

このように虚部（j の係数）を明に記述する必要がある．すなわち，虚部が 1 や 0 であってもそれらを明に記述しなけ
ればならない．また計算の結果，虚部が 0 になっても 0j と表記される．
複素数の実部（実数の部分）が 0 の場合は実部の表示が省略される．また，実部，虚部ともに 0 の場合でも，値がcomplex 型の場合は 0j と表示される．
例．実部，虚部が 0 となる例>>> a = 0+2j
>>> a
2j

Enter

>>> a - 2j
0j

Enter

←実部が 0，虚部が 2 の複素数

←内容確認
←実部の表示が省略されている

Enter←更に虚部も 0 にしてみると← complex 型は虚部が必ず残る
15

複素数の実部と虚部は，プロパティreal と imag に保持されており，個々に取り出すことができる．
例．実部，虚部の取得>>> c = 1-3j←複素数の生成Enter>>> c.real
1.0

Enter
←実部の取り出し←実部が得られる>>> c.imag
-3.0

Enter
←虚部の取り出し←虚部が得られる

複素数に対して conjugate メソッドを使用すると共役複素数が得られる．
例．共役複素数（先の例の続き）>>> c.conjugate()Enter←共役複素数の算出(1+3j)←共役複素数が得られている■ complex コンストラクタ

complex コンストラクタで複素数を生成することもできる．
書き方：

complex( 実部, 虚部 )例．complex コンストラクタで複素数を生成←実部が 1，虚部が 2 の複素数を生成>>> complex(1,2)
Enter(1+2j)←結果表示参考）複素数は実部 a と虚部 b の和 a+bj の形で表現されるため，複素数の計算の結果は基本的にこの形になる．
例．複素数の除算 (5 + 10i)/(3 − 4i)>>> (5+10j)/(3-4j)Enter←複素数の除算(-1+2j)←結果は実部と虚部の和の形式■ 複素数のノルム
複素数 a + bi のノルム√

a2 + b2 は abs 関数で求めることができる．

例．3 + 4i のノルム>>> abs( 3+4j )Enter← abs 関数による複素数のノルムの算出
5.0←ノルムの値（ﬂoat 型で得られる）
abs 関数の引数に実数を与えると，その絶対値を返す．
例．-5 の絶対値を求める>>> abs( -5 )
Enter
5
←結果表示
2.3.6.7← |−5| を求める

最大値，最小値関数 max，min の引数に値の列を与えることで，それぞれ最大値，最小値を求めることができる．
例．最大値と最小値の算出>>> max( 1, 2, 3, 4, 3, 2 )
4
←結果表示

Enter

←引数の中から最大の値を選び出す>>> min( 1, 2, 3, 4, 3, 2 )
1
←結果表示

Enter

←引数の中から最小の値を選び出す

max，min の引数にはリストやタプル24 を与えることもできる．

24 リスト，タプルに関しては「2.4 データ構造」（p.46）で解説する．

16

例．最大値と最小値の算出（リストの中から選出）←値の列のリストを作成>>> a = [1,2,3,4,3,2]

Enter>>> max( a )
Enter
4
←結果表示

←リスト a の中から最大の値を選び出す>>> min( a )
Enter
1
←結果表示

←リスト a の中から最小の値を選び出す

参考）複数の値の合計値を求める関数として sum がある．これに関しては「2.4.1.8 要素の合計： sum 関数」（p.52）
で解説する．

2.3.6.8

浮動小数点数の誤差と丸め浮動小数点数の計算の結果は誤差を含む．
例．浮動小数点数の計算における誤差>>> 0.1 + 0.2
Enter0.30000000000000004←加算←誤差を含んだ計算結果

数値は実際には（計算機内では）2 進数の形式で表現される．また，10 進数表現において「0.1」は有限の桁数で表現できるが，これを 2 進数で表す場合は循環小数となる．従って，そのような値を計算に用いる場合は，精度の上限（扱える桁数の上限25 ）によって計算結果の桁数が制限され，これに起因する計算の誤差が生じる．
値によっては 2 進数表現の際に循環小数とならないこともあり，その場合は計算結果に誤差が生じない．
例．誤差のない浮動小数点数の計算>>> 0.5 + 0.25
Enter
←加算
0.75
←誤差が見られない
この例の場合は 0.5(10) = 0.1(2) ，0.25(10) = 0.01(2) である26 ので，10 進数，2 進数の両方の表現において有限の桁数となり（循環小数とはならず）計算結果に誤差が生じない．
指定した桁数に値を丸めるには round 関数を使用する．この関数は浮動小数点数の小数点以下の桁を丸める（四捨
五入する27 ）ことができる．
書き方：

round( 値，小数点以下の桁数 )この関数は，引数に与えた値を丸めた結果を返す．
例．round 関数>>> 1.0 / 3.0
Enter0.3333333333333333>>> round( 1.0 / 3.0, 2 )0.33←結果の表示← 1 ÷ 3 の計算（丸めなし）←結果の表示Enter← 1 ÷ 3 の計算（小数点以下 2 桁にする丸め）>>> round( 123456789.123, -2 )Enter
123456800.0←結果の表示←桁数指定に負の値を指定

この例の様に，丸めの桁数に負の値を指定することができ，その場合は「整数部の末尾の丸め」となる．

2.3.6.9

数学関数

次のようにして math モジュールを読み込むことで，各種の数学関数が使用できる．
例．math モジュールの読み込み>>> import mathEnter

各種関数は「math.」の接頭辞を付けて呼び出す．例えば正弦関数の値を求めるには次のようにする，
例．正弦関数（sin）の使用>>> math.sin(math.pi/2)
1.0
←計算結果

Enter

← sin(π/2) の算出

25 ﬂoat の有効桁数は約 15 桁程度である．
26 参考：巻末付録「I.5 浮動小数点数と 2 進数の間の変換」（p.433）27 Python の round 関数の処理は厳密には四捨五入とは異なる．

17

表 4 に math モジュールが提供する数学関数や定数の一部を挙げる．表 4 に挙げたもの以外にも多くの関数が提供されている．詳しくは Python の公式インターネットサイトを参照のこと．

関数

説明

sqrt(x)x の平方根exp(x)√

表 4: 使用できる数学関数，定数の一部
関数
説明

xy

x

pow(x,y)xのy乗x の指数関数exlog(x,y)x の対数関数logy xlog2(x)x の対数関数

log2 xlog10(x)x の対数関数

log10 xsin(x)

x の正弦関数sin(x)

cos(x)

x の余弦関数cos(x)

tan(x)

x の正接関数tan(x)

asin(x)x の逆正弦関数

sin−1 (x)acos(x)x の逆余弦関数

atan(x)x の逆正接関数

tan−1 (x)sinh(x)x の双曲線正弦関数

sinh(x)cosh(x)x の双曲線余弦関数

tanh(x)x の双曲線正接関数

tanh(x)asinh(x)x の逆双曲線正弦関数

sinh−1 (x)acosh(x)x の逆双曲線余弦関数

atanh(x)x の逆双曲線正接関数

tanh−1 (x)pidivmod(a,b)

円周率cos−1 (x)cosh−1 (x)πea ÷ b の商と余りのタプル

※2

ネイピア数

※1

cosh(x)

e

を返す関数
※1
y を省略した場合は自然対数※ 2 タプルに関しては「2.4 データ構造」（p.46）で解説する．

例．n! を求める関数 factorial>>> import math

←モジュールの読み込みEnter>>> math.factorial( 30 )Enter
265252859812191058636308480000000← 30! の計算
←計算結果

■ 最大公約数（gcd）と最小公倍数（lcm）について

math モジュールは最大公約数を求める関数 gcd を提供するが，Python の版によって仕様が異なることに注意しなければならない．
（次の例参照）
例．Python3.8 における gcd 関数>>> import math

←モジュールの読み込みEnter>>> math.gcd(12,18)6←計算結果← 12 と 18 の最大公約数を求める

Enter>>> math.gcd(12,18,24)
Enter← 12 と 18 と 24 の最大公約数を求めようとすると…
Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: gcd expected 2 arguments, got 3
この例からわかるように，Python3.8 の gcd 関数は 2 つ整数の最大公約数を求めることはできるが，3 つ以上の整数については計算することができない．これに対して，Python3.9 以降の版の gcd 関数では 3 つ以上の整数について計算することができる．
（次の例参照）
例．Python3.9 における gcd 関数>>> import math

←モジュールの読み込みEnter>>> math.gcd(12,18)6←計算結果← 12 と 18 の最大公約数を求める

Enter>>> math.gcd(12,18,24)
6
←計算結果

Enter

← 12 と 18 と 24 の最大公約数を求める

Python3.9 以降では，math モジュールは最小公倍数を求める関数 lcm を提供する．
（3.8 以前では未提供）
例．Python3.9 における lcm 関数>>> import math>>> math.lcm(4,6)
12
←計算結果

Enter
Enter

←モジュールの読み込み← 4 と 6 の最小公倍数を求める

18

例．Python3.8 では lcm 関数は未提供>>> import math

←モジュールの読み込みEnter>>> math.lcm(4,6)
Enter← lcm 関数を呼び出そうとすると…
Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
AttributeError: module ’math’ has no attribute ’lcm’■ 複素数を扱う関数

math モジュールが提供する関数群は実数に対するものである．複素数を扱う関数群は cmath モジュールが提供しており，表 4 に挙げたものと共通の関数名のものが多い．詳しくは Python の公式ドキュメント（公式インターネッ
トサイトなど）を参照のこと．
例．math モジュール，cmath モジュールそれぞれの sqrt 関数の違い>>> import math← math モジュールの読み込みEnter← math モジュールの関数でEnter>>> math.sqrt(-2)√−2 を算出する試み

Traceback (most recent call last):← math.sqrt が複素数を扱えないため
File "<stdin>", line 1, in <module>
エラーが発生する
ValueError: math domain error>>> import cmath← cmath モジュールの読み込みEnter>>> cmath.sqrt(-2)
Enter← cmath モジュールの関数で1.4142135623730951j←計算結果が複素数として得られる
2.3.6.10√−2 を算出する試み

特殊な値：inf, nan

数値として扱われる特殊な記号として inf と nan がある．inf は，あらゆる数値より大きい値（無限大）として定義された形式的な記号である．
（次の例参照）
例．形式的な無限大記号の扱い>>> import math← math モジュールの読み込み

Enter←形式的な無限大>>> math.inf
Enter
inf
←形式上の表示>>> a = math.inf←変数に代入することもできる

Enter>>> a > 100**10000
Enter←非常に大きな数値 10010000 との比較
True
← inf はあらゆる数値よりも大きい
この例で使用している比較演算子「>」に関しては，p.84 「2.5.4.1 条件式」で説明する．また，True という値は真か偽かを表す値「真理値」であり，これについては p.39「2.3.8 真理値」で説明する．

inf は math モジュールに依らず使用することができる．
（次の例参照）
例．math モジュールに依らない inf の生成>>> a = float(’inf’)
>>> a
inf

Enter

← inf の生成

Enter
←内容確認
← inf が生成されている>>> type( a )Enter←型の検査（p.41「2.3.11 型の検査」で説明する）<class ’float’>←浮動小数点数（ﬂoat）の型である
inf は負（マイナス）の符号を取り得る．
（次の例参照）
例．負の inf（先の例の続き）>>> b = -1*a
>>> b
-inf

Enter

← (-1) を掛けて負の inf をつくる

Enter
←内容確認
←負の inf が生成されている>>> b < -(100**10000)
Enter←非常に絶対値の大きな負の数値 −(10010000 ) との比較
True
← -inf はあらゆる数値よりも小さい
inf はあくまで形式的なものであり，厳密な意味では数学的な値ではない．そのため，値として数値計算に用いるべきではない．
（次の例参照）

19

例．inf を計算に用いる試み（先の例の続き）>>> a + a
inf

Enter
←加算の試み←計算結果>>> a * a
inf

Enter
←乗算の試み←計算結果>>> a - a
nan

Enter
←減算の試み←計算結果（数ではない）>>> a / a
nan

Enter
←除算の試み←計算結果（数ではない）

この例からわかるように減算と除算の結果は解釈できない．これは非数であり，nan（not a number）という記号で形式的に表される．
注意）inf, nan の型は ﬂoat である．
■ 特殊な値かどうかの判定

math モジュールは inf や nan といった特殊な値を判定する関数や有限の数値を判定する関数（下記）を提供している．
・ math.isinf( 値 )：・ math.isnan( 値 )：・ math.isﬁnite( 値 ) ：

値が正もしくは負の無限大なら True，それ以外なら False
値が nan なら True，それ以外なら False
値が有限の数値なら True，それ以外なら False

例．無限大の判定（先の例の続き）>>> math.isinf( a )Enter← a（inf）を判定
True← a は正の無限大 inf である>>> math.isinf( -a )Enter
← -a（-inf）を判定
True← -a は負の無限大 -inf である>>> math.isinf( 2 )Enter← 2 を判定False← 2 は有限の数値である← a/a（nan）を判定>>> math.isinf( a/a )
Enter
False
← nan は無限大ではない
例．非数（nan）の判定（先の例の続き）>>> math.isnan( a/a )
Enter
True
←非数（nan）である← a/a（nan）を判定>>> math.isnan( a )
Enter
False
← inf は nan ではない

← a（inf）を判定>>> math.isnan( 2 )
Enter
False
← 2 は nan ではない

← 2 を判定例．有限な数値の判定（先の例の続き）>>> math.isfinite( 2 )
Enter
True
←有限な数値である← 2 を判定>>> math.isfinite( a )Enter← a（inf）を判定
False← inf は有限な数値ではない>>> math.isfinite( a/a )Enter← a/a（nan）を判定
False← nan は有限な数値ではない

20

2.3.6.11

多倍長精度の浮動小数点数の扱い

http://mpmath.org/ で公開されている mpmath ライブラリ28 を使用すると，IEEE-754 の倍精度浮動小数点数の精度に制限されない任意の精度による浮動小数点数の演算が可能となる．mpmath を使用するには必要なものを次のようにして読み込んでおく．

from mpmath import mp
mpmath ライブラリには math モジュールで提供されているものと類似の関数が多数提供されており，表 4 のような関数に接頭辞 ’mp.’ を付ける29 ことでその関数の値を求めることができることが多い．ただし math モジュールとの厳密な違いには注意すること．mpmath の使用方法の詳細に関しては先のサイトを参照のこと．
■ 演算精度の設定（仮数部の桁数の設定）

mp の dps プロパティに整数値を設定することで，計算精度（仮数部の桁数）を設定することができる．
例．円周率を 200 桁求める>>> from mpmath import mp← mpmath ライブラリの読込み

Enter←演算精度の設定

Enter>>> mp.dps = 200←円周率の算出Enter>>> print( mp.pi )3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280
348253421170679821480865132823066470938446095505822317253594081284811174502841027019385
21105559644622948954930382←計算結果
注 1）この例では演算精度に 200 桁を指定しているが結果的に 199 桁の仮数部が得られている．従って，結果的に得られる値の桁数の上限を mp.dps に設定すると考えるべきである．
注 2）mpmath ライブラリの関数が返す値の型は，通常の浮動小数点数 ﬂoat とは異なる mpf オブジェクト（mpmath.ctx mp python.mpf）
であることに注意すること．

■ 値の生成mpmath が扱う数値は mpf クラスのインスタンスであり，mpf コンストラクタに初期値を与えて生成30 する．
例．値の生成（mpf オブエジェクトの生成）>>> from mpmath import mp>>> mp.dps = 72

←演算精度の設定

Enter>>> a = mp.mpf(’0.0000000001’)>>> b = mp.mpf(’1.0e10’)>>> a*bEnter
mpf(’1.0’)← mpmath ライブラリの読込みEnter← 10−10 のオブジェクト生成して a に設定

Enter

Enter

← 1010 のオブジェクトを生成して b に設定

←積の算出
←計算結果

a*b の計算結果が mpf オブジェクトとして得られていることがわかる．mpf オブジェクトは print 関数により自然な形で出力することができる．
例．print 関数による mpf オブジェクトの出力（先の例の続き）>>> print( a*b )
Enter
1.0
←自然な形の出力
mpf コンストラクタの引数には様々な型のオブジェクト（int，ﬂoat，str）を与えることができる．特に仮数部の桁の長い浮動小数点数を与える場合は，文字列（str）として与えることができる．文字列として浮動小数点数を記述する場合は先の例の様に指数表記が使える．

mpf オブジェクト a の値を int，ﬂoat，str などの型の値に変換するには次のようにする．
28 PSF 版 Python での導入方法に関しては，巻末付録「A.4 PIP によるライブラリ管理」（p.363）を参照のこと．Anaconda の場合は既にインストールされていることが多い．Anaconda でのパッケージ管理は Anaconda Navigator や conda コマンドで行う．
29 ライブラリの読み込みと接頭辞の扱いについては若干の注意が求められることがある．詳しくは巻末付録「F ライブラリの取り扱いについて」（p.413）を参照のこと．
30 クラス，インスタンス，コンストラクタに関することは後の「2.8 オブジェクト指向プログラミング」（p.136）で解説する．

21

整数に変換
浮動小数点数に変換
文字列に変換:::int( a )ﬂoat( a )str( a )■ 複素数

mpmath では複素数を扱うこともできる．虚数単位は Python 標準の表記と同じ「j」である．
例．-2 の平方根を求める← mpmath ライブラリの読込みEnter>>> from mpmath import mp← mpmath の -2 を生成

Enter>>> n = mp.mpf( -2.0 )←平方根の算出Enter>>> a = mp.sqrt( n )←内容確認√←複素数として得られる（0 + 2 i を意味する）>>> print( a )Enter(0.0 + 1.4142135623731j)

>>> a
Enter
←内部表現の確認
mpc(real=’0.0’, imag=’1.4142135623730951’)← mpc オブジェクトとなっている

この例でわかるように，複素数は mpmath の mpc オブジェクトとして扱われる．実部，虚部はプロパティ real ，imagにそれぞれ保持されている．
例．実部，虚部の取り出し（先の例の続き）>>> a.real
mpf(’0.0’)←実部の取り出し
←実部

Enter

←虚部の取り出し←虚部>>> a.imag
Enter
mpf(’1.4142135623730951’)

複素数を明に生成するには mpc コンストラクタを用いてmp.mpc( 実部, 虚部 )とする．
例．虚数単位 i の 2 乗を求める（先の例の続き）>>> n = mp.mpc( 0, 1 )>>> a = n**2>>> print( a )(-1.0 + 0.0j)

Enter
Enter

Enter

← mpmath の虚数単位を生成← 2 乗の算出←内容確認←計算結果は複素数として得られる

mpc コンストラクタには Python 標準の複素数（complex 型の値）を初期値として与えても良い．
例．complex 型の値を mpc オブジェクトに変換する（先の例の続き）>>> mp.mpc( 2+3j )Enter
mpc(real=’2.0’, imag=’3.0’)← complex 型の 2+3j を mpc オブジェクトにする←得られた mpc オブジェクト■ 特殊な値：無限大，非数mpmath パッケージも独自に無限大と非数を定義している．
（次の例参照）
例．mpmath の無限大と非数>>> from mpmath import mpEnter← mpmath ライブラリの読込み>>> a = mp.inf
Enter←無限大の生成
>>> a
Enter
←内容確認
mpf(’+inf’)← mpmath での無限大>>> -aEnter←負の無限大の算出
mpf(’-inf’)← mpmath での負の無限大>>> a + aEnter
←加算の試みmpf(’+inf’)←計算結果>>> a - aEnter
←減算の試みmpf(’nan’)←計算結果（数ではない）22

■ 符号，仮数部，指数部

mpf オブジェクトとして表される数の符号（+/−）を調べるには sign メソッドを使用する．
例．符号を調べる>>> from mpmath import mp>>> mp.dps = 25

←ライブラリの読み込みEnter←演算精度の設定

Enter← 0.3 のEnter>>> n1 = mp.mpf( ’0.3’ )符号を調べるEnter>>> mp.sign( n1 )← 1.0：正mpf(’1.0’)

←0の

Enter

>>> n2 = mp.mpf( ’0’ )符号を調べるEnter>>> mp.sign( n2 )← 0.0：ゼロ

mpf(’0.0’)>>> n3 = mp.mpf( ’-0.3’ )← -0.3 のEnter符号を調べるEnter>>> mp.sign( n3 )← -1.0：負

mpf(’-1.0’)

この例のように「mp.sign( 調査対象の値 )」として評価すると，正の場合は 1.0，ゼロの場合は 0，負の場合は-1.0が得られる．
（戻り値は mpf オブジェクト）

mpf オブジェクトは仮数部（mantissa）と指数部（exponent）から成り，それぞれ man プロパティ，exp プロパ
ティからint 型で得られる．
例．仮数部，指数部を調べる（先の例の続き）>>> n1.man←仮数部を調べる

Enter

←仮数部

23211375736600880154358579>>> n1.exp←指数部を調べる

Enter

←指数部

-86

この例から 0.3 が 23211375736600880154358579 × 2−86 であることがわかる．また，仮数部，指数部の値は元の数の正負に依らない．
例．mpf(’-0.3’) の仮数部と指数部（先の例の続き）>>> n3.man←仮数部を調べる

Enter

←仮数部

23211375736600880154358579>>> n3.exp←指数部を調べる

Enter

←指数部

-86

先の例と同じ結果となっていることがわかる．
【参考】 浮動小数点数の 2 進数表現

mpf オブジェクトの man，exp プロパティを参照することで，浮動小数点数の 2 進数表現を得ることができる．
例．0.3 の 2 進数表現（先の例の続き）>>> bin(n1.man)

Enter←仮数部を 2 進数に変換’0b1001100110011001100110011001100110011001100110011001100110011001100110011001100110011’
この結果から，0.3 の 2 進数表現（近似表現）が1001100110011001100110011001100110011001100110011001100110011001100110011001100110011(2) × 2−86であることがわかる．

23

2.3.6.12

分数の扱い

Python 処理系に標準的に添付されている fractions モジュールを用いると分数を扱うことができる．このモジュー
ルは次のようにして Python 処理系に読み込む．

from fractions import Fraction
これにより，分数を扱うための Fraction クラスが利用できる．
例．分数を生成して計算する例>>> from fractions import Fraction← fractions モジュールの Fraction クラスを読み込むEnter>>> a = Fraction(2,3)

Enter←分数 2/3 を生成して a に代入>>> b = Fraction(3,4)

Enter←分数 3/4 を生成して b に代入>>> c = a + bEnter← 2 つの分数を加算

>>> c
Enter
←内容確認
Fraction(17, 12)←計算結果>>> print( c )Enter← print 関数で出力
17/12←整形表示されている
この例のように Fraction コンストラクタの第一引数に分子を，第二引数に分母を与えることで分数オブジェクトが生成される．分数オブジェクトは整数（int）や浮動小数点数（ﬂoat）とは別のクラスのオブジェクトであり，約分され既約な形で保持される．
浮動小数点数（ﬂoat 型）や文字列（str 型）から直接的に分数を作成することもできる．
例．浮動小数点数から分数に変換する例（先の例の続き）>>> d = 1.23456

Enter←浮動小数点数 1.23456 を用意>>> Fraction(d)Enter← Fraction への変換
Fraction(694995494495815, 562949953421312)
この例から，1.23456 ≈←変換結果

694995494495815
であることがわかる．
562949953421312

また同様のことが，Fraction クラスのメソッド from ﬂoat によっても可能である．
（次の例）
例．from ﬂoat メソッドによる変換（先の例の続き）>>> Fraction.from float( d )Enter← from ﬂoat メソッドによる変換
Fraction(694995494495815, 562949953421312)←変換結果
例．文字列表現の分数を Fraction にする（先の例の続き）>>> Fraction(’3/5’)
Enter
Fraction(3, 5)←変換結果← Fraction の引数に文字列表現の分数を与える

分数から浮動小数点数，あるいは文字列に変換することもできる．
例．分数を浮動小数点数や文字列に変換する例（先の例の続き）>>> float( c )Enter←分数を浮動小数点数に変換する
1.4166666666666667←変換結果>>> str( c )Enter’17/12’←変換結果←分数を文字列に変換する

分数は int や ﬂoat との演算が可能である．
（次の例参照）
例．分数と整数，浮動小数点数との計算（先の例の続き）>>> print( 1 + c )Enter←分数と整数の加算
29/12←計算結果（分数として得られる）>>> print( 0.5 + c )1.9166666666666667

Enter←分数と浮動小数点数の加算←計算結果（浮動小数点数として得られる）

分数と整数の演算では分数の形で，分数と浮動小数点数の演算では浮動小数点数の形で結果が得られる．

24

■ 分母の大きさの制限
分数（Fraction オブジェクト）に対して limit denominator メソッドを使うと分母の大きさを制限した形で近似した分数を得ることができ，様々な場面で応用ができる．例えば 2.2 という値を分数で表現すると 11/5 になると思われるが，実際に ﬂoat 型の 2.2 を Fraction に変換すると次のようになる．
例．ﬂoat の 2.2 を Fraction に変換する>>> f = Fraction( 2.2 )Enter← 2.2 を Fraction に変換>>> print( f )Enter←表示して確認2476979795053773/1125899906842624←変換結果
分母，分子ともに非常に大きな値となっていることがわかる．これは，ﬂoat 型の 2.2 が計算機の内部では循環小数10.00110011001100110011 · · ·(2) となっていることが原因である．次に分母が 10 を超えない形に近似した分数を求める例を示す．
例．分母が 10 を超えないように近似（先の例の続き）>>> print( f.limit denominator(10) )11/5←近似値の分数←分母の上限を 10 にした形の近似値を求める

Enter

この例のように limit denominator の引数に分母の上限値を与えて実行する．
■ 分母，分子の取り出し

Fraction オブジェクトの分子と分母は numerator プロパティと denominator プロパティがそれぞれ保持している．
例．Fraction の分子と分母>>> f = Fraction(13,17)Enter← Fraction オブジェクトの生成>>> print( f )
←内容確認
13/17
←結果表示
>>> f.numerator
13
←分子

Enter

>>> f.denominator
17←分母←分子の参照Enter←分母の参照参考）浮動小数点数に対して as integer ratio メソッドを実行すると，それを表現する分数の分子と分母のペアが得られる．
例．分子と分母のペアの取得>>> (3.5).as integer ratio()(7, 2)

Enter← 3.5 を分数と見た場合の分子と分母の取得←結果表示

これは，3.5 を 7/2 と見て，分子と分母である 7 と 2 のペアをタプル31 という括弧で括られたデータ構造として取得している例である．

31 タプルに関しては「2.4.2 タプル」
（p.56）で説明する．

25

2.3.6.13

乱数の生成

乱数を生成するには random モジュールを使用する方法がある．このモジュールを使用するには次のようにする．

import random■ 整数の乱数
整数の乱数を生成するには randrange メソッドを使用する．
書き方：

randrange( 開始, 上限, 増分 )「開始」以上「上限」未満の範囲で整数の乱数を生成する．生成される乱数に偏りは無く一様である．
「増分」は省略可能であるが，これを与えると開始 + n× 増分（n は非負の整数）の形で乱数を生成する．

randrange に引数を 1 つだけ与えると，上限のみを指定した動作となる．
（0 以上「上限」未満の乱数）
例．整数の乱数の生成>>> import random←モジュールの読み込みEnter>>> random.randrange(0,100)16←得られた乱数Enter← 0 以上 100 未満の整数の乱数の生成

複数の乱数を生成する例を次に示す．
例．複数の乱数の生成>>> [ random.randrange(0,100) for i in range(10) ] Enter ← 0 以上 100 未満の整数乱数を 10 個生成[16, 51, 90, 68, 82, 39, 83, 23, 15, 35]←得られた乱数列>>> [ random.randrange(0,100,10) for i in range(10) ] Enter ←増分を指定した乱数生成[50, 90, 30, 80, 20, 40, 20, 10, 90, 40]←得られた乱数列>>> [ random.randrange(10) for i in range(10) ] Enter ←上限のみを指定した乱数生成[5, 1, 3, 9, 3, 3, 2, 8, 7, 1]←得られた乱数列
この例では，データ列が [〜] で括られたリストという形で得られている．リストに関しては「2.4.1 リスト」（p.46）のところで説明する．また，この例で示した手法はリストの要素の内包表記を応用したものであり，詳しくは「2.5.1.7

for を使ったデータ構造の生成（要素の内包表記）」（p.78）のところで説明する．
randrange とは別に，一様な整数の乱数を生成する randint もある．
書き方：

randint( 最小値, 最大値 )「最小値」以上「最大値」以下の範囲の乱数を生成する．
例．randint による整数乱数の生成>>> [ random.randint(10,15) for i in range(10) ] Enter ← 10 以上 15 以下の整数乱数を 10 個生成[15, 14, 11, 12, 10, 15, 10, 15, 12, 13]←得られた乱数列■ 浮動小数点数の乱数
浮動小数点数（ﬂoat）の一様乱数（0 以上 1 未満）を生成するには random メソッドを使用する．
例．ﬂoat の乱数の生成>>> random.random()
0.6830640714706756

Enter← ﬂoat 乱数（0 以上 1.0 未満）の生成←得られた乱数

範囲を指定して一様な浮動小数点数の乱数を生成するには uniform を使用する．
書き方：

uniform( 開始, 上限 )「開始」以上「上限」未満の範囲の乱数を生成する．

26

例．uniform 関数による乱数の生成>>> [ random.uniform(10,15) for i in range(10) ] Enter ← ﬂoat 乱数列（10 以上 15 未満）の生成[13.518212730827601, 10.314921371305998, 14.58509484557475, 11.108519481070932,
14.016725270731012, 10.712471969544122, 12.714949788450062, 10.45607976915113,
14.966107767822391, 14.375436436680728]←↑ 得られた乱数列■ 乱数生成における状態，種に関すること

randrange，randint，random，uniform はメルセンヌ・ツイスタ32 を用いたものであり，乱数生成が確定的である．すなわち，ある初期状態から生成する乱数の並びが決められている．このような乱数を疑似乱数33 という．疑似乱数の生成が確定的であることは次の例で確かめることができる．
例．同じ初期状態から同じ乱数列が生成される例>>> random.seed(0)←乱数生成処理を初期化

Enter←乱数を 10 個生成>>> [ random.randrange(0,100) for i in range(10) ]Enter[49, 97, 53, 5, 33, 65, 62, 51, 38, 61]←得られた乱数>>> random.seed(0)←乱数生成処理を再度初期化

Enter>>> [ random.randrange(0,100) for i in range(10) ]Enter←乱数を 10 個生成[49, 97, 53, 5, 33, 65, 62, 51, 38, 61]←同じ乱数列が得られている
この例では seed 関数を使用して乱数生成の状態を初期化している．この関数の引数には，乱数の初期状態を意味する
種（seed）を与える．同一の種で初期化すると，同一の乱数生成過程となる．
このように，指定した初期状態から確定的な乱数を生成することは，統計学や機械学習のためのプログラム開発などにおいて，決まったテストデータを生成する場合に必要となる．また，次のような関数を使用すると，疑似乱数生
成におけるある時点での状態を取得し，その状態を再現することができる．
状態の取得：
状態の再現：

getstate()
setstate( 状態 )getstate は実行時点の乱数生成の状態を意味するオブジェクトを返す．このオブジェクトを setstate の引数に与えて実行すると，乱数生成の系列を再現することができる．
（次の例）
例．乱数生成の状態の取得>>> [ random.randrange(10) for i in range(10) ]Enter[3, 9, 8, 2, 5, 9, 7, 9, 1, 9]←得られた乱数列>>> st = random.getstate()

Enter

←乱数生成

←この時点の状態を st に取得>>> [ random.randrange(10) for i in range(10) ]Enter[0, 7, 4, 8, 3, 3, 7, 8, 8, 7]←得られた乱数列←後続の乱数生成

この例で取得した st を使用して，再度その時点での乱数生成を再現することができる．
（次の例）
例．乱数生成の状態の再現（先の例の続き）>>> random.setstate(st)Enter← st が示す状態を再現>>> [ random.randrange(10) for i in range(10) ]Enter[0, 7, 4, 8, 3, 3, 7, 8, 8, 7]←再現されている←乱数生成■ 正規乱数

gauss 関数を使用すると正規分布（ガウス分布）に沿った乱数を生成することができる．
書き方：

gauss( μ, σ )「μ」を平均，「σ」を標準偏差とする正規分布 N[μ, σ] に沿った乱数を返す．

32 乱数生成器の 1 つ．参考文献：M.Matsumoto, T.Nishimura, ”Mersenne Twister: A 623-dimensionally equidistributed uniform

pseudorandom number generator”, ACM Trans. on Modeling and Computer Simulation Vol.8, No.1, January pp.3-30 (1998)

33 生成系列が確定的でない（再現性がない）乱数を真の乱数，真性乱数と呼ぶ．

27

例．N[0, 1] に沿った正規乱数を 100,000 個生成して度数分布を調べる>>> nr = [ random.gauss(0,1) for i in range(100000) ]Enter←正規乱数 100,000 個生成>>> import matplotlib.pyplot as plt
Enter←可視化ライブラリの読込み>>> h = plt.hist(nr,bins=16)Enter←ヒストグラムの作成>>> plt.show()Enter←作図の実行
これは，可視化ライブラリ matplotlib 34 を用いて乱数のリストのヒストグラムを作成する例であり，この処理の直後に図 4 の (a) のようなヒストグラムが表示される．

(a) N[0, 1] の乱数のヒストグラム(b) 一様乱数のヒストグラム

図 4: 100,000 個の乱数のヒストグラム
参考．
正規分布はμの近くにサンプルが集中するものであり，先の一様乱数とは異なる．参考までに一様乱数のヒストグ
ラムを作成する処理を次に示す．
例．一様乱数を 100,000 個生成して度数分布を調べる（先の例の続き）>>> ur = [ random.random() for i in range(100000) ]Enter>>> h = plt.hist(ur,bins=16)Enter←ヒストグラムの作成>>> plt.show()Enter←作図の実行←一様乱数 100,000 個生成

この処理の結果，図 4 の (b) のようなヒストグラムが表示される．
※ matplotlib に関することは別の文献35 を参照されたい．

random モジュールは本書で紹介したもの以外にも乱数を生成する関数を提供している．詳しくは公式ドキュメン
トを参照のこと．
■ 安全な乱数
暗号学的な処理においては確定的な乱数生成を使用してはならない．より安全な乱数生成には secrets モジュールを使用するべきである．secrets モジュールを使用するためには次のようにする．

import secrets
この後，randbelow メソッドを使用して乱数を得る．このメソッドの引数に 1 つの正の整数与えると，0 以上, 与えた引数未満の整数の乱数を生成する．
例．整数の乱数の発生>>> import secretsEnter>>> secrets.randbelow(100)←得られた乱数52←モジュールの読み込みEnter← 0 以上 100 未満の整数の乱数の発生

34 PSF 標準のライブラリではないので，計算機環境に別途インストールしておく必要がある．
35 拙書「Python3 ライブラリブック」でも解説しています．

28

2.3.7

文字列

文字列はダブルクオート「”」もしくはシングルクオート「’」といった引用符で括ったデータである．どちらを使っても良い36 が，引用符の開始と終了は同じものにしなければならない．
文字列の例． ’Python’，”パイソン”
またこのように，引用符で括って文字列データを表現したものを文字列リテラルという．

2.3.7.1

エスケープシーケンス

Python では C 言語での扱いと同様に，文字列中には特殊な機能を持った記号（エスケープシーケンス）を含める
ことができる．エスケープ記号は「￥」（半角）である．これは，処理環境によってはバックスラッシュ「\」の表示になる場合37 がある．
《 ￥ と \ に関する注意事項》

Unicode の 165（0xa5）に対応する文字も「￥」と表示される場合がある．この場合の「￥」はエスケープシー
ケンスの「\」とは異なるので注意が必要である．特に Apple 社の Macintosh の機種によってはエスケープシー
ケンスの「\」を入力する際に Option +￥ と入力する場合がある．

一般的な意味では「文字列」は可読な記号列のことを指すが，記号列の中に特別な働きを持った，ある種の「制御記号」を含めると，その文字列を端末画面などに表示する際の制御ができる．例えば，「￥n」というエスケープシーケ
ンスを含んだ文字列”一行目の内容です．￥n 二行目の内容です．”
を端末画面に表示してみる．

>>> a = ”一行目の内容です．￥n 二行目の内容です．”>>> print( a )

Enter

Enter

一行目の内容です．
二行目の内容です．
このように，「￥n」の位置で文字列の表示が改行されていることがわかる．この例における print は端末装置に出力する（画面に表示する）ための機能であるが，詳しくは以後の章で解説する．
注）print 関数を使用せずに直接的に文字列を対話モードで参照した場合はエスケープシーケンスの効果は表れない．
例．文字列の内容を直接参照する（先の例の続き）

>>> a

Enter

←変数 a の内容を参照’ 一行目の内容です．￥n 二行目の内容です．’
このように，文字列の内容がそのまま表示される．
参考）テキストファイルの中の改行コードに関しては「2.6.3 ファイルからの入力」（p.94）で解説する．
表示に使用する端末装置によっては，ベルを鳴らすことも可能である．例えば次のように「￥a」というエスケープ
シーケンスを含む文字列を print する．
例．「￥a」でベル音を鳴らす>>> a = "Ring the bell.￥a">>> print( a )

Enter

Enter

Ring the bell.
この表示と同時にベル音が鳴る．
（端末装置によって音は違う．あるいは音が鳴らない場合もある）

エスケープシーケンスには様々なものがあり，代表的なものを表 5 に挙げる．
36 Python 処理系はシングルクオートを付けて文字列を表示する．

37 「￥」,「\」と表示が異なっているが ASCII コードとしては共に 92 （0x5c）である．

29

表 5: 代表的なエスケープシーケンス
ESC 機能

ESC

機能

￥n

改行

￥t

タブ

￥r

行頭にカーソルを復帰

￥v

垂直タブ

￥f

フォームフィード

￥b

バックスペース

￥a

ベル

￥￥

’￥’ そのもの￥"

ダブルクオート文字￥’

シングルクオート文字

この他にも Python では u でエスケープするシーケンスも使用できる．
「￥u」に続いて Unicode の 16 進数表記を記述すると，その文字コードに該当する文字となる．
例．エスケープシーケンスによる Unicode 文字の表現>>> ’￥u604b￥u611b’Enter← Unicode の文字コードで文字列を表現’ 恋愛’←結果としての文字列
参考）ANSI エスケープシーケンス（ANSI コード）コンソール（ターミナルウィンドウ）によっては ANSI エスケープシーケンス（ANSI コード）を使うことができる．
（ウィンドウ環境によっては有効にならないことがあるので注意）
例．下線を付ける>>> a = ’￥033[4m 下線￥033[0m’>>> print( a )
下線

Enter

←’￥033[4m 〜 ￥033[0m’ で下線を付ける

Enter￥033[4m 以降の文字に下線が付く．￥033[0m で ANSI エスケープシーケンスによる装飾を解除する．
例．色を付ける>>> a = ’￥033[31m 赤い文字￥033[0m’>>> print( a )赤い文字←’￥033[31m 〜 ￥033[0m’ で赤にする

Enter

Enter

￥033[31m 以降の文字が赤くなる．￥033[0m で ANSI エスケープシーケンスによる装飾を解除する．
この他にも多くの ANSI エスケープシーケンスが存在するが，詳細については他の資料を参照のこと．

2.3.7.2

raw 文字列（raw string）

文字列中のエスケープシーケンスを無視して ’￥’ を単なる文字として扱うには raw 文字列として扱うと良い．通常の文字列の先頭に ’r’ もしくは ’R’ を付けるとその文字列に含まれる記号は全て「そのままの記号」として扱われる．
例．raw 文字列>>> s = r’abc￥ndef’>>> print(s)abc￥ndef
2.3.7.3

Enter← raw 文字列の生成←出力してみる←’￥n’ で改行されず，そのままの文字として扱われているEnter

複数行に渡る文字列

単引用符 3 つ ’’’〜’’’ で括ることで，複数の行に渡る文字列を記述することができる．
例．複数行に渡る文字列の記述>>> s = ’’’ これは

Enter

...

複数の行にわたる

Enter

...

文字列です．’’’

Enter←記述の開始←記述の終了これで 3 行に渡る文字列が s に得られた．次にこの内容を確認する．

30

例．複数行に渡る文字列の確認（先の例の続き）>>> s← s の内容確認Enter’ これは￥n 複数の行にわたる￥n 文字列です．’

2.3.7.4← s の整形表示Enter>>> print( s )これは複数の行にわたる
文字列です．

← s の内容表示←複数の行として表示されている文字列の長さ（文字数）

文字列の長さ（文字列を構成する文字の個数）は len 関数で求めることができる．
例．文字列の長さを求める>>> len( s )7
2.3.7.5← 7 文字で構成される文字列Enter>>> s = ’abcdefg’Enter← len 関数の実行←長さ（文字数）が得られた

文字列リテラルの連接

文字列リテラル（引用符で括った文字列の表現）を連接すると 1 つの文字列となる．
例．文字列リテラルの連接（その 1）>>> ’abc’ ’def’’abcdef’Enter←連接 (1)←結果>>> ’abc’’def’’abcdef’Enter←連接 (2)←結果（先と同じ）

例．文字列リテラルの連接（その 2）←連接 (3)>>> ’’’abc’’’ ’’’def’’’’abcdef’

Enter
←結果

>>> ’’’abc’’’’’’def’’’’abcdef’Enter←連接 (4)←結果（先と同じ）

一見して視認しにくい場合があるので注意すること．

2.3.7.6

文字列の分解と合成

文字列の指定した部分を取り出すには ’[ ]’ で括った添字（スライス）を付ける．例えば，’abcdef’ という文字列があった場合，’abcdef’[2] は ’c’ である．このように位置を意味する添字を付けることで，文字列の部分を取り出すことができる．先頭の文字の添字は 0 である．
（インデックスの開始は「0」）《 部分文字列の取り出し 》
書き方 (1)： 文字列 [n]「文字列」の n 番目の 1 文字を取り出す．
書き方 (2)： 文字列 [n1 : n2 ]「文字列」の n1 番目から n2 − 1 番目までの部分を取り出す．
書き方 (3)： 文字列 [n1 : n2 : n3 ]上記のことに加え，インデックスの増分 n3 を指定して要素を取り出す．
※ 添字（スライス）の更に高度な応用については「2.4.5 添字（スライス）の高度な応用」（p.69）を参照のこと．

例．1 文字の取り出し>>> s = ’ 美味しい食べ物’>>> s[1]
’ 味’

Enter

←文字列の生成Enter
1 番目の文字の取得←取り出した部分文字列31

例．部分文字列の取得←文字列の生成Enter>>> s = ’abcdefg’>>> s[2:5]Enter← 2 番目から 5-1 番目までの部分文字列の取得’cde’←取り出した部分文字列
例．インデックスの増分を指定して要素を取り出す←文字列の生成Enter>>> s = ’0123456’>>> s[1:6:2]
Enter← 1 番目から 6-1 番目までの要素を 1 つ飛ばしながら抽出’135’←取り出した要素から成る文字列
文字列の連結には，’+’ による加算表現が使える．
例．文字列の連結 (1)←加算記号で連結
←連結結果

Enter

>>> ’abc’ + ’def’’abcdef’

更に，累算代入 ’+=’ を使って次々と累積的に連結してゆくこともできる．
例．文字列の連結 (2)>>> s = ’abc’

Enter←文字列の生成>>> s += ’def’Enter←’def’ を追加>>> s += ’ghi’

Enter←’ghi’ を追加

>>> s
Enter
’abcdefghi’←内容確認←最終的な内容

積の演算 ’*’ を使うと文字列の繰り返しを生成できる．
例．文字列の繰り返し>>> ’abc’ * 10Enter← ’abc’ を 10 回繰り返す’abcabcabcabcabcabcabcabcabcabc’←生成結果■ split メソッドによる文字列の分解

split メソッドを使用すると，特定の文字（列）を区切りとして文字列を分解することができる．
例．文字列の分解>>> s = ’ab,cd,ef,gh’

Enter←文字列の生成←コンマ ’,’ を境（区切り）にして文字列を分解←分解されたリスト>>> s.split(’,’)
Enter[’ab’, ’cd’, ’ef’, ’gh’]

分解されたものがリストの形で得られている．リストに関しては「2.4.1 リスト」（p.46）のところで説明する．
参考）分解の回数を指定する方法

split メソッドで文字列を分解する際，キーワード引数 ‘maxsplit=’ に分解の回数を指定することができる．
例．2 回だけ分解する（先の例の続き）←回数を設定して分解>>> s.split(’,’, maxsplit=2 )Enter[’ab’, ’cd’, ’ef,gh’]←分解結果
この例から，分解されない要素が残ることがわかる．

split メソッドに引数を与えない場合は，対象の文字列中の空白文字を区切りとして分解する．
例．引数なしで split を実行>>> s = ’abc def>>> print( s )abc def ghi
mno

ghi￥tjkl￥nmno’
Enter
jkl

Enter

←各種の空白文字を含む文字列

←内容確認
←結果表示

>>> s.split()Enter←引数なしで split を s に対して実行[’abc’, ’def’, ’ghi’, ’jkl’, ’mno’]
←結果表示

32

空白文字はタブや改行などのエスケープシーケンスを含む．
■ splitlines メソッドによる行の分離

splitlines メソッドを使用すると，複数行に渡る文字列の行を分離することができる．
例．行の分離>>> s = ’’’ これは Enter... 複数の行にわたる Enter... 文字列です．’’’Enter>>> a = s.splitlines()← 3 行にわたる文字列

←行を分離

Enter

>>> a
Enter
←内容確認
[’ これは’, ’ 複数の行にわたる’, ’ 文字列です．’]←結果表示（リストになっている）

split メソッドを用いて ’￥n’ を区切りにして分解することもできるが，行の区切りは ’￥n’ 以外にもあるので，行の分
離には splitlines を使用するべきである．
■ リストの要素の連結

join メソッドを使用すると，リストの要素を全て連結することができる．
（split メソッドの逆の処理）
ただしその場合のリストの要素は全て文字列型でなければならない．
例．リストの要素の連結（split の逆）>>> lst = [’a’,’b’,’c’,’d’]>>> ’:’.join(lst)Enter←リストの生成Enter←コロン ’:’ を境（区切り）にして文字列を連結←リストを連結した文字列’a:b:c:d’join メソッドは区切り文字となる文字列型データに対して実行し，その引数に連結対象要素をもつリストを与える．
2.3.7.7

文字列の置換

文字列中の特定の部分を置き換えるには replace メソッドを使用する．
《 文字列の置換 》
書き方：

文字列.replace(対象部分, 置換後の文字列)「文字列」の中の「対象部分」を探し，それを「置換後の文字列」に置き換えたものを返す．元の文字列は変更されない．

例．文字列の置換>>> a = ’abcdefgabcdefgabcdefg’>>> a.replace(’bcd’,’BCD’)’aBCDefgaBCDefgaBCDefg’
2.3.7.8←元の文字列

Enter

Enter

← ’bcd’ を ’BCD’ に置き換える
←置換結果

文字の置換

1 文字単位で置換する規則に基いて，文字列中の文字を置換することができる．手順としては，まず str クラスのmaketrans メソッドを用いて置換規則のオブジェクトを生成し，それを用いて translate メソッドによって置換処理を行う．
例．1 文字単位の変換規則の適用>>> tr = str.maketrans(’ABC’,’abc’)>>> ’DAEBFCG’.translate(tr)’DaEbFcG’
←処理結果

Enter

←置換規則を tr として生成Enter← tr を用いて置換処理

この例における tr は，

A
↓
a

B
↓
b

C
↓
c
33

と置換する規則であり，その内容は辞書オブジェクト（p.62 「2.4.4 辞書型」で解説する）である．

translate メソッドは置換結果の文字列を返す．
この方法では日本語を含む多バイト系文字の置換も可能である．特にアルファベット大文字／小文字の間での変換に関しては後の「2.3.7.10 大文字／小文字の変換と判定」（p.34）で説明する方法が便利である．

2.3.7.9

英字，数字の判定

文字列に含まれる記号の種類を判定するいくつかの方法を表 6 に示す．
表 6: 文字列に含まれる文字種を判定するメソッド（一部）
メソッド
説明

isalpha()

対象の文字列の要素が全てアルファベット

isdecimal()

対象の文字列の要素が全て数字

isalnum()

対象の文字列の要素が全てアルファベットか数字

これらメソッドの実行例を示す．
例．文字列の要素が全てアルファベットかどうかの判定>>> ’abc’.isalpha()
True

Enter

>>> ’aBc’.isalpha()
True

Enter

>>> ’m4a’.isalpha()
False

Enter

例．要素が全て数字かどうかの判定>>> ’1234’.isdecimal()
True

Enter
Enter

>>> ’640x480’.isdecimal()
False

例．要素が全てアルファベットか数字かの判定

Enter>>> ’123’.isalnum()True>>> ’640x480’.isalnum()
True

Enter

>>> ’123+456’.isalnum()
False

Enter

2.3.7.10

大文字／小文字の変換と判定

アルファベット大文字／小文字の変換や判定のためのメソッド群が使用できる．
例． 文字列中の小文字を大文字に変換する処理>>> s = ’this is a sample.’>>> t = s.upper()

Enter

Enter

←小文字による文字列←小文字を大文字に変換する処理

>>> t
Enter
←内容の確認’THIS IS A SAMPLE.’←大文字になっている
この例では upper メソッドを用いて小文字を大文字に変換している．このメソッドは変換元の文字列オブジェクトに対して適用し，変換結果の文字列を返す．また，元の文字列は変更されない．
他にも様々なメソッドがある．表 7 にそれらの一部を示す．

2.3.7.11

文字列の含有検査

文字列の中に「ある文字列」が含まれるかどうかを検査するには in 演算子を使う．
書き方： 探したい文字列 in 元の文字列
このようにすることで「元の文字列」の中に「探したい文字列」があるかどうかを判定できる．

34

表 7: 大文字／小文字の変換や判定
処理結果（戻り値）
説明

メソッド

元の文字列

upper()’this is a sample.’’THIS IS A SAMPLE.’

小文字→大文字lower()’THIS IS A SAMPLE.’’this is a sample.’

大文字→小文字capitalize()’this is a sample.’’This is a sample.’

文頭を大文字に変換

title()’this is a sample.’’This Is A Sample.’

各単語の先頭を大文字に変換

swapcase()’This Is A Sample.’’tHIS iS a sAMPLE.’

小文字/大文字を逆転

islower()’this is a sample.’True

全て小文字の場合に真’This Is A Sample.’

False

小文字以外を含むと偽’THIS IS A SAMPLE.’

True

全て大文字の場合に真’This Is A Sample.’

False

大文字以外を含むと偽isupper()

元の文字列. メソッド の形で実行する．

例．文字列の含有検査>>> s = ’ 私は大阪府に住んでいます．’←元の文字列の生成Enter>>> ’ 大阪’ in s
True

Enter

←「大阪」が含まれるか検査←含まれる>>> ’ 東京’ in s
False

Enter

←「東京」が含まれるか検査←含まれない

結果は「真か偽か」を表現する真理値であり，True（真）か False（偽）の値である．真理値に関しては「2.3.8 真理値」（p.39）で解説する．

in を用いた文字列の含有検査を応用すると，様々な文字列編集が可能となる．
応用例．冗長な空白文字の除去>>> s = ’A

B

C

D’

>>> while ’ ’ in s: Enter...
s = s.replace(’ ’,’ ’)
...
Enter
←繰り返し処理の終了

Enter←冗長な空白を含んだ文字列← 2 つの空白文字 ’ ’ が存在する間の繰り返しEnter ← 2 つの空白文字 ’ ’ を 1 つの空白文字に置き換える

>>> s
Enter
←内容確認
’A B C D’←空白文字が短縮されている
これは，重複する 2 つの空白文字を 1 つの空白文字に変換する処理を繰り返す例38 である．
（while 文による繰り返しに関しては p.75「2.5 制御構造」で解説する）

2.3.7.12

文字列の検索文字列の中に「ある文字列」がどの位置にあるかを調べるには ﬁnd メソッドを使用する．
書き方 (1)：
書き方 (2)：

文字列.ﬁnd( 語 )文字列.ﬁnd( 語, 開始位置, 終了位置 )「文字列」の中の「語」がある位置（インデックス）を返す．検索は「文字列」の前方（インデックスの小さい方）から後方（インデックスの大きい方）に向かって行う．
「文字列」の中での検索範囲は「開始位置」〜「終了位置-1」で指定することができる．
「終了位置」の記述を省略すると「開始位置」から「文字列」の末尾までが検索対象となる．
「語」が見つからなければ -1 を返す．
例．ﬁnd メソッドによる検索>>> s = ’0123word89word456word123’←文字列 s を作成

Enter>>> s.find(’word’)
4

Enter

← s の中の ’word’ の位置を求める←検出位置（インデックス）>>> s.find(’test’)
-1

Enter

← s の中の ’test’ の位置を求める試み←検出せず

38 このアルゴリズムは最適ではない．更に高速なアルゴリズムについて考察されたい．

35

例．範囲を指定した検索（先の例の続き）>>> s.find(’word’,8,15)
10

Enter

← s の中のインデックス範囲 8〜14で検索←検出位置（インデックス）>>> s.find(’word’,8,13)
-1

Enter

← s の中のインデックス範囲 8〜12で検索←検出せず「文字列」の後方から前方に向かって「語」を検索するメソッド rﬁnd も使用できる．引数の与え方は ﬁnd と同様である．
例．rﬁnd メソッドによる検索（先の例の続き）← s の末尾から先頭にかけて ’word’ の位置を探す←検出位置（インデックス）Enter>>> s.rfind(’word’)
17

Enter

>>> s.rfind(’word’,0,15)
10← インデックス位置 14 から先頭にかけて ’word’ の位置を探す←検出位置（インデックス）

文字列検索には index メソッドも使用できる．
例．index メソッドによる検索（先の例の続き）>>> s.index(’word’)
4

Enter

←検索が成功する場合←検出位置のインデックスが得られる>>> s.index(’test’)Enter←検索が失敗する場合

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found←エラーとなる

この例からもわかるように，index メソッドで検索が失敗するとエラー（ValueError）が発生する．エラーが発生する事象を正しく扱うには後の「2.4.1.6 例外処理」（p.51）で説明する例外処理を施すべきである．
更に高度な文字列検査の方法に関しては「4.3 文字列検索と正規表現」（p.220）で解説する．
■ 文字列の左端／右端にあるものの検査
文字列の左端に指定した文字列部分があるかどうかを調べるには startswith メソッドを使用する．同様に右端にあるかどうかを調べるには endswith メソッドを使用する．
例．左端／右端に指定した文字列があるかどうかを検査する>>> s = ’ABCdefghiJKL’

Enter←検査対象文字列>>> s.startswith(’ABC’)
True

Enter

←左端に ’ABC’ が←ある>>> s.endswith(’ABC’)
False

Enter
Enter

>>> s.startswith(’JKL’)
False>>> s.endswith(’JKL’)
True

Enter

←右端に ’ABC’ は←ない←左端に ’JKL’ は←ない←右端に ’JKL’ が←ある■ 部分文字列の出現回数をカウントする

count メソッドを使用すると，文字列の中に現れる部分文字列の個数を数えることができる．
例．部分文字列のカウント>>> s = ’ABCdefABCghi’>>> s.count(’ABC’)
2

Enter

←この文字列の中に含まれる←’ABC’ は

Enter
←2個

36

2.3.7.13

両端の文字の除去

文字列の両端にある特定の文字を除去するには strip メソッドを使用する．
書き方：

文字列.strip(除去対象の文字の並び)「文字列」の両端に「除去対象の文字の並び」に含まれる文字があればそれらを除去したものを返す．元の「文字列」
は変化しない39 ．
例．両端にある特定の文字の除去>>> s = ’ABCabcABCdefABC’>>> s.strip(’ABC’)’abcABCdef’

Enter

Enter

←この文字列の両端にある←’ABC’ のどれかに該当する文字を除去する←処理結果

この例からわかるように両端に位置していないものは除去されない．

strip メソッドの引数に与える文字列は，除去対象の文字を並べたものであり，それら文字の順序は任意で良い．
例．上と同様の例（先の例の続き）>>> s.strip(’CBA’)’abcABCdef’

Enter←’CBA’ のどれかに該当する文字を両端から除去する←処理結果

strip メソッドの引数を省略すると空白文字（スペース，タブ，改行文字など）を除去する．
例．両端の空白文字を削除する>>> s = ’abcdef￥t￥n’>>> s.strip()’abcdef’Enter←この文字列の両端にある←空白文字を除去する

Enter
←処理結果

strip メソッド以外にも，左端のみを除去対象とする lstrip，右端のみを除去対象とする rstrip メソッドもある．
2.3.7.14

文字コード，文字の種別に関すること

コンピュータで取り扱う文字は，記憶媒体上ではそれに対応するバイト値やバイト列として表現されている．例えば代表的な半角文字であるアスキー文字（ASCII）は巻末付録「J.2 アスキーコード表」（p.437）に示すように 0 〜

127 の値としてコンピュータ内部では扱われている．例えば，アスキー文字「A」の文字コードは「65」であるという．
「文字コード」という言葉には下に示す 2 種類の意味があるので，この言葉がどちらを意味するかは，用いられる状況の文脈で判断すること．

1) ある文字に対応する数値（コードポイントの値40 ）やバイト列
2) 文字と数値（あるいはバイト列）の対応関係を決める規則
特に上記 2) を意味する場合は，曖昧さを避けるために文字コード体系あるいはエンコーディングと呼ぶ場合がある．

Python 言語で取り扱うことができるエンコーディングとしては，p.6 の表 1 に示したものをはじめ多くのものがある
が，Python 言語処理系内部では文字の取り扱いは Unicode 41 に基づいている．
（Unicode は ASCII の体系を含んでいる）
ある 1 文字の文字コードを取得するには ord 関数を使用する．また逆に，文字コードを表す整数値から文字を取得するには chr 関数を使用する．
例．文字コードの取得>>> ord(’a’)
Enter←’a’（半角文字）の文字コードの取得
97←得られた文字コード（ASCII コード）>>> ord(’ あ’)
Enter←’ あ’（全角文字）の文字コードの取得
12354←得られた文字コード（Unicode）

39 文字列型 (str) はイミュータブル（変更不可）なので当然であるとも言える．
40 後の「Unicode の文字符号化モデル」（p.38）で述べる．
41 詳しくは Unicode の公式インターネットサイト The Unicode Consortium （http://www.unicode.org/）で公開されている情報を参照のこと．

37

例．文字コードに対応する文字の取得>>> chr(97)
Enter
’a’
←得られた文字←文字コード 97（10 進数）に対応する文字の取得←文字コード 12354（10 進数）に対応する文字（Unicode）の取得>>> chr(12354)
Enter
’ あ’
←得られた文字■ 文字の種別の調査

標準モジュールの unicodedata を使用すると文字の種別を判定することができる．具体的にはこのモジュールのname 関数を使用して，指定した文字の名前（文字の属性）を取得する．
例．文字の種別の判定←モジュールの読み込みEnter>>> import unicodedata>>> unicodedata.name(’a’)’LATIN SMALL LETTER A’

Enter← ’a’ の判定
←判定結果：「半角英数小文字」>>> unicodedata.name(’A’)’LATIN CAPITAL LETTER A’

Enter← ’A’ の判定
←判定結果：「半角英数大文字」>>> unicodedata.name(’ ア’)
Enter’HALFWIDTH KATAKANA LETTER A’← ’ ア’ の判定←判定結果：「半角カタカナ」>>> unicodedata.name(’ あ’)’HIRAGANA LETTER A’Enter← ’ あ’ の判定←判定結果：「全角ひらがな」>>> unicodedata.name(’ ア’)’KATAKANA LETTER A’Enter← ’ ア’ の判定←判定結果：「全角カタカナ」>>> unicodedata.name(’ 中’)Enter← ’ 中’ の判定’CJK UNIFIED IDEOGRAPH-4E2D’←判定結果：「全角漢字」
name 関数の戻り値を構成する語の意味などについては Unicode の公式インターネットサイトを参照のこと．

■ Unicode の文字符号化モデル

Unicode は文字コード 0〜1114111（16 進数で 0〜10FFFF）の範囲で定義されており，特に Unicode においては文字に対する整数値（文字コード）のことを「コードポイントの値」と呼ぶ．本書執筆時点では，この範囲の全てのコー
ドポイントに対しては Unicode 文字は割り当てられていない．例えば，コードポイントの最大値 1114111 の Unicode
文字を調べようとすると次のようになる．
試み）コードポイント 1114111 の Unicode 文字について調べる>>> c = chr(1114111)

Enter←コードポイント 111411 の文字を c に取得>>> print( c )Enter←表示を試みる・・←不可解な表示（文字が割り当てられていない）>>> unicodedata.name(c)Enter← name 関数でこの文字の属性を調べてみるとTraceback (most recent call last):←文字が定義されておらずFile "<stdin>", line 1, in <module>
エラーとなる
ValueError: no such namename 関数の第 2 引数には例外時（文字が割り当てられていない場合）の戻り値を与えることができ，これによりエラー（例外）の発生を回避できる．
先の試みの続き）>>> unicodedata.name(c,’ 未定義です’)’ 未定義です’←結果表示←再度 name 関数でこの文字の属性を調査Enter参考）使用できる全ての Unicode 文字を列挙するサンプルプログラムを「I.6 全ての Unicode 文字の列挙」（p.435）に示す．

Unicode のコードポイントの値を記憶媒体上で表現するには 1 バイトでは不十分である．従って日本語をはじめとする全角文字を表現するには複数バイトの記憶領域が必要42 となる．実際に Unicoe のコードポイントの値をどの
42 このことにより，全角文字はマルチバイト文字（多バイト文字）であると言われる．

38

ような形で記憶媒体上のバイト列として符号化するかは「Unicode の文字符号化方式」（CEF）として規定されており，文字符号化方式の具体的なもの（文字符号化スキーム：CES）として，UTF-8，UTF-16，UTF-16LE，UTF-16BE，

UTF-32，UTF-32LE，UTF-32BE がある．Python 言語では Unicode の CES をはじめ様々なエンコーディングに対応している．
ここで述べたような Unicode に関する各種規定（コードポイントの範囲や符号化方式，符号化スキームなど）はUnicode の符号化モデルと呼ばれるものであるが，これの詳細に関する説明は割愛する．詳しくは Unicode の公式
インターネットサイト The Unicode Consortium（http://www.unicode.org/）で公開されている情報を参照のこと．
■ string モジュールに定義されている文字の種別

string モジュールには表 8 に示すような文字の種別の定義がある．
表 8: string モジュールで定義されている半角文字の種別（一部）
定義

内容

定義

内容

ascii lowercase

英小文字ascii uppercase

英大文字

ascii letters

ascii lowercase と ascii uppercaseを合わせたもの

digits

半角数字

hexdigits

16 進数の表記を構成する文字

octdigits

8 進数の表記を構成する文字

printable

印字可能文字whitespace

空白文字

例．表 8 の定義の一部を閲覧する>>> import stringEnter← string モジュールの読込み>>> string.ascii lowercase
Enter← ascii lowercase を表示’abcdefghijklmnopqrstuvwxyz’← ascii lowercase の内容>>> string.digitsEnter← digits を表示’0123456789’← digits の内容
表 8 の定義を利用すると，半角文字の種別の判定ができる．
例．半角文字の種別の判定>>> ’a’ in string.ascii lowercase
True
←真

Enter

←’a’ は小文字か？

>>> ’A’ in string.ascii lowercase
False
←偽

Enter

←’A’ は小文字か？

参考）ここで説明したことに加え，後の「2.6.1.1 出力データの書式設定」（p.89）で説明するフォーマット済み文字
列リテラル（f-string）を利用すると，更に高度な文字列編集が可能となる．

2.3.8

真理値（bool 型）

真理値（bool 型）は真か偽かを現す値で，True, False の 2 値から成る43 ．例えば，両辺の値が等しいかどうかを検査する比較演算子 ’==’ があり，1 == 2 という式は誤りなのでこの式の値は False となる．
（次の例を参照）
例．判定結果を変数に代入する>>> p = 1==2>>> print( p )
False

Enter
Enter

← 1==2 の検査結果を変数 p に与えている．
←変数 p の内容を表示する．
←変数 p の内容が False（偽）であることがわかる．

このように，値の比較をはじめとする条件検査の式は真理値を与えるものであり，「2.5 制御構造」（p.75）のところで条件判定の方法として解説する．
参考）真理値と数値の間の演算
数値の計算に真理値を使用すると，True は 1，False は 0 として扱われる．
43 bool は int のサブクラスである．詳しくは「4.28 Python の型システム」（p.323）を参照のこと．

39

例．真理値と数の演算>>> 1.2 + True
Enter
2.2
← True は 1 とみなされる>>> False * 5.0
Enter
0.0
← False は 0 とみなされる
ヌルオブジェクト：

2.3.9

None

ヌルオブジェクトは「値を持たない」ことを意味する特殊なオブジェクトであり，None と記述する．
例．ヌルオブジェクト

>>> a
Enter
←未設定の記号（変数）a を参照するとエラーが発生する
Traceback (most recent call last):←以下，エラーメッセージ
File "<stdin>", line 1, in <module>
NameError: name ’a’ is not defined>>> a = NoneEnter

← a にヌルオブジェクトを設定

Enter
←内容確認
←何も表示されない（しかし，a はヌルオブジェクトを保持している）

>>> a
>>>

None は print 関数で出力すると「None」と出力される．
例．print 関数による None の出力（先の例の続き）

Enter>>> print( a )None
2.3.10型の変換

代表的な値の型として数値，文字列，真理値があるが，これら異なる型の間でデータを変換するには，型 (値)とする44 ．型の変換処理の例を表 9 に挙げる．

変換元のデータ

整数へ

表 9: 型の変換の例
浮動小数点数へ
文字列へ

整数
浮動小数点数int(3.1) → 3

ﬂoat(3) → 3.0-

str(3) → ’3’str(3.1) → ’3.1’

bool(3) → Truebool(3.1) → True
0 や 0.0 は False となる

文字列

int(’2’) → 2

ﬂoat(’2.1’) → 2.1-bool(’a’) → True

真理値へ

bool(’True’) → Truebool(’False’) → True (注意!)空文字列 ’ ’ は False となる
真理値

2.3.10.1

int(True) → 1
int(False) → 0

ﬂoat(True) → 1.0
ﬂoat(False) → 0.0

str(True) → ’True’
str(False) → ’False’-

各種の値の文字列への変換（str，repr）

各種の型の値を文字列に変換する45 には表 9 で示した str を使用する．
例．int，ﬂoat の値を文字列に変換する>>> str( 2 )
’2’

Enter
←整数の 2 を文字列に変換←変換結果>>> str( 3.14 )’3.14’

Enter←浮動小数点数の 3.14 を文字列に変換←変換結果

また，str とは別に repr もある．
44 この方法は，クラスのコンストラクタによってオブジェクトを生成する機能によるものである．詳しくは「2.8 オブジェクト指向プログラミング」（p.136）で解説する．
45 データをファイルに出力する場合や通信路に送出する場合などにおいて多用する処理である．

40

例．repr による文字列への変換>>> repr( 2 )
’2’

Enter

>>> repr( 3.14 )’3.14’←整数の 2 を文字列に変換
←変換結果

Enter
←浮動小数点数の 3.14 を文字列に変換←変換結果

一見すると repr は str と同じ処理をするかのように見えるが，より複雑なオブジェクトを文字列に変換する場合にその違いがわかる．次の例は mpmath の mpf オブジェクトを文字列に変換するものである．
例．mpmath の mpf オブジェクトを文字列に変換する←演算精度の設定

Enter>>> mp.dps = 60

←モジュールの読み込みEnter>>> from mpmath import mp← mpf オブジェクトによる 30! の計算

Enter>>> x = mp.factorial(30)>>> str( x )Enter’265252859812191058636308480000000.0’← str による文字列への変換←変換結果>>> repr( x )Enter"mpf(’265252859812191058636308480000000.0’)"← repr による文字列への変換←変換結果

このように，repr は元のデータ型がわかる形で文字列に変換する．

2.3.11型の検査

type 関数を用いるとデータの型を調べることができる．
例．type 関数による型の検査>>> type( 2 )<class ’int’>←整数値の型を調べる←「整数」を表す型

Enter←浮動小数点数の型を調べる←「浮動小数点数」を表す型>>> type( 3.14 )<class ’float’>Enter>>> type( ’abc’ )<class ’str’>Enter←文字列の型を調べる←「文字列」を表す型>>> type( [1,2,3] )<class ’list’>Enter←リストの型を調べる←「リスト」46 を表す型

この例が示すように，‘<class 型名>’ という形式で型の種類が得られる．また，is 演算子47 を用いてtype(値) is 型名という判定も可能48 であり，判定結果が真理値として得られる．
（次の例）
例．type 関数と is 演算子による型の検査>>> type( 2 ) is int
True←整数値「2」が int 型かどうかの検査
←真

Enter

>>> type( 2 ) is float
False←整数値「2」が ﬂoat 型かどうかの検査
←偽

Enter

型の検査には isinstance 関数を用いる方法もある．
書き方：

isinstance( オブジェクト, 型名 )「オブジェクト」の型（クラス）が「型名」の場合に True を，そうでない場合に False を返す．
例．isinstance 関数による型の検査>>> isinstance( 3, int )
True

Enter

>>> isinstance( 3.14, int )False← 3 は int 型か←真：int 型である

Enter

← 3.14 は int 型か←偽：int 型ではない

46 リストに関しては「2.4.1 リスト」
（p.46）で説明する．
47 is に関しては後の「2.5.4.4 is 演算子による比較」（p.87）で説明する．
48 この方法で多くの種類のオブジェクトの型を判定可能であるが，「型名」として指定できないものもあるので，各種のケースについて試していただきたい．

41

ﬂoat の値が整数値かどうかを検査する方法

2.3.11.1

ﬂoat の値が整数値（小数点以下が 0 である値）かどうかを判定するには is integer メソッドを使用する．
例．is integer メソッドによる判定

Enter>>> a = 3.0>>> type(a)Enter<class ’float’>>>> a.is integer()
True
Enter

>>> a = 3.14>>> type(a)Enter<class ’float’>>>> a.is integer()False← ﬂoat 型の 3.0 を変数 a に設定←型の検査← ﬂoat 型である

Enter

←値が整数値かどうか検査←整数値である← ﬂoat 型の 3.14 を変数 a に設定←型の検査← ﬂoat 型である

Enter

←値が整数値かどうか検査←整数値ではない

このように判定結果が真理値で得られる．
注）Python 3.11 の版までは，int 型のオブジェクトに対しては is integer メソッドは定義されておらず，使用することができない．
例．Python 3.11 での int 型変数に対する is integer メソッドの試み（Windows 環境）

C:￥Users￥katsu>py -3.11← Python 3.11 を起動

Python 3.11.9 (tags/v3.11.9:de54cf5, Apr 2 2024, 10:12:12) [MSC v.1938 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

>>> a = 3Enter>>> type(a)Enter<class ’int’>>>> a.is integer()← int 型の 3 を変数 a に設定←型の検査← int 型である

Enter

← is integer を試みると…

Traceback (most recent call last):← そのようなメソッドは使えないという旨のFile "<stdin>", line 1, in <module>
エラーメッセージが表示される
AttributeError: ’int’ object has no attribute ’is integer’
例．Python 3.12 以降では int 型変数に対する is integer メソッドが有効（Windows 環境）

C:￥Users￥katsu>py -3.12← Python 3.12 を起動

Python 3.12.7 (tags/v3.12.7:0b05ead, Oct 1 2024, 03:06:41) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

>>> a = 3Enter>>> type(a)Enter<class ’int’>>>> a.is integer()True
2.3.122.3.12.1← int 型の 3 を変数 a に設定←型の検査← int 型である

Enter

← is integer を試みると…

←結果が得られる

基数の変換

n 進数→ 10 進数

int 関数49 の第 2 引数に基数を指定すると，文字列として記述された10 進数以外の表現の数値を整数値に変換できる．
例．2 進数→ 10 進数の変換>>> int(’1111’,2)Enter
15←変換結果（整数）>>> int(’0b1111’,2)Enter
15←変換結果（整数）← 2 進数の ’1111’ を 10 進数に変換← 2 進数の接頭辞 ’0b’（ゼロビー）も使用可能

49 正確には int コンストラクタ．

42

例．8 進数→ 10 進数の変換>>> int(’77’,8)Enter
63←変換結果（整数）← 8 進数の ’77’ を 10 進数に変換← 8 進数の接頭辞 ’0o’（ゼロオー）も使用可能>>> int(’0o77’,8)Enter
63←変換結果（整数）例．16 進数→ 10 進数の変換>>> int(’FF’,16)
Enter
255
←変換結果（整数）← 16 進数の ’FF’ を 10 進数に変換← 16 進数の接頭辞 ’0x’（ゼロエックス）も使用可能>>> int(’0xFF’,16)
Enter
255
←変換結果（整数）
10 進数→ n 進数

2.3.12.2

10 進数の整数値を別の基数表現の文字列に変換する次のような関数がある．
働き

10 進数→ 2 進数

10 進数→ 8 進数

10 進数→ 16 進数

関数名

bin

oct

hex

これら関数は第 1 引数に整数値を取る．
例．10 進数を他の基数表現に変換する>>> bin(15)Enter← 15 を 2 進数表現の文字列に変換’0b1111’←変換結果（文字列）>>> oct(15)Enter← 15 を 8 進数表現の文字列に変換’0o17’←変換結果（文字列）>>> hex(15)Enter← 15 を 16 進数表現の文字列に変換’0xf’←変換結果（文字列）参考）浮動小数点数（ﬂoat 型）から 2 進数への変換とその逆の変換を行うサンプルプログラムを巻末付録「I.5 浮動小数点数と 2 進数の間の変換」（p.433）で示す．
参考）mpmath ライブラリを用いると高い精度で 2 進数の表現を得ることができる．これに関しては
p.23「【参考】浮動小数点数の 2 進数表現」を参照のこと．

2.3.13

ビット演算

表 10 に整数のビット演算の書き方を示す．
表 10: ビット演算のための演算子
演算
説明

演算

説明

x&y

x と y の論理積x|yx << nx を左に n ビットシフト

x >> n演算

説明

x と y の論理和xˆyx と y の排他的論理和

x を右に n ビットシフト

˜x

x をビット反転（1 の補数）

注）ここで言う論理積，論理和，排他的論理和はビット毎の演算を意味する．

ビット演算は桁の長い整数に対しても実行できる．
例．ビット毎の論理積>>> a = int(’11111111’,2)Enter← 2 進数表現で値を生成 (1)>>> b = int(’11110000’,2)Enter← 2 進数表現で値を生成 (2)>>> c = a & b

Enter>>> print( bin(c) )Enter0b11110000←結果表示←上記 2 つの数の論理積← 2 進数表現に変換

43

例．ビット毎の論理和>>> a = int(’00001111’,2)Enter← 2 進数表現で値を生成 (1)>>> b = int(’11110000’,2)Enter← 2 進数表現で値を生成 (2)>>> c = a | b←上記 2 つの数の論理和

Enter← 2 進数表現に変換>>> print( bin(c) )Enter0b11111111←結果表示
例．ビット毎の排他的論理和>>> a = int(’11111111’,2)Enter← 2 進数表現で値を生成 (1)>>> b = int(’10101010’,2)Enter← 2 進数表現で値を生成 (2)>>> c = a ^ b←上記 2 つの数の排他的論理和

Enter← 2 進数表現に変換>>> print( bin(c) )Enter0b1010101←結果表示
例．左に n ビットシフト（2n 倍）>>> a = int(’1’,2)Enter← 2 進数表現で値を生成>>> print( a << 1 )
2
←結果表示

Enter

←左に 1 ビットシフト（2 倍）>>> print( a << 2 )
4
←結果表示

Enter

←左に 2 ビットシフト（4 倍）>>> print( a << 3 )
8
←結果表示

Enter

←左に 3 ビットシフト（8 倍）

例．右に n ビットシフト（1/2n 倍）>>> a = int(’1000’,2)Enter← 2 進数表現で値を生成>>> print( a >> 1 )
4
←結果表示

Enter

←右に 1 ビットシフト（1/2 倍）>>> print( a >> 2 )
2
←結果表示

Enter

←右に 2 ビットシフト（1/4 倍）>>> print( a >> 3 )
1
←結果表示

Enter

←右に 3 ビットシフト（1/8 倍）

例．ビット反転（1 の補数）>>> a = int(’1’,2);
-0b10
←結果表示

b = ~a; print( bin(b) )Enter← 2 進数表現の ’1’ をビット反転>>> a = int(’11’,2);-0b100←結果表示

b = ~a; print( bin(b) )Enter← 2 進数表現の ’11’ をビット反転>>> a = int(’111’,2); b = ~a; print( bin(b) )-0b1000
←結果表示

Enter

← 2 進数表現の ’111’ をビット反転‘˜’ によるビット反転は，計算結果と元の値の和が -1 となる形で実行される．
課題）int(’0’,2) や int(’00’,2) を ‘˜’ でビット反転するとどのような結果になるかを確認せよ．
また，何故そのような結果となるか考察せよ．

2.3.13.1

ビット演算の累算代入

変数に格納された値そのものを変更する形でビット演算を実行することができる．
（下記参照）

x &= y は x = x & y と同じ，x |= y は x = x | y と同じ，

x ˆ= y は x = x ˆ y と同じ，

x <<= y は x = x <<y と同じ， x >>= y は x = x >>y と同じ，
2.3.13.2

整数値のビット長を求める方法

与えられた整数値を表現するのに最低限必要なビット長を調べるには bit length メソッドを使用する．

44

例．1023 を表現するのに最低限必要なビット数を求める>>> a = 1023

← int 型の 1023 を変数 a に設定

Enter←ビット長を調べる← 10 ビットの長さ>>> a.bit length()
10

Enter

>>> bin(a)Enter’0b1111111111’←実際に 1023 を 2 進数に変換して確認する← 2 進数で 10 桁（10 ビットの長さ）

注）bit length メソッドは ﬂoat 型に対しては使用できない．

2.3.14

バイト列

計算機の記憶資源上のバイトデータの並びを表現するためのデータ型として bytes 型がある．様々なデータを入出力や通信に使用する際に，対象のデータをこの型のオブジェクトに変換して取り扱うことが多い．

bytes 型のデータは先頭に b を伴う引用符で括る形式で表現され，引用符の中は 16 進数で表記する．
例．bytes 型の表現>>> b = b’￥x01￥xff’
>>> b
Enter
b’￥x01￥xff’← bytes 型のデータの表記

Enter

←内容確認

このように bytes 型の値は，1 バイトずつの 16 進数 00〜ﬀ の先頭に ￥ を付けて書き並べる．
整数値をバイト列に変換するには to bytes メソッドを使用する．
書き方：

整数値.to bytes( バイト長, バイトオーダー )「整数値」を指定した「バイトオーダー」50 の順（’big’ もしくは ’little’）で「バイト長」の長さの bytes オブジェク
トに変換して返す．
例．整数値を bytes オブジェクトに変換する

Enter>>> a = 2882400000>>> b = a.to bytes(4,’big’)>>> b←この整数値をEnter← 4 バイトのバイト列に変換する

←確認

Enter

b’￥xab￥xcd￥xef￥x00’←このようなバイト列になっている

念のため，この例で用いた a の値を hex 関数で確認する．
例．hex 関数による確認（先の例の続き）

Enter>>> hex(a)’0xabcdef00’←先の例と同じ 16 進値になっている

バイト列を整数値に変換するには int.from bytes を使用する．
書き方：

int.from bytes( バイト列, バイトオーダー )指定した「バイトオーダー」で「バイト列」を整数値に変換して返す．
例．バイト列を整数値に変換する（先の例の続き）>>> int.from bytes(b,’big’)
2882400000

Enter←先の a の値と同じ文字列をバイト列に変換する方法については後の「2.6.3.4 バイト列の扱い」（p.98）で解説する．また，バイト列の内容を様々なデータ形式として読み取る方法については「4.11.2 バイナリデータの展開」（p.282）で解説する．

bytes 型のオブジェクトは事後に変更不可能51 である．そのため，編集可能なバイト列として bytearray 型がある．
これに関しては「4.13 編集可能なバイト列： bytearray」（p.285）で解説する．
50 バイトオーダーに関しては後の「4.11.3 バイトオーダーについて」（p.282）で解説する．
51 イミュータブルであるという．

45

データ構造2.4

ここでは，複数のデータ要素を保持するデータ構造について解説する．具体的にはリスト，タプル，セット，辞書（それらをまとめてコンテナと呼ぶ）について解説する．
リスト

2.4.1

複数のデータの並び（要素の並び）をリストとして表すことができる．要素の区切りにはコンマ「,」を使用する．
例えば，0〜9 の数を順番に並べたものはリストとして[0,1,2,3,4,5,6,7,8,9]と表すことができる．このようにリストは ’[’ と ’]’ で括ったデータ構造である．リストの要素としては任意の型のデータを並べることができる．例えば，[’nakamura’,51,’tanaka’,22,’hashimoto’,14]のように，型の異なるデータが要素として混在するリストも作成可能である．また，リストを要素として持つリストも作成可能であり，例えば，[’a’,[’b’,’c’],’d’]といったリストも作成することができる．
要素を持つリストの末尾には余分なコンマが 1 つ存在しても良い．
例．末尾の余分なコンマ>>> [1,2,3][1, 2, 3]

Enter←要素を持つリスト←問題ない>>> [1,2,3,][1, 2, 3]

Enter←末尾に余分なコンマが 1 つある場合は←余分なコンマは無視される>>> [1,2,3,,]Enter←末尾に余分なコンマが複数ある場合はFile "<stdin>", line 1←エラーとなる[1,2,3,,]^ invalid syntax
SyntaxError:
2.4.1.1

空リスト

要素を持たない空リストは [ ] と記述する．これはヌルオブジェクト None とは異なる．空リストは list 関数52 に引数を与えずに「list()」として評価することでも得られる．

2.4.1.2

リストの要素へのアクセスリストの要素を取り出すには，取り出す要素の位置を示すインデックスを ’[...]’ で括って53 指定する．これは次の例を見ると理解できる．
例．スライスの指定による要素の参照>>> lst = [2,4,6,8,10]>>> lst[1]
4

Enter

Enter

←リストの生成← 1 番目の要素を指定←対象の要素が表示されている

このようにリストの要素は 0 番目から始まる位置（インデックス）を指定してアクセスすることができる．
リストの中の，インデックスで指定した特定の範囲（部分リスト）を取り出すこともできる．
例．部分リストの取り出し>>> lst = [2,4,6,8,10]>>> lst[1:4][4, 6, 8]

Enter

Enter

←リストの生成←部分リスト（1〜4-1 番目）の取り出し←部分リストが得られている

この例のように，コロン ’:’ でインデックスの範囲を指定するが，[n1 :n2 ] と指定した場合は，n1 〜(n2 − 1) の範囲の部分を示していることに注意しなければならない．
52 正確には list コンストラクタという．
53 ’[...]’ の部分をスライスと呼び，文字列をはじめとする多くのデータ構造で同様の扱いができる．

46

リストの要素にアクセスするためのスライスにはインデックスの増分を指定することができる．
例．飛々のインデックス指定による要素の取り出し>>> lst = [0,1,2,3,4,5,6,7]>>> lst[1:6:2][1, 3, 5]Enter←リストの生成←飛々のインデックス指定←得られたリスト

Enter

この例のようにスライスを [n1 :n2 :n3 ] と記述して n3 にインデックスの増分を与えることができる．これに関しては後の「2.4.5.4 不連続な部分の取り出し」（p.70）で更に詳しく説明する．
リストを用いることで，複数の要素を持つ複雑な構造を 1 つのオブジェクトとして扱うことができる．この意味で，
リストは複雑な情報処理を実現するに当たって非常に有用なデータ構造である．

2.4.1.3

リストの編集リストは要素の追加や削除を始めとする編集ができるデータ構造である．リストを編集するための基本的な機能について解説する．
● 要素の書き換え
リストの指定したインデックスの要素を直接書き換えることができる．
例．リストの要素の書き換え (1)>>> lst = [0,1,2,3,4,5]>>> lst[3] = ’x’←リストの作成

Enter← 3 番目の要素を’x’ に変更

Enter>>> lstEnter←内容確認[0, 1, 2, ’x’, 4, 5]←要素が変更されている
例．リストの要素の書き換え (2)>>> lst[2:4] = [’a’,’b’]（先の例の続き）← 2〜3 番目の要素を書き換えるEnter>>> lstEnter←内容確認[0, 1, ’a’, ’b’, 4, 5]←変更結果● 要素の追加
リストに対して要素を末尾に追加するには append メソッドを使用する．
例．リストへの要素の追加>>> lst = [’x’,’y’]Enter←リストの作成>>> lst.append(’z’)

Enter←要素の追加>>> lst

Enter

←内容確認

[’x’, ’y’, ’z’]

←要素が追加されている

これは，リスト lst の末尾に要素’z’ を追加している例である．
《 オブジェクトに対するメソッドの適用 》

Python ではオブジェクト指向の考え方に則って，作用対象オブジェクト. メソッドというドット ’.’ を用いた書き方で，メソッドをオブジェクトに対して適用する．
先の例ではリスト lst に対して，メソッド append(’z’) を適用している．
《 リストへの要素の追加 》
書き方：

対象リスト.append(追加する要素)「対象リスト」そのものが変更される．
．

47

● 要素の挿入
リストの指定した位置に要素を挿入するには insert メソッドを使用する．
例．リストの指定した位置に要素を挿入>>> lst = [’a’,’c’,’d’]←リストの作成

Enter←要素の挿入Enter>>> lst.insert(1,’b’)>>> lstEnter←内容確認[’a’, ’b’, ’c’, ’d’]

←要素が挿入されている

これは，リスト lst の 1 番目に要素’b’ を挿入している例である．
● リストの連結 (1)演算子 ’+’ によって複数のリストを連結し，結果を新しいリストとして作成することができる．
例．リストの連結>>> lst1 = [’a’,’b’]Enter←リストの作成 (1)>>> lst2 = [’c’,’d’]Enter←リストの作成 (2)>>> lst3 = [’e’,’f’]Enter←リストの作成 (3)←リストの連結Enter>>> lst4 = lst1 + lst2 + lst3>>> lst4
Enter
←内容確認
[’a’, ’b’, ’c’, ’d’, ’e’, ’f’]

← 3 つのリストが連結されている’+’ によるリストの連結処理において重要なことに，連結結果が新たなリストとして生成されているということがある．すなわち，この例においてリスト lst1,lst2,lst3 の内容は処理の前後で変更はなく，連結結果のリストが新
たなリスト lst4 として生成されている．
● リストの連結 (2)’+’ によるリストの連結処理とは別に，与えられたリストを編集する形でリストを連結することも可能である．
《 extend メソッドによるリストの連結 》- リストの拡張 書き方： 対象リスト.extend(追加リスト)「対象リスト」の末尾に追加リストを連結する．結果として対象リストそのものが拡張される．
例．リストの拡張>>> lst = [’a’,’b’,’c’]←リストの作成

Enter
Enter

>>> lst.extend([’d’,’e’,’f’])>>> lstEnter←内容の確認[’a’, ’b’, ’c’, ’d’, ’e’, ’f’]Enter

←リストの拡張←リストが拡張されている● リストの繰り返し’*’ 演算子によってリストの繰り返しを取得することができる．
例．リストの繰り返し>>> lst = [1,2,3]

Enter←このリストを>>> lst * 3Enter← 3 回繰り返す[1, 2, 3, 1, 2, 3, 1, 2, 3]←処理結果● リストの要素の削除
リストの特定のインデックスの要素を削除するには del 文を使用する．
《 del 文によるリストの要素の削除 》
書き方：

del

削除対象のオブジェクト

削除対象のオブジェクトを削除する．
リストの指定した 1 つの要素を削除するには次の例のようにする．

48

例．指定した要素を削除>>> lst = [2,4,6,8,10]←リストの作成

Enter←リストの 1 番目の要素の削除>>> del lst[1]Enter>>> lstEnter[2, 6, 8, 10]←内容確認←リストの要素が削除されている同様の方法で，リストの中の指定した部分を削除することもできる．
（次の例）
例．指定した範囲の削除>>> lst = [2,4,6,8,10]>>> del lst[1:4]>>> lst[2, 10]←リストの作成

Enter

Enter

←リストの 1〜(4-1) 番目の要素の削除

Enter
←内容確認
←指定した範囲の要素が削除されているリストから指定した値の要素を取り除くには remove メソッドを使用する．
《 remove メソッドによる要素の削除 》
書き方： 削除対象リスト.remove(値)
削除対象リストの中の指定した値の要素を削除する．削除対象の値の要素が複数存在する場合は，最初に見つかった要素を 1 つ削除する．
例．remove メソッドによる要素の削除>>> lst = [’a’,’b’,’c’,’b’,’a’]>>> lstEnter←内容確認[’a’, ’c’, ’b’, ’a’]
2.4.1.4←リストの作成←’b’ という値の要素を削除

Enter>>> lst.remove(’b’)

Enter←最初の’b’ が削除されているリストによるスタック，キューの実現：

pop メソッド

リストの特定のインデックスの要素を取り出した後に削除するメソッド pop がある．
《 pop メソッドによる要素の取り出しと削除 》
書き方： 対象リスト.pop(インデックス)
対象リストの中の指定したインデックスの要素を取り出して削除する．このメソッドを実行すると，削除した要素を返す．また pop の引数を省略すると，末尾の要素が対象となる．

pop メソッドを用いると，スタック（FILO）やキュー（FIFO）といったデータ構造が簡単に実現できる．
例．pop メソッドによるスタック>>> lst = []←空のリストを作成

Enter>>> lst.append(’a’)

Enter← lst の末尾に要素’a’ を追加>>> lst.append(’b’)

Enter← lst の末尾に要素’b’ を追加>>> lst.append(’c’)

Enter← lst の末尾に要素’c’ を追加← lst の内容を確認する←要素が蓄積されていることがわかる>>> lstEnter[’a’, ’b’, ’c’]>>> lst.pop()
’c’

Enter

← lst の末尾の要素を取り出す← lst の末尾の要素が得られた>>> lst.pop()
’b’

Enter

← lst の末尾の要素を取り出す← lst の末尾の要素が得られた>>> lst.pop()
’a’

Enter

← lst の末尾の要素を取り出す← lst の末尾の要素が得られた>>> lst[]Enter← lst の内容を確認←空になっている49

参考．上の例で lst.pop(0) として実行するとキューが実現できる．また，後の「4.15.1 deque」（p.288）で説明する deque を使用すると，列の回転が簡単に実現できる．

2.4.1.5

リストに対する検査

リストに対する各種の検査方法について説明する．
● 要素の存在検査
リストの中に，指定した要素が存在するかどうかを検査する in 演算子がある．
《 in 演算子によるメンバシップ検査 》
書き方： 要素 in リスト
リストの中に要素があれば True，なければ False を返す．要素が含まれないことを検査するには not in と記述する．
例．in によるメンバシップ検査>>> lst = [’a’,’b’,’c’,’d’]←リストの作成

Enter>>> ’c’ in lst
True

Enter

←’c’ が lst に含まれるか←含まれる>>> ’e’ in lst
False

Enter

←’e’ が lst に含まれるか←含まれない>>> ’e’ not in lst
True

Enter

←’e’ が lst に含まれないか←含まれない● 要素の位置の特定リストの中に，指定した要素が存在する位置を求めるには index メソッドを用いる．
《 index メソッドによる要素の探索 》
書き方 1： 対象リスト.index(要素)「対象リスト」の中に「要素」が最初に見つかる位置（インデックス）を求める．
書き方 2： 対象リスト.index(要素, p1 , p2 )p1 以上 p2 未満のインデックス範囲で「要素」が最初に見つかる位置を求める．p2 を省略すると末尾までが探索の対象となる．
要素が見つからなければ index メソッドはエラーとなる．
例．index メソッドによる要素の探索Enter>>> lst = [’a’,’b’,’c’,’d’,’a’,’b’,’c’,’d’]>>> lst.index(’c’)
2←リストの作成←’c’ の位置を求める←インデックス 2 の位置に最初の ’c’ が存在する

Enter

例．開始位置を指定して探索>>> lst.index(’c’,3)
6

Enter

←インデックス位置 3 以降で ’c’ の位置を求める←インデックス 6 の位置に ’c’ が存在する

探索する要素が対象リストに含まれていない場合，このメソッドの実行は次の例のようにエラーとなる．
例．要素が含まれていない場合に起こるエラー>>> lst.index(’e’)

Enter

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: ’e’ is not in list←’e’ の位置を求める←以下，エラーメッセージ

これは ValueError という種類のエラーである．探索範囲内に目的の要素が見つからない場合も同様のエラーとなる．

50

例．指定した範囲内に要素が見つからない場合のエラー>>> lst.index(’c’,0,2)

Enter

←

インデックス 0 以上 2 未満の範囲で ’c’ の位置を求める

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: ’c’ is not in list

←以下，エラーメッセージ

Python では，エラーが発生する可能性のある処理を行う場合は，適切に例外処理の対策をしておくべきである．例
えば次のようなサンプルプログラム test03.py のような形にすると良い．
プログラム：test03.py
1
2
3
4
5
6
7
8

# coding : utf -8
lst = [ ’a ’ , ’b ’ , ’c ’ , ’d ’]
try :n = lst . index ( ’e ’)print (n ," 番 目 に あ り ま す ． " )except ValueError :print (" 要 素 が 見 つ か り ま せ ん … " )プログラムの 4 行目にある try は，エラー（例外）を発生する可能性のある処理を指定するための文である．すなわ
ち 5,6 行目で例外が発生した場合は except 以下のプログラムに実行が移る．
（処理系の動作は中断しない54 ）2.4.1.6

例外処理《 例外処理のための try と except 》
書き方：

try:
（例外を起こす可能性のある処理）
except エラー（例外）の種類:（例外を起こした場合に実行する処理）
except:（上記以外の例外を起こした場合に実行する処理）
ﬁnally:（全ての except の処理の後に共通して実行する処理）

except は複数記述することができる．
先のプログラム test03.py を実行すると次のような結果となる．

py test03.py

Enter

要素が見つかりません…

OS のコマンドからプログラムを実行
結果の表示

5 行目の index メソッドの引数を様々に変更して実行を試みられたい．例外処理に関して後の「4.18 例外（エラー）の処理」（p.299）で更に詳しく解説する．

2.4.1.7

要素の個数のカウント

リストは同じ要素を複数持つことができるが，指定した要素（値）がリストにいくつ含まれるかをカウントするメ
ソッド count がある．
《 count メソッドによる要素のカウント 》
書き方： 対象リスト.count(要素)「対象リスト」の中の「要素」の個数を求める．

54 更に p.299「4.18 例外（エラー）の処理」では，システムが生成する例外やエラーに関するメッセージを文字列型データとして取得する方法を

紹介する．

51

例．count メソッドによる要素のカウント>>> lst = [’a’,’b’,’a’,’c’,’a’,’d’]←リストの作成

Enter>>> lst.count(’a’)
3

Enter

←’a’ の個数を求める← 3 個ある>>> lst.count(’e’)
0

Enter

←’e’ の個数を求める← 0 個（含まれない）

リストの長さ（全要素の個数）を求めるには len 関数を使用する．
《 リストの長さ 》
書き方：

len(対象リスト)

対象リストの長さ（全要素の個数）を求める．
例．len 関数によるリストの長さの取得>>> lst = [1,2,3,4,5]>>> len(lst)
5

Enter

←リストの作成←長さの算出← 5 個の要素を持つ

Enter

参考．後の「2.9.3 ﬁlter」（p.160）で説明する ﬁlter 関数と len 関数を応用すると，条件を満たす要素のカウント55が実現できる．サンプルを countif01.py に示す．
プログラム：countif01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8# 条件付きカウントの例# 偶数かどうかを判定する関数の定義
def isEven ( n ):return n %2 == 0
# 奇数かどうかを判定する関数の定義
def isOdd ( n ):return n %2 != 0
# テストデータのリスト
lst = [1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9]print ( ’ デ ー タ リ ス ト : ’ , lst )# 偶数である要素の個数
c = len ( list ( filter ( isEven , lst ) ) )print ( ’ 偶 数 で あ る 要 素 の 個 数 : ’ , c )# 奇数である要素の個数
c = len ( list ( filter ( isOdd , lst ) ) )print ( ’ 奇 数 で あ る 要 素 の 個 数 : ’ , c )このプログラムでは条件付きカウントの実現に「指定した条件を満たす要素を取り出して，その個数を調べる」という方法を採っている．このプログラムを実行すると次のようになる．
データリスト: [1, 2, 3, 4, 5, 6, 7, 8, 9]
偶数である要素の個数: 4奇数である要素の個数: 5

プログラム中で def 文による関数定義をしているが，これに関しては「2.7 関数の定義」（p.122）で解説する．
課題．後の「2.5.1.7 for を使ったデータ構造の生成（要素の内包表記）」（p.78）で解説する条件付きの内包表記を使用して countif01.py と同等の処理をするプログラム countif01-2.py を作れ．

2.4.1.8

要素の合計：

sum 関数

リストの要素が数値である場合，sum 関数を用いることで全要素の合計を求めることができる．
55 表計算ソフト Microsoft Excel に備わっている COUNTIF 関数と似た機能

52

例．要素の合計>>> lst = [1,2,3,4,5]>>> sum( lst )
Enter
15
←合計の値
2.4.1.9

要素の整列 (1)：

←リストの作成

Enter

←合計処理

sort メソッド

リストの要素を整列するには sort メソッドを使用する．
例．リストの要素の整列>>> lst = [8,3,2,7,5,6,9,1,4]>>> lst.sort()←リストの作成

Enter←整列の実行

Enter

←内容確認
←整列されている>>> lstEnter[1, 2, 3, 4, 5, 6, 7, 8, 9]

これは，要素の大小を基準にして並べ替えを実行した例である．sort メソッドは対象となるリストそのものを変更する．
順序の比較の基準を明に指定するには，sort メソッドにキーワード引数56 ‘key=比較対象のキーを求める関数の名前’を与える．例えば次の例について考える．
例．複雑なリストの並べ替え>>> lst = [ [1,’c’], [2,’b’], [3,’a’] ]>>> lst.sort()←複雑なリストEnter←これを単純に整列してみる

Enter

←内容確認
←変化が見られない>>> lstEnter[[1, ’c’], [2, ’b’], [3, ’a’]]

この例では整列の処理の後でもリストの要素の順番に変化が見られない．これは，リストの各要素を構造的に（素朴に）比較したことによる．次に，リストの各要素の 2 番目の要素（インデックスの [1] 番目）のアルファベットの部
分を基準に整列することを考える．
（次の例）
例．各要素のアルファベットの部分を基準にして整列する（先の例の続き）←インデックスの 1 番目をキーにする整列処理

Enter>>> lst.sort( key = lambda x:x[1] )

←内容確認
←整列結果

>>> lstEnter[[3, ’a’], [2, ’b’], [1, ’c’]]

例の中にある記述 ‘lambda x:x[1]’ は，与えられた x の 2 番目の要素（インデックスの 1 番目）を取り出す lambda
表現である．この部分にはキーを取り出す関数の名前を与えることもできる．lambda と関数に関しては「2.7 関数の定義」（p.122），「2.9.2 lambda と関数定義」（p.159）のところで解説する．
並べ替えの順番を逆にする場合は sort メソッドにキーワード引数 ‘reverse=True’ を与える．
（次の例）
例．逆順の整列>>> lst = [1,2,3,4,5]>>> lst.sort( reverse=True )>>> lstEnter[5, 4, 3, 2, 1]
2.4.1.10

要素の整列 (2)：←リストデータの作成

Enter
Enter

←逆順で整列
←内容確認

←整列結果

sorted 関数

リストの整列結果を別のリストとして取得するには sorted 関数を用いる．
例．リストの要素の整列>>> lst = [8,3,2,7,5,6,9,1,4]

Enter>>> sorted( lst )Enter[1, 2, 3, 4, 5, 6, 7, 8, 9]←リストの作成←整列の実行←整列されている>>> lstEnter←元のリストの内容確認[8, 3, 2, 7, 5, 6, 9, 1, 4]←変更されていない
56 詳しくは「2.7 関数の定義」（p.122）で解説する．

53

この例が示すように，sorted 関数は元のリストを変更しない．

sort メソッドと同様に ‘key=’，‘reverse=’ といったキーワード引数が使用できる．
（次の例参照）
例．‘key=’，‘reverse=’ を指定して整列Enter>>> lst = [ [1,’c’], [2,’b’], [3,’a’] ]>>> sorted( lst, key = lambda x:x[1] )Enter[[3, ’a’], [2, ’b’], [1, ’c’]]←整列結果←逆順で整列Enter>>> sorted( lst, reverse=True )[5, 4, 3, 2, 1]←整列結果
2.4.1.11←インデックスの 1 番目をキーにする整列処理←リストの作成

Enter>>> lst = [1,2,3,4,5]←複雑なリスト

要素の順序の反転リストの要素の順序を反転するには reverse メソッドを使用する．
例．要素の順序の反転←リストの作成

Enter>>> lst = [5,4,3,2,1]←反転の実行Enter>>> lst.reverse()←内容確認←反転されている>>> lstEnter[1, 2, 3, 4, 5]

反転結果を別のデータ（イテレータ）として取得するには reversed 関数を用いる．
例．reversed 関数による要素の順序の反転（先の例の続き）>>> list( reversed( lst ) )Enter[5, 4, 3, 2, 1]←反転されている>>> lstEnter[1, 2, 3, 4, 5]←反転されたイテレータをリストに変換←元のリストの内容確認←変更されていない

イテレータについては「2.5.1.8 イテレータ」（p.78）で説明する．

2.4.1.12

リストの複製

既存のリストの複製には copy 関数を使用する．リストなどのデータ構造に対する処理は対象のデータそのものを改変するものが多い．処理において元のデータの内容を変更したくない場合は，元のデータの複製を作成し，その複製に対して処理を実行するのが良い．
この関数は copy モジュールに含まれるものであり，使用するには copy モジュールをインポートしておく必要がある．
例．リストの複製>>> import copy

← copy モジュールをインポートEnter>>> lst1 = [8,3,2,7,5,6,9,1,4]>>> lst2 = copy.copy(lst1)>>> lst2.sort()

Enter

Enter

Enter

←リストの作成← lst1 の複製を lst2 として作成← lst2 を整列>>> lst2
Enter[1, 2, 3, 4, 5, 6, 7, 8, 9]← lst2 の内容を確認←整列されている>>> lst1
Enter[8, 3, 2, 7, 5, 6, 9, 1, 4]← lst1 の内容を確認←元のままのリストである

ただし，この方法による複製では，要素にリストを持つリストの場合に問題が起こることがある．
（次の例）

54

例．リストを要素に持つリストの複製（先の例の続き）

Enter>>> lst3 = [1,[2,3,4],5,[6,7,8]]>>> lst4 = copy.copy(lst3)>>> lst4[0] = 10

←リストを要素に持つリスト←それを複製するEnter←複製の先頭要素（数値）を改変

Enter>>> lst4
Enter
←内容確認
[10, [2, 3, 4], 5, [6, 7, 8]]←変更できている>>> lst3
Enter←元のリストの内容確認[1, [2, 3, 4], 5, [6, 7, 8]]←影響なし（元のまま）>>> lst4[1][0] = 20

←複製の要素の内，リストの部分を改変

Enter>>> lst4
Enter
←内容確認
[10, [20, 3, 4], 5, [6, 7, 8]]←変更されている>>> lst3Enter←しかし，元のリストの内容を確認すると…
[1, [20, 3, 4], 5, [6, 7, 8]]←要素のリストの部分が変更されている
この例からわかるように，copy.copy による複製では要素のリストまでは複製されず，元のリストの要素を参照していることがわかる．このような複製の作成を浅いコピー（shallow copy）という．これに対して，要素のリストまで
全て（再帰的に）複製することを深いコピー（deep copy）という．

copy モジュールの deepcopy 関数を用いると深いコピーができる．
例．deepcopy 関数による深いコピー（先の例の続き）

Enter>>> lst3 = [1,[2,3,4],5,[6,7,8]]

Enter>>> lst4 = copy.deepcopy(lst3)>>> lst4[0] = 10

←それを deepcopy で複製する←複製の先頭要素（数値）を改変

Enter>>> lst4[1][0] = 20

←リストを要素に持つリスト←複製の要素の内，リストの部分を改変

Enter>>> lst4
Enter←複製側の内容確認[10, [20, 3, 4], 5, [6, 7, 8]]←変更されている>>> lst3
Enter←元のリストの内容を確認[1, [2, 3, 4], 5, [6, 7, 8]]←全く変更なし■ 参考

copy メソッドによる浅いコピー

リストに対して copy メソッドを使用することでも浅いコピーが作成できる．
例．リストに対する copy メソッドEnter>>> lst3 = [1,[2,3,4],5,[6,7,8]]>>> lst4 = lst3.copy()

Enter←リストを要素に持つリスト←それを copy メソッドで複製する

この例は，リスト lst3 の浅いコピー lst4 を作成するものである．
課題．上の例において lst4 が lst3 の浅いコピーになっていることを確かめよ．
■ 参考

list コンストラクタによる浅いコピー

既存のリストを list コンストラクタに与えて浅いコピーを作成することができる．
例．list コンストラクタによる浅いコピー>>> lst1 = [1,2,[3,4],5]Enter>>> lst2 = list(lst1); print(lst2)[1, 2, [3, 4], 5]←リストを作成

Enter←上記のリストを複製して内容確認←複製されている←複製側の内容を変更>>> lst2[1] = ’x’Enter>>> lst1
Enter[1, 2, [3, 4], 5]←元のリストの内容確認←変更なし>>> lst2
Enter
←複製側は
[1, ’x’, [3, 4], 5]←変更されている
課題．上の例において lst2 が lst1 の浅いコピーになっていることを確かめよ．

55

■ 参考
リストに対するメソッドや関数の内，内容の変更を伴わないものについては多くのものが文字列型（str 型）のオブジェクトに対しても使用できる．
（次の例参照）
例．文字列に対する各種の処理>>> ’abcdefg’.index(’c’)
2

Enter

← index メソッド
←実行結果>>> ’abacad’.count(’a’)
3

Enter

← count メソッド
←実行結果>>> sorted(’dcgeafb’)Enter← sorted 関数[’a’, ’b’, ’c’, ’d’, ’e’, ’f’, ’g’]
←この場合の実行結果はリストとして得られる
この例で挙げたメソッドや関数以外についても試していただきたい．

2.4.1.13

リストか否かの判定あるオブジェクトの型がリストか否かを判定するには type 関数を用いる．
例．リストか否かの判定>>> type( lst )←変数 lst にリストを与える

Enter>>> lst = [1,2,3]← type 関数による型の調査

Enter←リストの型<class ’list’>>>> type( lst ) is list

←リストであるTrue
2.4.1.14← type 関数と is 演算子による型の判定

Enter

リストの内部に他のリストを展開する方法’*’ を用いてリスト内に他のリストを要素として展開することができる．
例．リスト内に他のリストを展開する>>> lst1 = [3,4,5]

Enter>>> lst2 = [1,2,*lst1,6,7]←このリストの全要素をEnter←別のリスト内に展開する>>> lst2
Enter
←内容確認
[1, 2, 3, 4, 5, 6, 7]←展開されている
同様の方法で，種類の異なるデータ構造（文字列など）も要素として他のリスト内に展開することができる．

2.4.2

タプル

タプルはリストとよく似た性質を持つ，’(’ と ’)’ で括ったデータ構造である．
タプルの例．

(0,1,2,3,4,5,6,7,8,9)(’nakamura’,51,’tanaka’,22,’hashimoto’,14)(’a’,(’b’,’c’),’d’)
次のように，リストとタプルは互いに要素として混在させることができる．
例．リスト，タプルの混在[’a’,(’b’,’c’),’d’](’a’,[’b’,’c’],’d’)2.4.2.1

リストとタプルの違い

リストとタプルは表記に用いる括弧の記号が異なるだけではない．リストは先に解説したように，要素の追加や削除など自在に編集ができるが，タプルは 1 度生成した後は変更ができない．リストのように，事後で内容の変更が可能であることを「ミュータブル（mutable）である」と言い，事後で内容を変更できないことを「イミュータブル
（immutable）である」と言う．

56

2.4.2.2

括弧の表記が省略できるケース

Python では変数への値の代入をする際に，
x,y = 2,3という並列的な表記が許されている．実はこの例の両辺はタプルになっており，(x,y) = (2,3)という処理を行ったことと等しい．これはタプルの性質を利用している例であると言える．この例の操作をした直後に x,y それぞれの変数の値を確認すると，

>>> x
2

Enter

>>> y
3

Enter

と設定されていることが確認できる．このような高度な代入処理に関して後の「2.4.8 データ構造に沿った値の割当て（分割代入）」（p.72）で更に詳しく解説する．
リストに対する文や関数，メソッドの内，データ構造を変更しないものは概ねタプルに対しても使うことができる．

2.4.2.3

特殊なタプル

要素を持たないタプルも存在し，( ) と記述する．また，要素が 1 つのタプルは要素の後にコンマを付ける必要がある．
例．空のタプル>>> a = ( )
>>> a
()

←空のタプルを a に設定

Enter

Enter
←内容確認
←空のタプルとして保持されていることがわかる>>> len(a)Enter←データ長の確認
0←結果（要素の個数は 0）
例．要素数が 1 のタプル>>> a = (1)
>>> a
1

Enter
←内容確認
←タプルではなく，数値 1>>> a = (1,)
>>> a
(1,)

←括弧の中に要素を 1 つだけ記述する試み

Enter

Enter

←要素が 1 つのタプルの作成

Enter

←内容確認
←タプルとなっている>>> len(a)Enter←データ長の確認
1←結果（要素の個数は 1）
この例でもわかるように，括弧の中にコンマ無しで要素を 1 つだけ記述するとタプルとはならないので注意が必要である．

2.4.2.4

タプルの要素を整列（ソート）する方法

タプルはイミュータブルなデータ構造なので，それ自体を整列することはできないが，sorted 関数を使用すると，整列結果をリストの形で取得することができる．
例．タプルの整列>>> a = (5,4,3,2,1)>>> sorted( a )[1, 2, 3, 4, 5]

Enter

Enter

←タプルを作成←それを sorted 関数で整列←整列結果がリストの形で得られている

>>> a
Enter
←元のタプルの内容確認(5, 4, 3, 2, 1)←変化は無い

57

2.4.2.5

タプルか否かの判定あるオブジェクトの型がタプルか否かを判定するには type 関数を用いる．
例．タプルか否かの判定>>> t = (1,2,3)

Enter>>> type( t )Enter<class ’tuple’>>>> type( t ) is tuple
True
2.4.3

←変数 t にタプルを与える← type 関数による型の調査←タプルの型Enter← type 関数と is 演算子による型の判定←タプルであるセット

セットは ’{’ と ’}’ で括ったデータ構造であり，集合論で扱う集合に近い性質を持っている．例えば，>>> s = {4,1,3,2,1,3,4,2}

Enter

としてセットを生成した後に内容を確認すると，

>>> s
Enter
{1, 2, 3, 4}となっていることがわかる．すなわち，セットでは要素の重複が許されず，要素に順序の概念がない．この例では要素が整列されているように見えるが，セットの要素の順序は一般的には独特な並びとなる．
（次の例参照）
例．セットの要素の独特な並び← 12 , 22 , · · · , 102 のセット>>> s = {1,4,9,16,25,36,49,64,81,100}

Enter

>>> s
Enter
←内容確認
{64, 1, 4, 36, 100, 9, 16, 49, 81, 25}←独特な並び

この例のようにセットの要素は独特の順序となるが，同じ版の Python 処理系では同じ順序となる．これは，要素の探索（メンバシップ検査）を高速に実行するための Python 処理系内部の仕組み57 による．また，上の例は Windowsのコマンドプロンプト環境で実行したものであり，別の実行環境によっては出力時にセットの要素の順が整列されることもある．
（次の例参照）
例．IPython 環境における実行例

In [1]:s = {1,4,9,16,25,36,49,64,81,100}

In [2]:
Out[2]:sEnter{1, 4, 9, 16, 25, 36, 49, 64, 81, 100}

Enter
←セットの要素が整列されて表示されている

これは IPython 58 の実行環境による例である．
重要）
出力時のセットの要素の順序はスクリプト実行の場合でも異なったものになることがあり，セットの要素の順序が結果に影響を与えるようなプログラミングは避けること．

2.4.3.1

セットの要素となるオブジェクト

セットは不変なオブジェクトを要素とする59 ．従ってリストを始めとする可変な（ミュータブルな）オブジェクト
はセットの要素に含めることができない．
（セットも別のセットの要素にはできない）

57 ハッシュ表による高速探索を実現している．
58 Jupyter Notebook の処理環境も IPython を使用している．
59 Python 処理系内部でハッシュ値が算出可能なもの（基本的にはイミュータブルなオブジェクト）を要素とする．

58

例．様々なオブジェクトをセットの要素に含める試み>>> s = {1,2,3,’4’,5,6}←文字列の ’4’ をセットの要素にする

Enter

>>> s
Enter
←内容確認
{1, ’4’, 2, 3, 5, 6}←セットになっている>>> s = {1,2,3,(4,5),6}←タプルをセットの要素にする

Enter

>>> s
Enter
←内容確認
{1, 2, 3, 6, (4, 5)}←セットになっている>>> s = {1,2,3,[4,5],6}Enter←リストをセットの要素にしようとすると…
Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: unhashable type: ’list’←リストはハッシュ化できない旨のメッセージ
2.4.3.2

セットの生成基本的には要素の列を ’{’ と ’}’ で括ることでセットを記述するが，空セット（空集合）を生成する際は { } という記述をせずに

st = set()のように set クラスのコンストラクタを使用する．これは { } という表記が，後で述べる辞書型データの空辞書と区別できない事情があるためであり，このように明に set コンストラクタで生成することになる．また，リストや文字列などのデータ構造を set コンストラクタの引数に与えることもでき，それらデータ構造の要素をセットの要素に変換することができる．
例．リストや文字列を set コンストラクタに与える←リストを set コンストラクタに与えるEnter>>> s = set( [1,2,3] )

>>> s
Enter
←内容確認
{1, 2, 3}←セットになっている>>> s = set( ’abc’ )Enter←文字列を set コンストラクタに与える

>>> s
Enter
←内容確認
{’c’, ’a’, ’b’}
←与えた文字列の各文字がセットの要素になっている
2.4.3.3

セットに対する各種の操作● 要素の追加
セットに要素を追加するには add メソッドを使用する．
例．セットへの要素の追加>>> st = set()Enter>>> st.add(’a’)

Enter>>> st
{’a’}

Enter

←空セットの生成←要素’a’ の追加←内容確認←要素が追加されている● 要素の削除
セットの要素を削除するには discard メソッドを使用する．例えばセット st から要素 ’a’ を削除するには

st.discard(’a’)とする．リストの場合と同様に remove メソッドを使用することもできるが，削除対象の要素がセットの中にない場
合にエラー KeyError が発生するので discard メソッドを使用する方が良い．
（次の例参照）
例．要素の削除（先の例の続き）>>> st.discard(’a’)>>> stset()←要素 ’a’ を削除

Enter←セットの内容確認←空セットになっている>>> st.discard(’a’)>>> st
set()

Enter

Enter

←存在しない要素 ’a’ の削除を試みる

Enter←セットの内容確認
←空セット

59

● 要素の取り出しと削除： pop
セットから要素を取り出した後，その要素を当該セットから削除するには pop メソッドを使用する．pop によって取り出される要素の順序は不定である．また，空のセット set() に対して pop を実行すると KeyError となる．
（次の例参照）
例．要素の取り出しと削除>>> s = set( [x**2 for x in range(8)] )
>>> s
Enter
←内容確認
{0, 1, 4, 36, 9, 16, 49, 25}Enter←セットの生成←結果表示>>> s.pop(), s.pop(), s.pop(), s.pop(), s.pop(), s.pop(), s.pop(), s.pop() Enter ← pop の実行(0, 1, 4, 36, 9, 16, 49, 25)
←処理結果
>>> s
set()

Enter
←処理後の内容確認←空になった>>> s.pop()

Enter←空セットに対して pop を実行すると…

Traceback (most recent call last):←エラーとなる．
File "<stdin>", line 1, in <module>
KeyError: ’pop from an empty set’
実際には pop によって取り出される要素の順序は，処理対象のセットの要素の順序となる．
● 全要素の削除
セットの全ての要素を削除して空セットにするには clear メソッドを使用する．例えばセット st の全ての要素を削除するには

st.clear()とする．
● 要素の個数の取得
セットの要素の個数を調べるには len 関数を用いる．例えば，セット st の要素の個数を得るには len(st) とする．
● セットの複製
リストの場合と同様に，copy モジュールの copy 関数，deepcopy 関数でセットの複製が可能であるが，copy メソッ
ドで複製ができる．
例．copy メソッドによるセットの複製>>> s = {4,3,2,1}

Enter←セットの作成>>> s2 = s.copy()Enter← copy メソッドによる複製←複製の内容確認←元のセット s と同じ>>> s2
Enter{1, 2, 3, 4}Enter>>> s2.discard(3)←複製のセットの要素を削除>>> s2
Enter{1, 2, 4}←複製の内容確認←要素 3 が削除されている

>>> s
Enter
{1, 2, 3, 4}←元のセットの内容確認←影響を受けていない● 最小値，最大値，合計min，max，sum 関数でセットの要素の最小値，最大値，合計をそれぞれ求めることができる．

60

例．最小値，最大値，合計>>> s = {4,3,2,1}←セットの作成

Enter>>> min( s )
Enter
1
←結果

←最小値を求める>>> max( s )
Enter
4
←結果

←最大値を求める>>> sum( s )
Enter
10
←結果

←合計を求める

2.4.3.4

集合論の操作

セットに対する操作と集合論における操作との対応を表 11 に挙げる．
表 11: Python のセットに対する操作と集合論の操作の対応

Python での表記

集合論に
おける操作

戻り値の
タイプ

意味

X in SX∈S

真理値

要素 X は集合 S の要素であるX not in S

X∈
/S

真理値

要素 X は集合 S の要素でない

S1.issubset(S2)S1 ⊆ S2

真理値

集合 S1 は集合 S2 の部分集合である

S1.issuperset(S2)S2 ⊆ S1

真理値

集合 S2 は集合 S1 の部分集合である

S1.isdisjoint(S2)S1 ∩ S2 = φ

真理値

集合 S1 と集合 S2 は共通部分を持たない

S1.intersection(S2)S1 ∩ S2

セット

集合 S1 と集合 S2 の共通集合を生成する

S1 ← S1 ∩ S2

セット

集合 S1 と集合 S2 の共通集合を
S1 の内容として更新する

S1.union(S2)S1 ∪ S2

セット

集合 S1 と集合 S2 の和集合を生成する

S1.update(S2)S1 ← S1 ∪ S2

セット

集合 S1 と集合 S2 の和集合を
S1 の内容として更新する

S1.diﬀerence(S2)S1 − S2

セット

集合 S1-S2（集合の差）を生成する

S1 ∪ S2 − S1 ∩ S2

セット

集合 S1 と S2 の共通しない要素の集合を生成する

S1.intersection update(S2)S1.symmetric diﬀerence(S2)

表 11 に示したメソッドと同等の演算子もある．
例．union，intersection，symmetric diﬀerence 各メソッドと同等の演算子>>> {1,2,3} | {2,3,4}
Enter{1, 2, 3, 4}←結果←和集合：union と同等>>> {1,2,3} & {2,3,4}
Enter{2, 3}←結果←共通集合：intersection と同等>>> {1,2,3} ^ {2,3,4}
Enter{1, 4}←結果← symmetric diﬀerence と同等>>> {1,2,3} - {2,3,4}
Enter
{1}
←結果

←集合の差：diﬀerence と同等>>> {2,3,4} - {1,2,3}
Enter
{4}
←結果

←集合の差：diﬀerence と同等

この例のように，和集合は「|」，共通集合は「&」，和集合から共通集合を取り除いた集合は「^」，集合の差は「-」で求める方が簡便である．
● 部分集合の判定
表 11 のメソッドを用いて部分集合の判定ができるが，大小比較の演算子 <，<=，>，>= を用いて判定することもできる．

61

例．部分集合の判定>>> {2,4,6} <= {1,2,3,4,5,6}
True
←判定結果

Enter

←部分集合の判定>>> {1,2,3} <= {1,2,3}
Enter
True
←判定結果

←部分集合の判定：全要素が同じ場合>>> {1,2,3} < {1,2,3}
Enter
False
←判定結果

←真部分集合の判定

2.4.3.5

セットか否かの判定あるオブジェクトの型がセットか否かを判定するには type 関数を用いる．
例．セットか否かの判定>>> s = {1,2,3}>>> type( s )<class ’set’>← type 関数による型の調査←セットの型Enter>>> type( s ) is set
True
2.4.3.6←変数 s にセットを与える

Enter

Enter

← type 関数と is 演算子による型の判定←セットであるfrozenset

セットとよく似た frozenset というデータ構造もある．frozenset のオブジェクトは生成後に変更ができないが，セット（set）と比較して高速な処理ができる．
例．frozenset の作成>>> fs = frozenset( [1,2,3] )Enter← frozenset コンストラクタで生成>>> fsEnter←内容確認
frozenset({1, 2, 3})←作成された frozenset
セットに対する関数やメソッドの内，内容の変更を伴わないものは基本的に frozenset に対しても使用できる．
例．セットの場合と同様の処理（先の例の続き）>>> fs2 = frozenset( [2,3,4] )Enter←別の frozenset を作成>>> fs.intersection(fs2)
frozenset({2, 3})Enter←共通集合を求める←処理結果>>> fs & fs2
Enter
frozenset({2, 3})←&演算子で共通集合を求める
←処理結果

2.4.4

辞書型

辞書型オブジェクトはキーと値のペアを保持するもので，文字通り辞書のような働きをする．辞書型オブジェクトは{ キー 1:値 1, キー 2:値 2, ...}と記述する．辞書型オブジェクトの指定したキーに対応する値にアクセスするにはスライスを用いて辞書型オブジェクト [キー]と記述する．辞書型オブジェクトの作成と参照の例を次に示す．
例．辞書型オブジェクトの作成と参照>>> dic = {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’} Enter>>> dic[’apple’]’ りんご’

Enter←辞書の中のキー ’apple’ に対応する値を参照する←値が得られた辞書型のオブジェクトはキーの値でハッシュ化されており，探索が高速である．
キーと値のペアを新たに辞書に追加するには，

dic[’banana’] = ’ バナナ’などとする．

62←辞書を dic に作成

重要）

辞書型オブジェクトの要素となる「キーと値のペア」をエントリと呼ぶ．キーに使用できるオブジェクト
は数値，文字列，タプルといったもの60 がある．また，リストや辞書オブジェクトといったミュータブルなオブジェクトはキーには使えないことに注意すること．

2.4.4.1

空の辞書の作成

空の辞書を生成するには

dic = {}

あるいは

dic = dict()とする．また，既存の辞書を空にするには clear メソッドを使用する．

2.4.4.2

エントリの削除

辞書の中の特定のエントリを削除するには del 文が使用できる．例えば，del dic[’banana’]とすると辞書 dic から ’banana’ のキーを持つエントリが削除される．
辞書型オブジェクトに登録されていないキーを参照しようとすると次の例のようにエラー KeyError が発生する．
（次の例参照）
例．存在しないキーへのアクセス（先の例の続き）>>> dic[’grape’]Enter←存在しないキー ’grape’ を参照すると…

Traceback (most recent call last):←エラーメッセージが表示されるFile "<stdin>", line 1, in <module>
KeyError: ’grape’
また，del 文によって存在しないキーのエントリを削除しようとした場合も同様のエラーとなる．以上のことから，辞書型オブジェクトにアクセスする際は適切に例外処理61 をするか，キーが登録されているかを検査する必要がある．
あるいは，簡便な方法として，get メソッドで値を取り出す方法がある．
（これに関しては後で解説する）
辞書にキーが登録されているかを検査するには ’in’ を用いる．
例． キーの存在検査（先の例の続き）←辞書 dic にキー ’grape’ が存在するか検査>>> ’grape’ in dic
Enter
False
←存在しない．

このように， キー in 辞書型オブジェクトという式を記述すると，キーが存在すれば True が，存在しなければFalse が得られる．
2.4.4.3

get メソッドによる辞書へのアクセス（次
存在しないキーにアクセスする可能性などを考慮すると，get メソッドで辞書にアクセスするのが安全である．
の例参照）
例．get メソッドによる辞書へのアクセス（先の例の続き）>>> v = dic.get(’lemon’)>>> print( v )レモン←存在するキー ’lemon’ に対する値を v に格納←値の確認←値が得られているEnter>>> v = dic.get(’grape’)>>> print( v )
None

Enter

Enter

Enter

←存在しないキー ’grape’ に対する値の取得を試みる←値の確認←値が得られないので None となる

存在しないキーに対する戻り値を get メソッドの第 2 引数に指定することができる．

60 ハッシュ可能（hashable） なオブジェクト
61 「2.4.1.6 例外処理」（p.51）を参照のこと．

63

例．存在しないキーに対する戻り値の設定（先の例の続き）>>> v = dic.get( ’grape’, ’???’>>> print( v )
???

)

Enter

←存在しないキーに対する戻り値を ’ ???’ に設定←値の確認←値が得られないので ’ ???’ となるEnter

注）get メソッドは指定したエントリの値を取得するものであり，エントリの値の設定には使用できない．
（次の例参照）
例．get メソッドの処理結果に対して値を設定する試み（先の例の続き）>>> dic.get(’lemon’) = ’ れもん’

←値を設定しようとすると…

Enter

File "<stdin>", line 1←文法エラーとなる
dic.get(’lemon’) = ’ れもん’^^^^^^^^^^^^^^^^
SyntaxError:cannot assign to function call here.Maybe you meant ’==’ instead of ’=’?
2.4.4.4

辞書に対する pop

辞書に対して pop メソッドを実行（引数にキーを与える）すると値が取り出され，当該エントリが元の辞書から削除される．
例．辞書に対する pop>>> dic = {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’}

Enter←辞書の作成←キー ’orange’ に対する値を pop で取り出す>>> dic.pop(’orange’)Enter’ みかん’←値が得られた>>> dicEnter←元の辞書の内容確認{’apple’: ’ りんご’, ’lemon’: ’ レモン’}← pop の処理対象となったエントリが削除されている

注）辞書に対する pop メソッドでは，引数を空にして実行するとエラー（TypeError）が発生する．

2.4.4.5

辞書の更新

辞書の既に存在するキーに対して新たに値を設定すると，その値に更新される．
例．既存のキーに対する値の再設定>>> dic = {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’}>>> dic[’lemon’] = ’ れもん’Enter>>> dicEnter←内容確認{’apple’: ’ りんご’, ’orange’:Enter←辞書の作成←既存のキー ’lemon’ に新たに値を設定する’ みかん’, ’lemon’:’ れもん’}←値が更新されている

これは，1 つのエントリの更新の方法である．複数のエントリをまとめて更新することもできる．
（次の例参照）
例．複数のエントリの更新（先の例の続き）>>> dic2 = {’apple’:’ 林檎’,’banana’:’ バナナ’,’grape’:’ ぶどう’} Enter>>> dic.update(dic2)

Enter←新たな辞書を作成←既存の辞書の内容を新たな辞書の内容で更新>>> dicEnter←内容確認{’apple’: ’ 林檎’, ’orange’: ’ みかん’, ’lemon’:’banana’: ’ バナナ’, ’grape’: ’ ぶどう’}’ れもん’,←更新結果

この例のように update メソッドを使用して辞書 1.update( 辞書 2 )とすると，辞書 1 に辞書 2 の内容を追加する形で更新を行う．
● 既存のエントリを優先する形の更新処理

setdefault メソッドを使用すると，既存のエントリを優先する形で辞書を更新することができる．
（次の例参照）

64

例．setdefault による辞書の更新：新規エントリの追加の場合>>> dic = {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’}←辞書の作成Enter>>> dic.setdefault( ’banana’, ’ バナナ’ )Enter←新エントリ「バナナ」の登録’ バナナ’←登録結果としてエントリの値 ’ バナナ’ が返される>>> dicEnter←更新後の内容確認{’apple’:’ りんご’, ’orange’:’ みかん’, ’lemon’:’ レモン’, ’banana’:’ バナナ’}←辞書の内容この例では，新しいキー ’banana’ を持つエントリが辞書に追加されていることがわかる．次に，既存のキー ’orange’のエントリに対して setdefault で更新を試みる．
例．既存のキー ’orange’ のエントリの更新の試み（先の例の続き）>>> dic.setdefault( ’orange’, ’ 蜜柑’ )Enter←既存の ’orange’ のエントリの更新を試みる’ みかん’←実行結果として既存のエントリの値 ’ みかん’ が返され…
>>> dic
Enter←処理後の辞書の内容を確認すると{’apple’:’ りんご’, ’orange’:’ みかん’, ’lemon’:’ レモン’, ’banana’:’ バナナ’}←変更なし

setdefault による更新処理では，既存のエントリが優先されることがわかる．
2.4.4.6

辞書の結合

Python3.9 の版から，辞書の和を求める（辞書を結合する）演算子 ’|’ が使用できる．
書き方：

d1 | d2

辞書 d1 と d2 を結合する．d1 と d2 に重複するキーがある場合は d2 の側のエントリが優先される．
例．辞書の結合>>> d1 = {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’}>>> d2 = {’lemon’:’ 檸檬’,’banana’:’ バナナ’,’grape’:’ ぶどう’}←辞書 d1 の作成

Enter
Enter

←辞書 d2 の作成>>> d1 | d2
Enter
← d1 と d2 の結合（d2 を優先）
↓結合結果{’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ 檸檬’,’banana’:’ バナナ’,’grape’:’ ぶどう’}>>> d2 | d1
Enter
← d2 と d1 の結合（d1 を優先）
↓結合結果{’lemon’:’ レモン’,’banana’:’ バナナ’,’grape’:’ ぶどう’,’apple’:’ りんご’,’orange’:’ みかん’}
この処理によって元の辞書は変更されない．
例．元の辞書の内容確認（先の例の続き）>>> d1Enter← d1 の内容確認{’apple’: ’ りんご’, ’orange’: ’ みかん’, ’lemon’:>>> d2Enter← d2 の内容確認{’lemon’: ’ 檸檬’, ’banana’: ’ バナナ’, ’grape’:’ レモン’}’ ぶどう’}

←変化なし
←変化なし

参考）Python3.8 以前の版の処理系で辞書を結合するには，後に説明する方法（keys メソッド）で両方の辞書のキーの並びを取り出してセットに変換し，それらの和集合を求める方法を応用すると良い．

2.4.4.7

辞書を他の辞書の内部に展開する方法

アスタリスク 2 つを辞書の前に記述すると，それを他の辞書の内部に展開することができる．
例．辞書を他の辞書内に展開する>>> d2 = {’lemon’:’ 檸檬’,’banana’:’ バナナ’}Enter←この辞書を，>>> {’apple’:’ りんご’,’orange’:’ みかん’,**d2,’lemon’:’ レモン’} Enter ←この辞書内に展開する{’apple’:’ りんご’, ’orange’:’ みかん’, ’lemon’:’ レモン’, ’banana’:’ バナナ’} ←展開結果
この例では，’lemon’:’ 檸檬’ というエントリが展開された後で新たなエントリとして ’lemon’:’ レモン’ が与えられているので，結果的に後者のエントリが残る．すなわち，同じキーを持つエントリがある場合は，後から記述されたものが結果として残る．

65

例．展開位置を変える試み（先の例の続き）>>> {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’,**d2} Enter ←展開位置を変更{’apple’: ’ りんご’, ’orange’: ’ みかん’, ’lemon’: ’ 檸檬’, ’banana’: ’ バナナ’} ←展開結果
先の例と違うのは ’lemon’:’ レモン’ のエントリの後に d2 を展開しているので，結果として，’lemon’:’ 檸檬’ が残っている．

2.4.4.8

キーや値の列を取り出す方法

辞書型オブジェクトから全てのキーを取り出すには，次のように keys メソッドと list 関数を使用する62 ．
例．全てのキーの取り出し>>> dic={’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’} Enter ←辞書型オブジェクト生成>>> k = dic.keys()Enter←全てのキーの取り出し

>>> k
Enter
←内容確認
dict keys([’apple’, ’orange’, ’lemon’])>>> list(k)Enter[’apple’, ’orange’, ’lemon’]←結果表示←リストに変換する←全キーのリスト

このように keys メソッドにより dict keys(...) というオブジェクト63 が生成され，更にそれを list 関数でリストにしている．もちろん

list(dic.keys())のようにしても良い64 ．
同様に，辞書型オブジェクトに対して values メソッド65 を使用して，全ての値のリストを生成することもできる．

2.4.4.9

エントリの数を調べる方法

辞書型オブジェクトのエントリの個数を調べるには len 関数を用いる．例えば，辞書型オブジェクト dic のエントリ数を得るには len(dic) とする．
例．辞書のエントリの数を調べる（先の例の続き）>>> len( dic )Enter←辞書の長さの調査
3←長さ（エントリ数）が得られている
2.4.4.10

リストやタプルから辞書を生成する方法

キーと値のペアを要素として持つリストやタプルを dict( ) 66 の引数に与えることで，それらを辞書型オブジェク
トに変換することができる．
例．リストから辞書型オブジェクトを生成する>>> dic2 = dict( [[’dog’,’ 犬’],[’cat’,’ 猫’],[’bird’,’ 鳥’]] ) Enter ←リストから辞書を生成>>> dic2
Enter{’dog’:’ 犬’, ’cat’:’ 猫’, ’bird’:’ 鳥’}

←内容確認
←結果表示

>>> dic2[’cat’]Enter←辞書オブジェクトとして引用’ 猫’←対応する値が得られている

62 「2.4.6 データ構造の変換」（p.70）に示す方法でも辞書の全キーが得られる．
63 ビュー（view）と呼ばれるもので，元の辞書が変更されるとそれに連動してビューも変わる．
64 更に簡単に list(dic) としてもキーのリストが得られる．
65 辞書の値のビューを返す．
66 辞書のコンストラクタ

66

例．リストやタプルから辞書型オブジェクトを生成する>>> dic2 = dict( [(’dog’,’ 犬’),(’cat’,’ 猫’),(’bird’,’ 鳥’)] )Enter←辞書を生成Enter←辞書を生成

←内容確認
←結果表示

>>> dic2
Enter{’dog’:’ 犬’, ’cat’:’ 猫’, ’bird’:’ 鳥’}>>> dic2 = dict( ((’dog’,’ 犬’),(’cat’,’ 猫’),(’bird’,’ 鳥’)) )
←内容確認
←結果表示

>>> dic2
Enter{’dog’:’ 犬’, ’cat’:’ 猫’, ’bird’:’ 鳥’}

参考）2 文字の文字列を要素とするリストから辞書を生成することができる．
例．2 文字の文字列をエントリに変換可能>>> a = [’a1’,’b2’,’c3’]←このようなリストをEnter>>> dict(a)Enter{’a’: ’1’, ’b’: ’2’, ’c’:

’3’}

←辞書に変換する
←変換結果

ただし，
「2 文字の文字列」以外の要素を持つリストは辞書には変換できない．
例．辞書に変換できない例>>> a = [’abc’,’def’,’ghi’]>>> dict(a)←このようなリストはEnter←辞書に変換Enter

Traceback (most recent call last):←できない
File "<stdin>", line 1, in <module>（エラーとなる）
ValueError: dictionary update sequence element #0 has length 3; 2 is required
2.4.4.11

辞書の全エントリを列として取り出す方法

辞書オブジェクトに対して items メソッドを実行することで，辞書の全エントリを列の形で取り出すことができる．
例．辞書の全エントリを列にする（先の例の続き）>>> itm = dic2.items()←辞書の全内容の取り出しEnter>>> itmEnter←内容確認
dict items([(’dog’, ’ 犬’), (’cat’, ’ 猫’), (’bird’, ’ 鳥’)])>>> list( itm )Enter[(’dog’, ’ 犬’), (’cat’, ’ 猫’), (’bird’, ’ 鳥’)]

←結果表示

←リストに変換←変換結果

辞書に対して items メソッドを実行すると dict items([…]) という形のオブジェクト67 が得られる．上の例ではこれを list 関数でリストに変換している．

2.4.4.12

辞書の複製

辞書型オブジェクトに対して copy メソッドを実行することで複製することができる．
例．辞書の複製>>> dic = {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’}>>> dic2 = dic.copy()Enter←複製のエントリを変更>>> dic2
Enter←複製の内容確認{’apple’:’ りんご’, ’orange’:’ 蜜柑’, ’lemon’:’ レモン’}←’orange’ のエントリが変更されている>>> dicEnter←元の辞書の内容確認{’apple’:’ りんご’, ’orange’:’ みかん’, ’lemon’:’ レモン’}←元の辞書は変化なし

参考）辞書オブジェクトに対しても copy モジュールの機能が使用できる．

2.4.4.13←辞書の作成←それを複製して dic2 に与える

Enter>>> dic2[’orange’] = ’ 蜜柑’

Enter

エントリの順序

Python3.7 の版から，辞書に登録したエントリの順序が保証された68 ．
67 ビュー（view）と呼ばれるもので，元の辞書が変更されるとそれに連動してビューも変わる．
68 実際には Python3.6 からこの性質がある．

67

例 1．登録したエントリの順序の確認>>> d1 = {}Enter

←空の辞書 d1 の作成>>> d1[’apple’] = ’ リンゴ’>>> d1[’banana’] = ’ バナナ’>>> d1[’grape’] = ’ ブドウ’

←エントリの登録（以下同様）

Enter
Enter
Enter

>>> d1
Enter←内容確認{’apple’: ’ リンゴ’, ’banana’:’ バナナ’, ’grape’:’ ブドウ’}←でき上がった辞書

次に，エントリの登録順序を変えて同様の処理を行う例を示す．
例 2．登録したエントリの順序の確認（その 2）>>> d2 = {}Enter

←空の辞書 d2 の作成>>> d2[’grape’] = ’ ブドウ’>>> d2[’banana’] = ’ バナナ’>>> d2[’apple’] = ’ リンゴ’

←エントリの登録（以下同様）

Enter
Enter
Enter

>>> d2
Enter←内容確認{’grape’: ’ ブドウ’, ’banana’:’ バナナ’, ’apple’:’ リンゴ’}←でき上がった辞書

エントリの順序が登録順になっていることがわかる．

2.4.4.14

辞書の整列

エントリの順序が登録順になるという性質を応用すると，辞書の整列が可能である．例えば，先の例の辞書 d2 をキーの順で整列するには次のような処理を行う．
例．辞書の整列（先の例の続き）>>> d3 = {}Enter

←空の辞書 d3 の作成

Enter>>> for k in sorted(d2.keys()):...
...

d3[k] = d2[k]Enter←辞書 d2 のキーを整列したもので反復処理69 する←辞書 d3 に辞書 d2 のエントリを登録する

Enter← for 文の記述の終了>>> d3
Enter←内容確認{’apple’: ’ リンゴ’, ’banana’:’ バナナ’, ’grape’:’ ブドウ’}←整列された辞書

この例では，辞書 d2 のキーを sorted(d2.keys()) で整列し，その順序に従って辞書 d2 のエントリを d3 に登録している．結果として整列された辞書が d3 に得られている．もちろん，元の辞書 d2 には変化はない．
（次の例参照）
例．元の辞書の内容確認（先の例の続き）>>> d2
Enter←元の辞書 d2 の内容確認{’grape’: ’ ブドウ’, ’banana’: ’ バナナ’, ’apple’:’ リンゴ’}←辞書 d2 の内容

課題．for 文を使わずに辞書を整列する方法について考えよ．

2.4.4.15

辞書の同値性異なる辞書が同じエントリを持っている場合，’==’ による同値性の判定は True となる．その場合，エントリの順
序は関係ない．
例．エントリの順序が異なる同値の辞書の比較>>> d1 = {’dog’:’ 犬’, ’cat’:’ 猫’}

Enter

←辞書

>>> d2 = {’cat’:’ 猫’, ’dog’:’ 犬’}

Enter←上の辞書と同じエントリを持つ辞書>>> d1 == d2
True
2.4.4.16

Enter←比較結果は←真

辞書か否かの判定

あるオブジェクトの型が辞書か否かを判定するには type 関数を用いる．

69 詳しくは「2.5 制御構造」（p.75）のところで解説する．

68

例．辞書か否かの判定>>> d = {’dog’:’ 犬’, ’cat’:’ 猫’}>>> type( d )<class ’dict’>← type 関数による型の調査
←辞書の型

Enter

← type 関数と is 演算子による型の判定←辞書であるEnter>>> type( d ) is dict
True
2.4.5

←変数 d に辞書を与えるEnter

添字（スライス）の高度な応用

リストやタプルあるいは文字列といったデータ構造では，添字 ’[...]’ を付けることで部分列を取り出すことができるが，ここでは添字（スライス）の少し高度な応用例を紹介する．

2.4.5.1

添字の値の省略

先頭あるいは最終位置の添字は省略することができる．例えば，>>> a = ’abcdefghijklmnopqrstuvwxyz’

Enterとして変数 a にアルファベット小文字の列を設定しておくと，a の要素は「0 番目」から「25 番目」のインデックス
でアクセスできる．このとき a[0:26]（0 番目から 26 番目未満）は文字列全体を示す．スライスのインデックス範囲の記述が 0 から始まる場合はそれを省略することができる．同様にインデックスの範囲の記述が「最後の要素のイン
デックス＋ 1」で終了する場合もそれを省略できる．
（次の例参照）
例．添字の省略（先の例の続き）>>> a[:26]Enter’abcdefghijklmnopqrstuvwxyz’←先頭位置の 0 を省略←文字列全体>>> a[0:]Enter’abcdefghijklmnopqrstuvwxyz’←最終位置の 26 を省略←文字列全体>>> a[:]
Enter’abcdefghijklmnopqrstuvwxyz’←両方省略←文字列全体2.4.5.2

スライスオブジェクト

スライスは ‘[s1 : s2 ]’，あるいは ‘[s1 : s2 : s3 ]’ と記述するが，このスライス自体を表現するスライスオブジェク
トがあり，これを用いてスライスの部分を

slice(s1 , s2 )あるいはslice(s1 , s2 , s3 )と記述することができる．
（次の例参照）
例．スライスオブジェクト>>> lst = [1,2,3,4,5,6,7]>>> s = slice(1,4)>>> lst[s][2, 3, 4]

Enter

Enter

Enter

←リストの用意← ‘[1:4]’ と同等のスライスオブジェクト

←内容確認
←結果表示

>>> lst[ slice(1,6,2) ]Enter[2, 4, 6]←結果表示← ‘lst[1:6:2]’ と同等の記述

スライスオブジェクトにおいて添字を省略する場合は None を指定する．これを用いて先の例と同じ処理を試みる．

69

例．添字の省略（その 2）

Enter>>> a = ’abcdefghijklmnopqrstuvwxyz’←先頭位置の 0 を省略

Enter>>> s = slice(None,26)←文字列の用意>>> a[s]
Enter
←内容確認
’abcdefghijklmnopqrstuvwxyz’ ←文字列全体←最終位置の 26 を省略

Enter>>> s = slice(0,None)>>> a[s]
Enter
←内容確認
’abcdefghijklmnopqrstuvwxyz’ ←文字列全体
←両方省略

Enter

>>> s = slice(None,None)>>> a[s]
Enter
←内容確認
’abcdefghijklmnopqrstuvwxyz’ ←文字列全体
逆順の要素指定

2.4.5.3

添字に負の数を指定すると，末尾から逆の順に要素を参照することができる．例えば上の例において，a[-1] とす
ると，末尾の要素を参照したことになる．
（次の例参照）
例．逆順の要素指定（先の例の続き）>>> a[-1]Enter’z’←末尾の要素←末尾の要素を参照>>> a[-2]Enter←末尾から 2 番目の要素を参照’y’←末尾から 2 番目の要素
不連続な部分の取り出し

2.4.5.4
添字は[開始位置：終了位置：増分]のように増分を指定することができ，不連続な「飛び飛びの」部分を取り出すこともできる．
（次の例参照）
例．不連続な位置の要素の取り出し（先の例の続き）>>> a[::2]Enter’acegikmoqsuwy’←偶数番目の取り出し←先頭から 1 つ飛びの要素>>> a[1::2]Enter’bdfhjlnprtvxz’←奇数番目の取り出し← 1 番目から 1 つ飛びの要素

更に，増分には負（マイナス）の値を指定することもできる．
（次の例参照）
例．増分に負の値を与える（先の例の続き）>>> a[::-1]
Enter←逆順に取り出す’zyxwvutsrqponmlkjihgfedcba’ ←結果的に反転したことになる
参考）スライスオブジェクトを用いた例（先の例の続き）>>> s = slice(None,None,2)>>> a[s]Enter’acegikmoqsuwy’←偶数番目の取り出し←内容確認←先頭から 1 つ飛びの要素>>> s = slice(1,None,2)>>> a[s]Enter’bdfhjlnprtvxz’

Enter

Enter

←奇数番目の取り出し←内容確認← 1 番目から 1 つ飛びの要素>>> s = slice(None,None,-1)

Enter←逆順に取り出す>>> a[s]
Enter
←内容確認
’zyxwvutsrqponmlkjihgfedcba’ ←結果的に反転したことになる
2.4.6

データ構造の変換

表 12 のような関数（コンストラクタ）を使用して，リスト，タプル，セットの間でデータを相互に変換することが
できる．

70

表 12: データ構造 d を別の型に変換する関数（コンストラクタ）
関数（コンストラクタ） 説
明

list( d )d をリストに変換する

tuple( d )d をタプルに変換する

set( d )d をセットに変換する

例．データ構造の変換>>> list( (1,2,3) )[1, 2, 3]Enter←リストへの変換←処理結果>>> tuple( [1,2,3] )(1, 2, 3)Enter←タプルへの変換←処理結果>>> set( [1,2,3] ){1, 2, 3}←セットへの変換
←処理結果

Enter

辞書オブジェクトを表 12 の関数で変換すると，その辞書の全てのキーを要素とするものが得られる．
例．辞書を他の構造に変換する>>> dic={’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’}>>> list( dic )Enter[’apple’, ’orange’, ’lemon’]←リストへの変換←処理結果>>> tuple( dic )Enter(’apple’, ’orange’, ’lemon’)←タプルへの変換←処理結果>>> set( dic )Enter{’lemon’, ’orange’, ’apple’}←セットへの変換
←処理結果

2.4.7

Enter

←辞書の作成データ構造の要素を他のデータ構造の中に展開する方法

リストやタプル，文字列といったデータ構造の要素を，他のデータ構造の中に展開する方法について説明する．これを応用するとデータ構造の編集が容易になることがある．
例．リストの中に他のリストを展開する>>> x = [’d’,’e’,’f’]Enter←リストを x に用意>>> [’a’,’b’,’c’, *x , ’g’,’h’,’i’]Enter[’a’, ’b’, ’c’, ’d’, ’e’, ’f’, ’g’, ’h’, ’i’]

←リスト x をこのリストの中に展開←得られたリスト

このように，展開したいリストの先頭にアスタリスク「*」を付ける．
例．リストの中に複数のリストを展開する>>> x = [’a’,’b’,’c’]>>> y = [’d’,’e’,’f’]>>> z = [’g’,’h’,’i’]

Enter
Enter
Enter

←リスト x←リスト y←リスト z>>> [ *x, *y, *z ]Enter← x, y, z をこのリストの中に展開[’a’, ’b’, ’c’, ’d’, ’e’, ’f’, ’g’, ’h’, ’i’]←得られたリスト
文字列の要素を展開することもできる．
（次の例）
例．リストの中に文字列を展開する>>> x = ’def’Enter←文字列を x に用意>>> [’a’,’b’,’c’, *x , ’g’,’h’,’i’]Enter[’a’, ’b’, ’c’, ’d’, ’e’, ’f’, ’g’, ’h’, ’i’]

←文字列 x をこのリストの中に展開←得られたリスト

タプルの内部に他のデータ構造を展開することもできる．
（次の例）

71

例．タプルの中に文字列を展開する（先の例の続き）>>> (’a’,’b’,’c’, *x , ’g’,’h’,’i’)Enter(’a’, ’b’, ’c’, ’d’, ’e’, ’f’, ’g’, ’h’, ’i’)
2.4.8

←文字列 x をこのタプルの中に展開←得られたタプル

データ構造に沿った値の割当て（分割代入）

Python では，データ構造に沿った形で変数に値を割り当てること（分割代入：destructuring assignment）70 ができる．これにより，データ構造から簡単に部分要素を抽出することができ，データ構造の解析のための簡便なる手段を与える．以下に具体例を示す．
例．データ構造に沿った値の割当て (1)>>> [a,b] = [2,3]
>>> a
2
>>> b
3

Enter

←リストに沿った値の割当て

Enter

←値の確認

Enter
← a,b 共に値が割当てられていることがわかる

例．データ構造に沿った値の割当て (2)>>> (a,b) = [3,4]
>>> a
3
>>> b
4

Enter

←タプルに沿った値の割当て（右辺はタプル，リストどちらも可）

Enter

←値の確認

Enter
← a,b 共に値が割当てられていることがわかる

タプルに沿って値を割り当てる際は括弧 ‘( )’ を省略することができる．
（次の例参照）
例．データ構造に沿った値の割当て (3)>>> a,b = 3,4
>>> a
3
>>> b
4

Enter

Enter

←タプルに沿った値の割当て

←値の確認

Enter
← a,b 共に値が割当てられていることがわかる

例．データ構造に沿った値の割当て (4)>>> (a,b,c) = (1,2,(3,4))
>>> a
Enter
1
>>> b
Enter
2
>>> c
Enter
(3, 4)

Enter←複雑な構造に沿った値の割当て←値の確認← a,b,c 全て値が割当てられていることがわかる

この例の最初の代入文 ‘a,b = 3,4’ は Python では多く用いられる記述形式であるが，これは ‘=’ による代入処理が並列に働いたと見るべきではない．あくまで，データ構造に沿った形での値の割り当て（分割代入）である．

70 データ構造を分解して部分を取り出すことからアンパック（unpack）と呼ぶこともある．

72

2.4.8.1

応用例： 変数の値の交換

分割代入を応用すると，変数の値の交換が簡潔に記述できる．
例．変数の値の交換>>> x = 1

Enter

←変数 x の設定>>> y = 2

Enter

←変数 y の設定>>> x,y = y,x

←値の交換

Enter

>>> x
2

Enter

← x の値の確認

>>> y
1

Enter

← y の値の確認

分割代入の左辺に記述する変数の最後のものにアスタリスク ‘*’ の接頭辞を付けると，右辺の末尾の複数の要素を対応させることができる．
例．末尾の複数の要素を分割代入する

Enter>>> [a,b,*c] = [1,2,3,4,5,6]
>>> a
1

Enter

←変数 a の値の確認←変数 a の値

>>> b
2

Enter

←変数 b の値の確認←変数 b の値

←分割代入

←変数 c の値の確認←変数 c の値（末尾の複数の要素が得られている）

>>> c
Enter
[3, 4, 5, 6]割り当てるべき変数をアンダースコア ‘ ’ で省略することもできる．
（次の例参照）
例．値の割当てにおける変数の省略>>> (a,b, ) = (4,5,6)
>>> a
4
>>> b
5

Enter

← ‘ ’ による変数の省略

Enter

←値の確認

Enter
← a,b に値が割当てられていることがわかる

ただし厳密には，アンダースコア ‘ ’ も変数である．
（次の例）
例．アンダースコアに割り当てられたもの（先の例の続き）>>>
6
2.4.8.2

Enter←アンダースコアの内容を参照する←値をもっている
データ構造の選択的な部分抽出

以上のことを応用すると，複雑なデータ構造から選択的に部分を抽出することができる．
（次の例参照）
例．データ構造の部分抽出>>> [a,b,( ,c)] = [1,2,(3,4)]>>> a,b,c(1, 2, 4)
2.4.9

Enter

Enter

←入れ子になった構造←値の確認←データの部分抽出ができている．

データ構造のシャッフル，ランダムサンプリング

random モジュールの shuﬄe 関数を用いるとリストの要素の順序をシャッフルすることができる．
例．リストの要素のシャッフル>>> import randomEnter←モジュールの読込み>>> a = [0,1,2,3,4,5,6,7,8,9]>>> random.shuffle( a )

Enter

>>> a
Enter
←内容確認
[7, 8, 2, 6, 0, 3, 4, 9, 5, 1]

Enter←リストを用意←シャッフルの実行←シャッフルされている

73

shuﬄe 関数は，引数に与えたリストオブジェクトそのものを改変する．
データ構造に関する操作と shuﬄe 関数を組み合わせると，リスト以外のデータ構造もシャッフルすることができる．
例．文字列のシャッフル（先の例の続き）>>> s = ’abcdefghijklmn’>>> t = list( s )

Enter

Enter

←文字列を用意←それをリストに変換

>>> t
Enter
←内容確認
[’a’,’b’,’c’,’d’,’e’,’f’,’g’,’h’,’i’,’j’,’k’,’l’,’m’,’n’]>>> random.shuffle( t )Enter←リストになった←それをシャッフルして，>>> ’’.join(t)Enter←全要素を連結すると，’jbalcigdkfhmne’←結果として，文字列をシャッフルしたことになる
random モジュールの choice 関数を用いるとデータ構造の要素を 1 つ無作為抽出（ランダムサンプリング）することができる．
例．要素を 1 つ無作為に抽出する（先の例の続き）

Enter>>> random.choice( [0,1,2,3,4,5,6,7,8,9] )8>>> random.choice( ’abcdefghij’ )
’c’

Enter

←引数に与えたリストから無作為抽出←得られたもの←引数に与えた文字列から無作為抽出←得られたもの

複数の要素を重複を許す形で無作為抽出するには choices 関数を用いる．
例．複数の要素を重複を許して無作為に抽出する（先の例の続き）>>> random.choices( ’abcdefghij’, k=4 )[’e’, ’e’, ’b’, ’j’]Enter

←引数に与えた文字列から無作為に 4 つ抽出←得られたもの

このように引数「k=抽出個数」を与える．
複数の要素を重複しない形で無作為抽出するには sample 関数を用いる．
例．複数の要素を重複せず無作為に抽出する（先の例の続き）

Enter>>> random.sample( [0,1,2,3,4,5,6,7,8,9], 3 )[2, 7, 1]>>> random.sample( ’abcdefghij’, 3 )[’h’, ’e’, ’j’]
2.4.10Enter←リストから 3 つを無作為抽出←得られたもの←文字列から 3 つ無作為抽出←得られたもの

データ構造へのアクセスの速度について

Python の基本的なデータ構造であるリスト，セット，辞書それぞれについてアクセスの速度を評価すると概ね次のようになる．
● スライスに整数のインデックスを与えて要素にアクセスする形態（「n 番目の要素」を指定するアクセス方法）
ではリストは高速にアクセスできるデータ構造である．
● in 演算子などで要素のメンバシップを調べる（ある要素が含まれるかを調べる）場合はリストが最も遅く，セッ
トと辞書は共に高速である．
（セットと辞書はほぼ同等の速度）
データ構造のアクセス速度の比較を行うサンプルプログラムを付録「I.1 リスト／セット／辞書のアクセス速度の比較」（p.424）で示す．

74

2.5

制御構造

2.5.1

繰り返し (1)：for

処理の繰り返しを実現する文の 1 つに for がある．
《 for による繰り返し 》
書き方：

for

変数

in

データ構造:（変数を参照した処理）「変数を参照した処理」は繰り返しの対象となるプログラムの部分である．この部分は for の記述開始位置よりも右にインデント（字下げ）する必要がある．またこの部分には複数の行を記述することができるが，その場合は各行に同じ深さのインデントを施さなければならない．

for 文は繰り返しの度に「データ構造」から順番に要素を取り出してそれを「変数」に与える．繰り返しに使用する「データ構造」にはリストの他，タプルや文字列など様々なものが指定できる．

2.5.1.1

イテラブルなオブジェクト

for 文をはじめとする繰り返し制御に使用できるデータ構造のことをイテラブル（iterable）なオブジェクト71 であるという．先に解説したリスト，タプル，文字列，辞書，セット，後に説明する range オブジェクトはイテラブルなオブジェクトであり，他にもいくつか存在する．特に，セットには順序の概念が無いがイテラブルであることに注意すること．
後の「2.5.1.8 イテレータ」（p.78）で説明するイテレータもイテラブルなオブジェクトであるが，それらは同義ではないことに注意すること．
以後，イテラブルなオブジェクトを単に「イテラブル」と表記することがある．

2.5.1.2「スイート」の概念

for 文の制御対象となる「同じインデント位置から始まる一連のプログラムの部分」のことをスイート（suite）と呼ぶ．for 文だけでなく，後で解説する各種の制御構造においても「スイート」を制御対象とする．また，関数やクラスの定義（これらについても後で説明する）においても「スイート」の概念が前提となる．

1 つのスイートを構成するためのインデントには，スペースキーで入力する「空白文字」以外にも Tab キーで入力する「タブ文字」が使える．ただし，インデントは空白文字やタブ文字の「文字数」で決まるものであるので，インデントの見た目の位置とインデントの文字数には注意が必要（図 5 の例）である．

for i in range(3):スペース 4 つprint(i,end=',')

タブ文字 1 つprint(2*i,end=',')
見た目は同じインデント位置でも，実際は異なるインデント位置

print(3*i)

図 5: 誤ったインデントの例

for 文を用いたサンプルプログラム test04-1.py を次に示す．
プログラム：test04-1.py
1
2
3
4
5
6
7

# coding : utf -8# 例1 ： リ ス ト の 全 て の 要 素 を 表 示 す る
for word in [ ’ book ’ , ’ orange ’ , ’ man ’ , ’ bird ’]:print ( word )# 例2 ： 繰 り 返 し 対 象 が 複 数 の 行 の 場 合
for x in [1 ,3 ,5 ,7]:
print (" x =" , x )71 「反復可能なオブジェクト」という意味．

75

8
9
10
11
12
13
14
15
16

print (" x ^3=" , x **3)
print (" x ^10=" , x **10)
print (" x ^70=" , x **70)# 例3 ： 上 記 と 同 様 の 処 理
for x in range (1 ,9 ,2):
print (" x =" , x )print (" x ^3=" , x **3)
print (" x ^10=" , x **10)
print (" x ^70=" , x **70)# rangeで作成した数列を与える

このプログラムの例 1 の部分（3〜4 行目）は与えられたリストの要素を先頭から 1 つずつ変数 word にセットしてそれを出力するものである．この例 1 の部分の実行により出力結果はbook
orange
man
bird

となる．
例 2 の部分（6〜10 行目）は 1 から 7 までの奇数に対して 3 乗，10 乗，70 乗を計算して出力するものである．このよ
うに同じインデント（字下げ）を持つ複数の行（スイート）を繰り返しの対象とする72 ことができる．この例 2 の部
分の実行により出力結果は
x= 1
x＾3= 1x＾10= 1x＾70= 1x= 3
x＾3= 27x＾10= 59049
x＾70= 2503155504993241601315571986085849
x= 5x＾3= 125x＾10= 9765625
x＾70= 8470329472543003390683225006796419620513916015625
x= 7x＾3= 343x＾10= 282475249
x＾70= 143503601609868434285603076356671071740077383739246066639249となる．

for 文では，与えられたデータ構造の要素を順番に取り出す形で繰り返し処理を実現するが，長大な数列の各項に対して処理を繰り返す場合（例えば 1〜1 億までの繰り返し）には直接にデータ列を書き綴る方法は適切ではない．繰り返し処理に指定する数列の代わりに，後に説明する range オブジェクトを使用することができる．先のプログラムの例 3 の部分（12〜16 行目）はこれを用いて繰り返しを実現するものであり，例 2 の部分と同様の動作をする．

2.5.1.3

スイートが 1 行の場合の書き方

1 行のみから成るスイートは for と同じ行に記述することができる．
例．1 行のみのスイートを繰り返す for 文（対話モードでの例）>>> for i in range(3): print(i)
Enter
...
Enter
← for 文の入力の終了← 1 行のみのスイートの繰り返し

←出力開始

0
1
2

for 文に限らず，他の制御構造，関数やクラスの定義においても，1 行のみのスイートはコロン「:」に続けて記述することができる．

2.5.1.4

range 関数，range オブジェクト

range クラスのオブジェクトは，実際に要素を書き並べたリストと似た性質を持つ．
72 C や Java をはじめとする多くの言語では，ソースプログラムのインデント（字下げ）にはプログラムとしての意味はない．

制御対象のプログラムの範囲をインデントによって指定する言語は Python を含め少数派である．

76

《 range オブジェクト 》
書き方 1：

range(n)意味：

0 以上 n 未満の整数列

書き方 2：

range(n1 ,n2 )意味：

n1 以上 n2 未満の整数列

書き方 3：

range(n1 ,n2 ,n3 )意味：

n1 以上 n2 未満の範囲の公差 n3 の整数列

書き方 1 の例． range(10)→[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] と同等

書き方 2 の例． range(5,10)→[5, 6, 7, 8, 9] と同等

書き方 3 の例． range(1,10,2)→[1, 3, 5, 7, 9] と同等

この range オブジェクトを応用したのが先のプログラム test04-1.py の例 3（12〜16 行目）の部分である．

range オブジェクトは，基本的にはリストと同様の扱いが可能で，長大な数列を扱う場合に記憶資源管理の面で有利である．range オブジェクトを生成する際の range(…) の記述は range 関数73 である．
例．range オブジェクトの扱い>>> r = range(10)Enter← range オブジェクトの生成←内容の確認←結果の表示>>> r
Enterrange(0, 10)>>> type( r )Enter←データ型の確認<class ’range’>←’range’ 型であることがわかる>>> r[3]Enter3←結果の表示←要素（3 番目）を取り出すことができる．

>>> list( r )Enter←リストに変換[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]←変換結果
2.5.1.5

辞書の for 文への応用

辞書型オブジェクトを for 文に与えると，辞書のキーが順番に得られる．
例．for 文に辞書を与える>>> d = {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’}

Enter←辞書型オブジェクト>>> for e in d: Enter←辞書オブジェクトのキーが e に順番に得られる...
print( e, ’->’, d[e] )Enter←辞書オブジェクトのキーと値を表示
...
Enter
← for 文の終了
apple -> りんご
orange -> みかん
lemon -> レモン
2.5.1.6←以降，出力for 文における elsefor 文の記述に else を付けると，終了処理を実現できる．
《 else を用いた for 文の終了処理 》
書き方：

for

変数

in

データ構造:（変数を参照した処理）
else:（終了処理）

for による繰り返しが終了した直後に 1 度だけ「終了処理」を実行する．ただし，break （p.83「2.5.3 繰り返
しの中断とスキップ」で解説する）で繰り返しを中断した場合は「終了処理」は実行されない．
これは Python 以外の言語ではあまり見られない便利な構文である．

73 厳密には range クラスのコンストラクタである．

77

2.5.1.7

for を使ったデータ構造の生成（要素の内包表記）

for の別の使い方として，データ構造の生成がある．次の例について考える．
例．整数の 2 乗のリストを作る>>> [ x**2 for x in range(10) ]Enter[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]←リストの生成←得られたリスト

このようにして，様々な値のリストを生成できる．
《 for を使ったデータ構造の生成 》：要素の内包表記
リストの生成：[ 繰り返し変数を使った要素の表現 for 繰り返し変数 in データ構造 ]集合，辞書の生成：{ 繰り返し変数を使った要素の表現 for 繰り返し変数 in データ構造 }例．文字列中の文字を要素とするリスト74>>> [c for c in ’abcde’]Enter←リストの生成[’a’, ’b’, ’c’, ’d’, ’e’]
←得られたリスト
このように，in の後ろにイテラブルなデータ構造を与えてリストを生成できる．
例．辞書の生成>>> d = { x:x**2 for x in range(10) }
>>> d
Enter
←内容の確認{0: 0, 1: 1, 2: 4, 3: 9, 4:>>> d[4]Enter
16←結果の表示Enter16, 5:

25, 6:← 0〜9 までの 2 乗の値を保持する辞書 d の生成

36, 7:

49, 8:←キー 4 に対する値

64, 9: 81}↑結果の表示例．セットの生成>>> { x**2 for x in range(10) }Enter{0, 1, 64, 4, 36, 9, 16, 49, 81, 25}← 0〜9 までの 2 乗の値を保持するセットの生成←結果の表示▲注意▲ 要素の内包表記によるタプルの生成では，ジェネレータという特別なデータ列となる．
例．内包表記でタプルを作る試み>>> t = ( 2*x for x in range(4) )Enter←内包表記の形式によるタプルの生成
←内容確認
>>> t
<generator object <genexpr> at 0x0000013C97AFC5C8> ←「ジェネレータ」となっている>>> list( t )[0, 2, 4, 6]

Enter←リストに変換可能←結果の表示ジェネレータは制御のための高度な方法を与える．詳しくは「4.7 ジェネレータ」（p.270）で解説する．
■ 条件付きの内包表記
要素の内包表記において if を記述して条件を付けることができる．
例．0〜19 の範囲の 3 の倍数を求める>>> [ x for x in range(20) if x%3==0 ]Enter[0, 3, 6, 9, 12, 15, 18]←結果の表示← if で条件を付ける

if の後に記述する条件式に関しては「2.5.4.1 条件式」（p.84）で解説する．
2.5.1.8

イテレータ

順番に値を取り出すデータ構造にイテレータがある．イテレータは要素を取り出す度にその要素が削除されてゆく
データ構造であり，for などの繰り返し処理のためのイテラブルなオブジェクトとして用いることができる．イテレー
タは関数 iter で生成することができる．
74 この例はデータ構造の分解を簡単な形で示すためのものである．同様の処理はより簡単に list(’abcde’) として実現できる．

78

例．イテレータによる繰り返し処理>>> it = iter( [1,2,3] )

←

Enter

リスト [1,2,3] をイテレータに変換←繰り返し処理の記述開始←要素を表示する処理←繰り返し処理の記述終了>>> for m in it:...
print(m)
...
Enter

Enter
Enter

1
2
3

←出力（ここから）←出力（ここまで）この例を見る限り，it はリスト [1,2,3] と同様のオブジェクトのように思われるが，次の例について考える．
例．next 関数による要素の取り出し>>> it = iter( [1,2,3] )

Enter

←

リスト [1,2,3] をイテレータに変換>>> next(it)Enter
1←最初の要素←次の要素の取り出し>>> next(it)
Enter
2
←次の要素

←次の要素の取り出し>>> next(it)Enter
3←最後の要素←次の要素の取り出し>>> next(it)Enter←次の要素の取り出しを試みると…

Traceback (most recent call last):←要素が無いことによる例外が発生
File "<stdin>", line 1, in <module>
StopIteration
この例の様に，関数 next によってイテレータの次の要素が取り出される．ただし，取り出すべき次の要素が無い場合
は例外 StopIteration が発生する．
イテレータは，リストのような要素を保持するためのデータ構造として扱うべきではなく，「繰り返し構造」の処理対象として扱うべき特殊なデータ構造である．
ここでは説明を簡単にするため，リストからイテレータを生成する処理を例示した．実際には，ストリーム（入力装置や通信装置をはじめとするデータの発生源）を含んだ多くのものがイテレータのような振る舞いをする75 ．
イテレータは要素を参照することでその要素が取り除かれるものであり，その意味では破壊的なデータ構造である．
従って，イテレータの内容を破壊されないものとして扱うには，リストなどの別のデータ構造に変換する必要がある．
例えば，イテレータ it を次のようにしてリスト L に変換することができる．

L = list( it )ただし，この処理の後，it の内容は失われる．
（it の参照が終了したことによる）また，得られる要素数が長大になる可能性のあるイテレータ（ファイル入力など）や，終端時期が不明のイテレータ（通信デバイスからの入力など）
を list コンストラクタなどで一括変換すべきではない．
イテレータはイテラブルなオブジェクトであるが，それらは同義ではないことに注意すること．
（次の例）
例．リストがイテレータでないことの確認>>> lst = [1,2,3]Enter←リスト lst の作成>>> next( lst )Enter←それに対して next 関数の実行を試みると…
Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: ’list’ object is not an iterator
next 関数はイテレータ（とその拡張クラス）に対してのみ実行できるものであり，この例ではリストに対して実行できないことが示されている．すなわちイテレータとは，next 関数を始めとする特定の仕様を満たすものとして定義される．プログラマが独自のイテレータを定義する方法に関しては，後の「2.8.6 イテレータのクラスを実装する方法」（p.148）で解説する．
イテレータと関連の深いものにジェネレータがある．これについては「4.7 ジェネレータ」（p.270）で説明する．
75 厳密には，ファイルや通信装置はイテレータではない．

79

2.5.1.9

分割代入を用いた for 文

for の後に変数のタプルを与えることで，データ構造の分割代入ができる．
例．分割代入でデータ構造の要素を分解して取り出す←リストを要素とするリスト q

Enter>>> q = [[1,2],[3,4],[5,6]]>>> for (x,y) in q: Enter← q の要素を x, y に分解しながら取り出す...
print(’x=’,x,’y=’,y)Enter←それらを出力...
Enter← for 文の終了
x= 1 y= 2
x= 3 y= 4
x= 5 y= 6←出力

この方法は，後に説明する zip オブジェクトや enumerate を用いた繰り返し処理において役立つ．

for の後のタプルは括弧 ‘(…)’ を省略して ‘for x,y in q:’ などと記述しても良い．
2.5.1.10

zip 関数と zip オブジェクト

zip 関数を用いると，複数のイテラブルオブジェクト（リストなど）を束ねて 1 つのイテラブル（zip オブジェクト）を生成することができる．
（次の例参照）
例．3 つのリストを束ねて 1 つのイテラブルを生成する (1)>>> q1 = [1,2,3]
Enter>>> q2 = [’one’,’two’,’three’]Enter>>> q3 = [’ 一’,’ 二’,’ 三’]Enter>>> z = zip( q1, q2, q3 )Enter

← 1 番目のリストの生成← 2 番目のリストの生成← 3 番目のリストの生成←それら 3 つを束ねて z にする>>> for (a,b,c) in z: Enter← z から要素を 1 つずつ取り出すループ...
print(a,’:’,b,’:’,c)
Enter
←出力処理
...
Enter
←繰り返し記述範囲の終わり
1 :
2 :
3 :

one : 一two : 二three : 三

←出力（1 番目）
←出力（2 番目）
←出力（3 番目）

これは，3 つのリスト q1, q2, q3 を束ねて 1 つのイテラブル z を生成し，それを用いて繰り返し処理を行っている例
である．

zip 関数で得られるオブジェクトは「zip オブジェクト」と呼ばれる特殊なイテラブルである．
（次の例参照）
例．3 つのリストを束ねて 1 つのイテラブルを生成する (2)>>> q1 = [1,2,3]
Enter>>> q2 = [’one’,’two’,’three’]Enter>>> q3 = [’ 一’,’ 二’,’ 三’]Enter>>> z = zip( q1, q2, q3 )

Enter

>>> z
Enter
← z を確認<zip object at 0x000002E1BC3B9D08>← 1 番目のリストの生成← 2 番目のリストの生成← 3 番目のリストの生成←それら 3 つを束ねて z にする← zip オブジェクトであることがわかる>>> list(z)Enter← z をリストに変換して内容を確認[(1, ’one’, ’ 一’), (2, ’two’, ’ 二’), (3, ’three’, ’ 三’)]←内容表示>>> list(z)Enter← z の内容を再度確認すると…
[]←参照後なので空になっている
長さの異なるデータ列を zip で束ねると，最も長さの短い列にイテラブルのサイズが制限される．

80

例．長さの異なるリストを束ねて zip オブジェクトを生成する>>> q1 = [1,2,3,4]
Enter>>> q2 = [’one’,’two’,’three’]>>> z = zip( q1, q2 )Enter

←長いリスト←短いリスト←それらを束ねて z にするEnter>>> for (a,b) in z: Enter← z から要素を 1 つずつ取り出すループ...
print(a,’:’,b)
Enter
←出力処理
...
Enter
←繰り返し記述範囲の終わり
1 :
2 :
3 :

one
two
three

←出力（1 番目）
←出力（2 番目）
←出力（3 番目：短い方のリストのサイズ）【zip オブジェクトの展開】

zip 関数によって束ねられた zip オブジェクトはアスタリスク ’*’ を用いて他のデータ構造（リストなど）の内部に展開することができる．
例．リストの内部に zip オブジェクトを展開する>>> a = [’a1’,’a2’,’a3’]>>> b = [’b1’,’b2’,’b3’]Enter>>> z = zip(a,b)

Enter
Enter

← 1 番目のリストの生成← 2 番目のリストの生成← zip 関数で束ねる>>> [’a0’,’b0’,*z,’a4’,’b4’]
Enter←それをリストの内部に展開する[’a0’, ’b0’, (’a1’, ’b1’), (’a2’, ’b2’), (’a3’, ’b3’), ’a4’, ’b4’] ←展開結果
これは「2.4.1.14 リストの内部に他のリストを展開する方法」（p.56）で解説した内容と同じ手法である．また同様の方法で，関数呼び出しの際の引数並びに zip オブジェクトを展開して渡すことができる．
（次の例参照）
例．zip オブジェクトの展開>>> a = [’a1’,’a2’,’a3’]>>> b = [’b1’,’b2’,’b3’]>>> c = [’c1’,’c2’,’c3’]>>> z = zip(a,b,c)

Enter

Enter
Enter
Enter

← 1 番目のリストの生成← 2 番目のリストの生成← 3 番目のリストの生成← zip 関数で束ねる>>> print( *z )Enter
← zip オブジェクトを展開して print 関数に渡す(’a1’,’b1’,’c1’) (’a2’,’b2’,’c2’) (’a3’,’b3’,’c3’) ← zip オブジェクトの要素が順番に表示される
ここで注意しなければならない点がある．zip オブジェクトをアスタリスク ‘*’ で展開したものを単独で取得することはできない．
（次の例参照）
例．zip オブジェクトの展開（失敗例：先の続き）>>> z = zip(a,b,c)>>> *z

Enter

Enter

← zip 関数で束ねる← zip オブジェクトの展開

File "<stdin>", line 1←エラー発生SyntaxError: can’t use starred expression here

←文法エラー

関数の引数に ‘*’ を記述することに関しては，後の「2.7.1.3 引数の個数が不定の関数」（p.123）で詳しく説明する．
■ 参考
関数呼び出し時のアスタリスク ‘*’ で展開された要素は，再び zip 関数で束ねることができる．このことが理解できる例を次に示す．
例．アスタリスク ‘*’ による展開と再 zip 化の例（先の続き）>>> z = zip(a,b,c)Enter← zip 関数で束ねる>>> print( *zip(*z) )Enter ←展開，zip，展開と連鎖実行(’a1’,’a2’,’a3’) (’b1’,’b2’,’b3’) (’c1’,’c2’,’c3’) ←結果
このような結果となる理由に関して考察されたい．

81

2.5.1.11

enumerate によるインデックス情報の付与

イテラブルから要素を取り出しながら繰り返し処理を行う際，処理対象の要素のインデックスが処理に求められることがしばしばある．
（下記の例）
例．データ要素のインデックスを繰り返し処理の中で使用する例>>> s = ’ あいう’>>> i = 0

Enter

←処理対象のデータ列←要素のインデックスの初期化

Enter>>> for m in s: Enter←繰り返し処理の記述開始←要素のインデックスを用いた処理...
print(i,’ 番目は「’,m,’」’)
Enter
...
i += 1
Enter←次回のインデックスを算出
...
Enter
←繰り返し処理の記述終了
0 番目は「 あ 」
1 番目は「 い 」
2 番目は「 う 」

←処理結果
←処理結果
←処理結果

この例では繰り返し処理の前に変数 i を用意して開始のインデックス 0 を設定し，繰り返し処理の度に 1 を加えるという手法で，処理中の要素のインデックスを得ている．enumerate を用いると，同様の処理を更に簡潔な形で実現することができる．
例．enumerate を用いた実装>>> s = ’ あいう’Enter

←処理対象のデータ列>>> for (i,m) in enumerate(s): Enter←繰り返し処理の記述開始（インデックス情報付き）...
print(i,’ 番目は「’,m,’」’)
Enter←要素のインデックスを用いた処理
...
Enter
←繰り返し処理の記述終了
0 番目は「 あ 」
1 番目は「 い 」
2 番目は「 う 」

←処理結果
←処理結果
←処理結果

enumerate で生成されたオブジェクトは enumerate オブジェクトであり，イテラブルである．
（次の例参照）
例．enumerate オブジェクトの内容確認（先の例の続き）>>> enumerate(s)
Enter
←内容確認
<enumerate object at 0x0000015A80298E58>← enumerate オブジェクトであることがわかる>>> list( enumerate(s) )Enter←リストに変換して内容確認[(0, ’ あ’), (1, ’ い’), (2, ’ う’)]
←各要素がインデックス付きのタプルとなっている
enumerate による付番の開始値を変更するには，enumerate の 2 番目の引数に開始値を与える．
例．enumerate による付番の開始値を 1 にする（先の例の続き）>>> list( enumerate(s,1) )Enter[(1, ’ あ’), (2, ’ い’), (3, ’ う’)]← enumerate の第 2 引数に開始値を与える← 1 からの付番となっている

付番の開始値はキーワード引数 start=開始値 として与えることもできる．
例．enumerate による付番の開始値を 2 にする（先の例の続き）>>> list( enumerate(s,start=2) )Enter←キーワード引数 start に開始値を与える[(2, ’ あ’), (3, ’ い’), (4, ’ う’)]← 2 からの付番となっている

82

繰り返し (2)：

2.5.2

while

条件判定76 に基いて処理を繰り返すための while 文がある．
《 while による繰り返し 》
書き方：

while 条件:
（繰り返し対象の処理）「条件」を満たす間「繰り返し対象の処理」を繰り返す．
「繰り返し対象の処理」（スイート）は while の記述開始位置よりも右にインデント（字下げ）される必要がある．
（for 文の場合と同様）《 else を用いた while 文の終了処理 》
書き方：

while 条件:
（繰り返し対象の処理）
else:（条件が不成立の場合の処理）「条件」が不成立になった場合に 1 度だけ「条件が不成立の場合の処理」を実行して while 文を終了する．ただし，後で説明する break で繰り返しを中断した場合は「条件が不成立の場合の処理」の部分は実行されない．

while 文を用いたサンプルプログラム test04-2.py を次に示す．
プログラム：test04-2.py
1
2
3
4
5
6
7

# coding : utf -8
n = 0
while n < 10:
print ( n )n += 2else :
print ( ’ end ’)

このプログラムの実行により出力結果は
0
2
4
6
8
end

となる．
このサンプルの 5 行目の ‘+=’ は累算代入演算子77 である．すなわちこれは，n = n + 2と記述したものと同等である．

2.5.3

繰り返しの中断とスキップ

for や while による処理の繰り返しは break で中断して抜け出すことができる．また，繰り返し対象の部分で continueを使うと，繰り返し処理を次の回にスキップできる．
（C や Java と同じ）

76 条件の記述に関しては「2.5.4.1 条件式」
（p.84）にまとめている．
77 C や Java のそれと同じ働きを持つ．

83

2.5.4

条件分岐

条件判定により実行する処理を選択するには if 文を使用78 する．
《 if 文による条件分岐 》（その１）
書き方：

if

条件:
（対象の処理）「条件」が成立したときに「対象の処理」を実行する．
「対象の処理」（スイート）は if の記述開始位置よりも右にインデント（字下げ）される必要がある．
（for 文の場合と同様）《 if 文による条件分岐 》（その２）
書き方：

条件:
（対象の処理）else:（条件が不成立の場合の処理）

if「条件」が不成立であった場合に else 以下の「条件が不成立の場合の処理」を実行する．

《 if 文による条件分岐 》（その３）
書き方：

条件 1:
（条件 1 を満たした場合の処理）
elif 条件 2:（条件 2 を満たした場合の処理）：
else:（全ての条件が不成立の場合の処理）

if

複数の条件分岐を実現する場合にこのように記述する．

2.5.4.1

条件式

条件として記述できるものは表 13 のような比較演算子を用いた式や，それらを論理演算子（表 14）で結合（装飾）した式である．

比較演算子を用いた条件式説

表 13: 比較演算子
明

a == ba と b の値が等しい場合に True，それ以外の場合は False．

a != ba と b が異なる場合に True，等しい場合は False．

a＞b

a が b より大きい場合に True，それ以外の場合は False．

a ＞= ba が b 以上の場合に True，それ以外の場合は False．

a＜b

a が b より小さい場合に True，それ以外の場合は False．

a ＜= ba が b 以下の場合に True，それ以外の場合は False．
表 14: 論理演算子

論理演算子を用いた条件式説明P and Q

P と Q が共に True の場合に True，それ以外の場合は False．

P or Q

P と Q の少なくとも 1 つが True の場合に True，それ以外の場合は False．

not P

P が False の場合に True，それ以外の場合は False．

78 Python には C や Java のような switch 文はないが，Python3.10 から高度な分岐処理のための構文が導入された．これに関しては「2.11 構造的パターンマッチング」（p.165) で解説する．

84

条件式はそれ自体が真理値の値（True か False）を返す．
※ 「if〜else…」の構文は 3 項演算子として記述することも可能である．これに関しては「2.9.4 3 項演算子としての if〜else…」（p.161）のところで解説する．

2.5.4.2

比較演算子の連鎖

表 13 の比較演算子は連鎖する形で記述することができる．
例．比較演算子の連鎖：その 1>>> x = 3

Enter>>> 1 < x < 4
Enter
True
←判定結果

←比較演算子の連鎖

更に長く記述することもできる．
例．比較演算子の連鎖：その 2（先の例の続き）>>> y,z = 5,7

Enter>>> 1 < x < y < z < 9
True
←判定結果

Enter

←比較演算子の連鎖>>> 9 > z > y > x > 1
True
←判定結果

Enter

←比較演算子の連鎖‘==’，‘!=’ も使用できる．
例．比較演算子の連鎖：その 3（先の例の続き）>>> 3 == x < y
Enter
True
←判定結果

← ‘==’ を含む判定>>> 1 != x < y
Enter
True
←判定結果

← ‘!=’ を含む判定

比較演算子を連鎖することで複雑な比較を簡潔に記述することができる．

85

2.5.4.3

各種の「空」値に関する条件判定

if 文の条件式の部分に各種の「空」値を与えた場合の条件判定がどのようになるかをサンプルプログラム emptyCheck0.py の実行によって例示する．このプログラムは，変数 cnd に各種の「空」値を与え，それを条件式として if
文で判定するものである．
プログラム：emptyCheck0.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# coding : utf -8# 各 種 の ’空 ’ 値 に 関 す る 判 定# - - - N o n e を 条 件 式 に 与 え た 場 合 --cnd = Noneif cnd :print ( ’ hit ’)else :
print ( cnd , ’ は 偽 の 扱 い で す ． \ n ’)
# - - - N o n e で あ る か ど う か の 判 定 --if cnd is None :print ( cnd , ’ is None に よ る 判 定 ’ )print ( cnd , ’ は None で す ． \ n ’)if cnd is not None :print ( ’ hit ’)else :
print ( cnd , ’ is not None に よ る 判 定 ’ )print ( cnd , ’ は None で す ． \ n ’)
# - - - 空 タ プ ル ’() ’ を 条 件 式 に 与 え た 場 合 --cnd = ()if cnd :print ( ’ hit ’)else :
print ( cnd , ’ は 偽 の 扱 い で す ． ’ )# - - - 空 リ ス ト ’[] ’ を 条 件 式 に 与 え た 場 合 --cnd = []if cnd :print ( ’ hit ’)else :
print ( cnd , ’ は 偽 の 扱 い で す ． ’ )# - - - 空 集 合 ’ set () ’ を 条 件 式 に 与 え た 場 合 --cnd = set ()if cnd :print ( ’ hit ’)else :
print ( cnd , ’ （ 空 集 合 ） は 偽 の 扱 い で す ． ’ )# - - - 空 辞 書 ’{} ’ を 条 件 式 に 与 え た 場 合 --cnd = dict ()if cnd :print ( ’ hit ’)else :
print ( cnd , ’ （ 空 辞 書 ） は 偽 の 扱 い で す ． ’ )# - - - ゼ ロ 0 を 条 件 式 に 与 え た 場 合 --cnd = 0
if cnd :print ( ’ hit ’)else :
print ( cnd , ’ は 偽 の 扱 い で す ． ’ )# - - - 空 文 字 列 ’’ を 条 件 式 に 与 え た 場 合 --cnd = ’’if cnd :print ( ’ hit ’)else :
print ( ’ 空 文 字 列 ’ , cnd , ’ は 偽 の 扱 い で す ． ’ )86

このプログラムを実行した結果の例を次に示す．
None は偽の扱いです．
None is None による判定
None は None です．
None is not None による判定
None は None です．
() は偽の扱いです．
[] は偽の扱いです．
set() （空集合）は偽の扱いです．
{} （空辞書）は偽の扱いです．
0 は偽の扱いです．
空文字列 は偽の扱いです．

このプログラムの実行によって，次に示す値が条件式として「偽」となることがわかる．

None（ヌルオブジェクト）( )（空のタプル）[ ]（空リスト）{ }（空の辞書）

0（ゼロ）’’（空文字列）

set()（空セット）「空」値でないもの（非「空」値）を条件式に与えると基本的には「真」となる．また，ヌルオブジェクトかどうかを判定するには is None や is not None を用いて記述する．
（is に関しては後の「2.5.4.4 is 演算子による比較」を参照
のこと）
▲注意▲

「空」値と非「空」の論理演算「空」値と非「空」を組合せた論理演算（and,or,not）には注意すること．すなわち，「空」値を「偽」，非「空」値
を「真」と見做して論理和や論理積といった演算をすると，結果としてどのような値となるかは予め個別に確認した方が良い．
■ 多量のデータに対する条件の一括判定「2.9.5 all, any による一括判定」（p.161）で解説する all 関数や any 関数を応用すると，多量のデータに対する条
件判定を一括して実行することが可能となる．

2.5.4.4

is 演算子による比較「同じ値か」どうかを判定するには演算子 ‘==’ を用いるが，これに対して同一のオブジェクトかどうかを判定する場合には ‘is’ を用いる．
次の例のような，2 つの変数に割り当てられたリストの比較について考える．
例．リストの比較>>> a = [1,2,3]>>> b = [1,2,3]

Enter
Enter

←変数 a に与えられたリスト←変数 b に与えられたリスト>>> a == bEnter
←変数 a,b の値が同じかどうかを検査
True←真（a,b の値は同じである）
次に ‘is’ を用いて検査する．
例．リストの比較（先の例の続き）>>> a is bEnter
←変数 a,b が同一のオブジェクトかどうかを検査
False←偽（a,b は別のオブジェクトである）
この例から「a,b はそれぞれ異なるオブジェクトである」ことがわかる．これは「変数 a,b はそれぞれ，同じ値を持つ
別々のオブジェクトである」と言い換えることができる．
オブジェクトの比較においては「同値」であることと同一性の違いを意識するべきである．

Python 処理系の中で扱われるオブジェクトは，それが廃棄されるまで独自の識別値79 を持っており，オブジェクトの同一性は，そのオブジェクトの識別値によって判定される．オブジェクトの識別値は id 関数で調べることができる．
79 CPython 実装では，識別値はそのオブジェクトを格納しているメモリのアドレスである．

87

例．id 関数による識別値の調査（先の例の続き）>>> id(a)Enter2089578189128←変数 a が保持するオブジェクトの識別値を調べる←変数 a の値の識別値>>> id(b)Enter2089578223496←変数 b が保持するオブジェクトの識別値を調べる←変数 b の値の識別値

この例から，変数 a，b が保持するリストは同じ要素で構成されるが，実体としては別のものであることがわかる．
オブジェクトに対する識別値は，処理系がそのオブジェクトを生成する時点で決める．
先の例で変数 a にリストが割り当てられていたが，更に c = a として変数 c に変数 a の値を割り当てると，変数c は変数 a と同一のリストを指し示す．
例．「=」によって割り当てられたリストの識別値を調べる（先の例の続き）>>> c = aEnter

←変数 a のリストを変数 c に割り当てる>>> id(a)Enter2089578189128←変数 a の値の識別値>>> id(c)Enter2089578189128←変数 c が保持するオブジェクトの識別値を調べる←変数 a の値の識別値と同じ>>> a is c
True
2.5.4.5

Enter←変数 a，c の同一性を調べる←判定結果

値の型の判定（p.41）で値の型を検査する方法について解説したが，実際の条件判定の処理において型の先の「2.3.11 型の検査」
判定を行うための具体的な方法には次に示すような複数のものがある．

1) type(値) is 型名2) type(値) == 型名3) isinstance(値, 型名)
上記 3 つの判定方法における処理時間はどれも概ね同様であるが，2) の方法が若干遅く，3) の方法が若干早い傾向が
ある．

88

入出力

2.6

コンピュータのプログラムは各種の装置（デバイス）から入力を受け取って情報処理を行い，処理結果を各種の装置に出力する．入出力のための代表的な装置としては，● ディスプレイ● キーボード● ファイル（ディスク）が挙げられる80 ．特にディスプレイとキーボードは常に使用可能なデバイスであることが前提とされている．このため，ディスプレイとキーボードはそれぞれ標準出力，標準入力と呼ばれている．
ここでは，これら 3 種類のデバイスに対する入出力の方法について説明する．
標準出力

2.6.1

通常の場合，標準出力はディスプレイを示している．これまでの解説にも頻繁に使用してきた print 関数は標準出力に対して出力するものであり，引数として与えた値を順番に標準出力に出力する．print 関数は任意の個数の引数を取る．

2.6.1.1

出力データの書式設定

表示桁数や表示する順番などの書式設定を施して出力をする際には，出力対象のデータ列（値の並び）を書式編集して一旦文字列にしてから出力することが一般的である．

format メソッド

■ 書式設定の方法 (1)

文字列に対する format メソッドを用いて書式編集をすることができる．具体的には {} を含む文字列に対して format
メソッドを実行すると，format の引数に与えた値が {} の部分に埋め込まれる．この {} を format メソッドのプレー
スホルダ（placeholder）と呼ぶ．
例．プレースホルダへの値の埋め込み>>> s = ’{}, {}, {}’.format(’one’,’two’,’three’)

Enter

←書式編集

>>> print(s)Enter←編集結果の確認
one, two, three←編集されて出力された結果{} の中に埋め込みの順番を表すインデックス（0 で始まる整数）を与えると，format の引数を埋め込む順番の制御ができる．
例．埋め込み位置の制御>>> s = ’{2}, {1}, {0}’.format(’one’,’two’,’three’)

Enter

←書式編集

>>> print(s)Enter←編集結果の確認
three, two, one←編集されて出力された結果{} の中には更に，埋め込むデータの型（表 15）と桁数（長さ）を:[桁数] 型の形式で指定することができる．
（桁数は省略可能）型

表 15: format メソッドの書式設定に指定するデータの型（一部）
解 説
型
解 説
型
解 説
型
解 説

d

10 進整数f

小数点数（暗黙で小数点以下 6 桁）x

16 進整数

o

8 進整数

s

文字列

b

2 進整数

例．埋め込むデータの型と桁数の指定（文字列型）>>> s = ’|{2:7s}|{1:7s}|{0:7s}|’.format(’one’,’two’,’three’)>>> print(s)|three |two

Enter
|one

Enter

←書式編集

←編集結果の確認|←編集されて出力された結果

80 この他にも重要なものとして，印刷装置（プリンタ）やネットワークインターフェース（NIC），マウスなどがある．

89

この例では，’7s’ の記述によってそれぞれ 7 桁の文字列になっている．
例．埋め込むデータの型と桁数の指定（整数型）

Enter>>> s = ’|{2:7d}|{1:7d}|{0:7d}|’.format(1,2,3)←編集結果の確認
1|←編集されて出力された結果

Enter
2|

>>> print(s)
|
3|

←書式編集

この例では，’7d’ の記述によってそれぞれ 7 桁の整数になっている．
例．埋め込むデータの型と桁数の指定（小数点数）>>> s = ’|{2:8.2f}|{1:8.2f}|{0:8.2f}|’.format(1.2,2.3,3.4)>>> print(s)
|
3.40|

Enter

←書式編集

←編集結果の確認
1.20|←編集されて出力された結果

Enter
2.30|

この例では，’8.2f’ の記述によってそれぞれ 2 桁の小数部を持つ合計 8 桁の小数点数になっている．
整数型と小数点数の桁数指定において，’7d’ や ’8.2f’ の代わりに ’07d’ や ’08.2f’ のように左端にゼロを付けると，左にゼロを充填した表現が結果として得られる．
例．左端のゼロの充填>>> ’{0:04d}’.format(2)Enter←ゼロを充填した整数の処理’0002’←編集されて出力された結果>>> ’{0:08.2f}’.format(2)Enter←ゼロを充填した小数点数の処理’00002.00’←編集されて出力された結果
更に，桁数指定の部分に <, >, ^ を使用することで「左寄せ」，「右寄せ」，「中央揃え」といったアラインメントが可
能となる．
（次の例）
例．「左寄せ」「右寄せ」「中央揃え」>>> ’|{0:<10d}|’.format(2)
’|2
|’

Enter

←左寄せ
←結果

>>> ’|{0:>10d}|’.format(2)
’|
2|’

Enter

←右寄せ
←結果

>>> ’|{0:^10d}|’.format(2)
’|
2
|’

Enter

←中央揃え
←結果

16 進，8 進，2 進表現の例を次に示す．
例．16 進，8 進，2 進表現>>> ’16 進){:x}, 8 進){:o}, 2 進){:b}’.format(255,255,255)’16 進)ff, 8 進)377, 2 進)11111111’←書式編集の結果■ 書式設定の方法 (2)Enter

f-string を用いる方法

Python 3.6 からフォーマット済み文字列リテラル（f-string：formatted string literal）が導入された．これにより，書式の記述の中に変数名が記述できるなど，format メソッドと同じ処理がより簡単に実現できる．例えば次のよ
うな例について考える．
例．f-string 中に変数名を直接記述する>>> v1=’one’; v2=’two’; v3=’three’>>> s = f’{v1}, {v2}, {v3}’Enter← 3 つの変数 v1, v2, v3 を用意

Enter←プレースホルダに変数名を埋め込んで文字列を生成>>> print( s )
Enter
←内容確認
one, two, three←結果
この例にあるような，接頭辞 ‘f’ を持つ文字列が f-string である．f-string は書式設定のための表現であり，format メ
ソッドで行うような書式記述のプレースホルダ内に変数名や式を直接的に記述することができる．f-string 自体は書式設定の結果の文字列となる．
以下に，f-string による書式設定の例をいくつか示す．

90

例．f-string による文字列の書式設定（先の例の続き）←文字列の桁数指定

Enter>>> print( f’|{v1:7s}|{v2:7s}|{v3:7s}|’ )
|one
|two
|three |←結果
例．f-string による整数値の書式設定← 3 つの変数 n1, n2, n3 に整数値を用意

Enter>>> n1=1; n2=2; n3=3

←整数値の桁数指定

Enter>>> print( f’|{n1:7d}|{n2:7d}|{n3:7d}|’ )
|
1|
2|
3|
←結果
例．f-string による浮動小数点数の書式設定← 3 つの変数 n1, n2, n3 に浮動小数点数を用意

Enter>>> n1=1.2; n2=2.3; n3=3.4

Enter>>> print( f’|{n1:8.2f}|{n2:8.2f}|{n3:8.2f}|’ )
|
1.20|
2.30|
3.40|
←結果

←浮動小数点数の桁数指定

例．数値の書式設定におけるゼロの充填>>> n = 2

←変数 n に数値を用意

Enter>>> f’{n:04d}’
Enter’0002’←結果>>> f’{n:08.2f}’
Enter’00002.00’←結果←ゼロを充填した整数表記←ゼロを充填した浮動小数点数の表記

例．アラインメント（先の例の続き）>>> f’|{n:<10d}|’
Enter
’|2
|’
←結果

←左寄せ

>>> f’|{n:>10d}|’
Enter
’|
2|’
←結果

←右寄せ

>>> f’|{n:^10d}|’
Enter
’|
2
|’
←結果

←中央揃え

例．16 進，8 進，2 進表現>>> n = 255

Enter>>> f’16 進){n:x}, 8 進){n:o}, 2 進){n:b}’Enter’16 進)ff, 8 進)377, 2 進)11111111’←結果
Python3.8 の版から f-string のプレースホルダに←書式編集{変数名=}

あるいは{式=}という記述が可能となった．

（次の例参照）
例．f-string の新しい書き方（Python3.8 から）>>> a=1; b=2; c=3

Enter←変数に値を設定>>> f’{a=}, {b=}, {c=}, {a+b+c=}’’a=1, b=2, c=3, a+b+c=6’
←結果

Enter

←変数名や式の内容を確認できる書き方

変数名や式の記述と，それに対応する値が表現された文字列が得られている．
■ 書式設定の方法 (3)’%’ 演算子を用いる方法

これは C や Java における書式編集に似た方法である．先に説明した format メソッドによる方法と考え方が似ており，文字列中の’%’ で始まる表記の場所（’%’ 演算子におけるプレースホルダ）に値を埋め込む方法である．
例．文字列データの埋め込み (1)>>> s = ’|%7s|%7s|%7s|’ % (’one’,’two’,’three’)

Enter

←書式編集

>>> print(s)Enter←編集結果の確認|
one|
two| three|←編集されて出力された結果
この例では，’%7s’ の部分に後方のタプルの要素の値が 7 桁の文字列として埋め込まれている．基本的には右寄せの配置となるが，次の例のように’%’ の後の数を負の値にすると左寄せの配置となる．

91

例．文字列データの埋め込み (2)>>> s = ’|%-7s|%-7s|%-7s|’ % (’one’,’two’,’three’)

Enter

←書式編集

Enter
←編集結果の確認|three |←編集されて出力された結果>>> print(s)
|one
|two

このように’%’ の後に表示桁数とデータタイプを指定する．データタイプとしては表 15（p.89）のものが概ね使用できる．ただし，’%’ 演算子における書式編集の方法は，format メソッドや f-string の場合とは厳密には異なる（2 進編
集の’b’ が使えないなど）ので注意すること．
■ 文字列のアラインメント
文字列に対する左寄せ，右寄せ，中央揃えのための ljust，rjust，center といったメソッドがある．
書き方：

文字列.ljust(長さ)，

文字列.rjust(長さ)，

文字列.center(長さ)与えられた「文字列」を指定した「長さ」でアラインメントする．
例．文字列のアラインメント>>> s = ’abc’

Enter←この文字列 s を…

>>> s.ljust(7)
’abc
’

Enter

←総長さ 7 で左寄せする←結果>>> s.rjust(7)
’
abc’

Enter

←総長さ 7 で右寄せする←結果>>> s.center(7)’ abc ’

Enter

←総長さ 7 で中央揃えする←結果

このように，アラインメントの結果として適切な個数の空白文字が充填される．

2.6.1.2

sys モジュールによる標準出力の扱い

print 関数による方法とは別に，sys モジュールを用いて標準出力に出力することもできる．
《 sys.stdout 》
オブジェクト sys.stdout は標準出力を示すオブジェクトである．このオブジェクトに対して write などのメソッドを使用して出力処理ができる．
標準出力への出力：

sys.stdout.write( 文字列オブジェクト )標準出力に対して文字列を出力する．出力処理が正常に終了すると，出力した文字数 * が返される．

sys の使用に先立って，sys モジュールを読み込んでおく必要がある．
* バイナリ形式で出力する場合は，出力バイト数が戻り値となる．標準出力にバイナリデータを出力する方法については
後の「2.6.6 標準入出力でバイナリデータを扱う方法」（p.105）で解説する．

print 関数で出力すると行末で改行されるが，この方法による出力では自動的に改行処理はされない．
（次の例を参照）
例．sys.stdout に対する出力>>> import sys

Enter← sys モジュールの読込み>>> n = sys.stdout.write(’abcd’)
abcd>>>

Enter←出力処理の実行←出力結果

出力後は改行されずにプロンプト’>>>’ が直後に表示されている．また write メソッドの実行後，出力したデータの長さ（文字数）が返される．
例．戻り値の確認（先の例の続き）

>>> n
Enter
←出力バイト数の確認
4← 4 文字出力されたことが確認できる
表示の最後で改行するには，次のように文字列の最後にエスケープシーケンス ’￥n’ を付ける．

92

例．write による出力後の改行方法（先の例の続き）>>> n = sys.stdout.write(’abcd￥n’)
abcd←表示の最後に改行されている

Enter←出力の最後で改行

>>> n
Enter
←戻り値の確認5← 5 文字出力されたことが確認できる（改行コードも含む）>>> n = sys.stdout.write(’ab￥tcd￥n’)
Enter
ab
cd
←タブの表示と改行処理がされている←タブも出力可能

>>> n
Enter
←戻り値の確認6← 6 文字出力されたことが確認できる（タブ，改行コードも含む）■ sys.stdout のエンコーディング設定

io モジュールを使用することで，sys.stdout に write メソッドで文字列を出力する際のエンコーディングを指定することができる．
例．sys.stdout のエンコーディングを utf-8 にする

import sys, io# モジュールの読み込み
sys.stdout = io.TextIOWrapper( sys.stdout.buffer, encoding=’utf-8’ )このように，io モジュールの TextIOWrapper オブジェクトを sys.stdout に設定する．この際，キーワード引数‘encoding=’ にエンコーディングを指定する．
標準入力

2.6.2

通常の場合，標準入力はキーボードを示しており，ユーザからのキーボード入力を取得することができる．

2.6.2.1

input 関数による入力の取得

81
input 関数を呼び出すと，標準入力から 1 行分の入力を読み取って，それを文字列として返す．

《 input 関数による入力の取得 》
書き方：

input(プロンプト文字列)

input 関数を呼び出すと，「プロンプト文字列」を標準出力に表示して入力を待つ．1 行分の入力と改行入力
Enter により，その 1 行の内容が文字列として返される．

input 関数を用いたサンプルプログラム test05-1.py を次に示す．
プログラム：test05-1.py
1
2
3
4# coding : utf -8
x = input ( ’ 入 力 x > ’)y = input ( ’ 入 力 y > ’)print ( x + y )このプログラムを実行すると，
入力 x>と表示され，プログラムは入力を待つ．続けて実行した様子を次に示す．
実行例．
入力 x> 2

Enter←「2」と入力

入力 y> 3

Enter←「3」と入力

23←出力

x+y の計算結果が ’23’ として表示されている．これは入力された値が文字列型であることによる．
次にサンプルプログラム test05-2.py について考える．

81 getpass モジュールを使用すると，パスワード用の秘匿入力ができる．その場合は，「fromモジュールを読み込んで，getpass( プロンプト文字列 ) として入力を取得する．

93

getpass import getpass」として

プログラム：test05-2.py
12
3
4# coding : utf -8
x = int ( input ( ’ 入 力 x > ’) )y = int ( input ( ’ 入 力 y > ’) )print ( x + y )これは，input 関数の戻り値を int 関数によって整数型に変換している例である．このプログラムを実行した例を次に示す．
実行例．
入力 x> 2

Enter←「2」と入力

入力 y> 3

Enter←「3」と入力←出力

5

x+y の計算結果が 5 として表示されている．
sys モジュールによる標準入力の扱い

2.6.2.2

input 関数による方法とは別に，sys モジュールを用いて標準入力から入力することもできる．
《 sys.stdin 》
オブジェクト sys.stdin は標準入力を示すオブジェクトである．このオブジェクトに対して read や readline などのメソッドを使用して入力を取得することができる．
標準入力からの入力：

sys.stdin.readline()

標準入力から 1 行分の入力を取得する．入力処理が正常に終了すると，取得したデータを文字列型のデータとして返す．

sys の使用に先立って，sys モジュールを読み込んでおく必要がある．
input 関数で入力する場合と異なり，この方法による入力では行末の改行コードも取得したデータに含まれる．
（次の
例を参照）
例．sys.stdin からの入力>>> import sys

Enter← sys モジュールの読込み>>> s = sys.stdin.readline()

Enter

abcde

Enter

← 1 行分のデータを入力

>>> s

Enter

←戻り値の確認’abcde￥n’←入力を開始←行末の改行コードも含まれている■ sys.stdin のエンコーディング設定

io モジュールを使用することで，sys.stdin から文字列を入力する際のエンコーディングを指定することができる．
例．sys.stdin のエンコーディングを utf-8 にする

import sys, io# モジュールの読み込み
sys.stdin = io.TextIOWrapper( sys.stdin.buffer, encoding=’utf-8’ )このように，io モジュールの TextIOWrapper オブジェクトを sys.stdin に設定する．この際，キーワード引数 ‘encoding=’にエンコーディングを指定する．
注）標準入力からバイナリデータを読み込む方法については後の「2.6.6 標準入出力でバイナリデータを扱う方法」（p.105）で解説する．

2.6.3

ファイルからの入力

ファイルからデータを読み込むにはファイルオブジェクトを使用する．ファイルオブジェクトはディスク上のファ
イルを示すものである．すなわち，ファイルからの入力に先立って open 関数を使用してファイルを開き，そのファイルに対応するファイルオブジェクトを生成しておく．以後はそのファイルオブジェクトからファイルのデータ（中身）94を取得することになる．
《 ファイルのオープン 》

open 関数を使用してファイルを開く
書き方：

open( パス, モード )「パス」は開く対象のファイルのパスを表す文字列型オブジェクトである．
「モード」はファイルの開き方に関する設定であり，入力用か出力用か，あるいはテキスト形式かバイナリ形式かの指定をするための文字列型オブジェクトである．ファイルのオープンが成功すると，そのファイルのファイルオブジェクトを返す．
モード：
r: 読取り用（入力用）にファイルを開く

w: 書き込み用（出力）にファイルを開く

a: 追記用（出力用）にファイルを開く

x: 出力用にファイルを新規作成する，（既存の場合はエラー）

r+: 入出力両用にファイルを開く，
ファイルは通常はテキスト形式として開かれるが，上記モードに b を書き加えるとバイナリ形式の扱いとなる．これに関しては後の「2.6.3.3 テキストファイルとバイナリファイルについて」（p.98）で更に詳しく解説する．
バイナリデータは Python 処理系ではバイト列として扱われる．バイト列の扱いについては「2.6.3.4 バイト列の扱い」（p.98）で解説する．

open 関数が返すファイルオブジェクトの型（クラス）は入力用，出力用で異なる．更にテキストかバイナリかによっても異なる．
表 16: open 関数が返すファイルオブジェクトのクラス（一部）2.6.3.1

テキスト

バイナリ

入力用

TextIOWrapper

BuﬀeredReader

出力用

（同上）

BuﬀeredWriter

ファイル，ディレクトリのパスについて「/」や
バス（path）はファイルシステムにおけるファイルやディレクトリ（フォルダ）の場所を示すものであり，「￥」といった記号82 でディレクトリの階層関係を記したものである．
例．Windows でのパスの表記
C:￥Users￥katsu￥test1.txt→「C ドライブのフォルダ Users の中のフォルダ katsu の中にあるファイル test1.txt」を意味する．
例．UNIX 系 OS（macOS，Linux など）でのパスの表記/usr/home/katsu/test1.txt→「ルートディレクトリの下にあるディレクトリ usr の下のディレクトリ home の下のディレクトリ katsu の下にあるファイル test1.txt」■ ルートディレクトリ，カレントディレクトリ

UNIX 系 OS でのパスの表記において左端に「/」があれば，それはファイルシステムのルートディレクトリ（最上位のディレクトリ）を意味する．また Windows でのパスの表記において左端に「C:￥」があれば，それは「ドライブC」のルートフォルダ（最上位のフォルダ）を意味する．左端にルートディレクトリ（ルートフォルダ）の記述があるパスを絶対パスと言う．
多くの場合，コンピュータのアプリケーションプログラムや言語処理システムには特定のディレクトリがカレント
ディレクトリとして設定されており，それが暗黙のディレクトリとなる．すなわち，ルートディレクトリの記述が無いパス（相対パスと言う）の表記では，カレントディレクトリがパスの起点となる．例えば，カレントディレクトリ
が ’/usr/local’ として設定されている場合，相対パス ’etc/dat1.txt’ が示すものは’/usr/local/etc/dat1.txt’
である．
82 使用するフォントによっては「￥」はバックスラッシュ「\」として表示される．

95

■ パスの表記における ’.’ と ’..’
パスの表記における ’.’ と ’..’ はそれぞれ「現在のディレクトリ」「1 つ上のディレクトリ」を意味する．例えば’../file1.txt’ というパスの記述は，「カレントディレクトリの 1 つ上のディレクトリにあるファイル ’file1.txt’」を意味する．
パスの記述は特殊な文字を含む場合があるので，パスを文字列として記述する際，raw 文字列とするのが安全である．例えば「C:￥Users￥katsu￥test1.txt」というパスは「r’C:￥Users￥katsu￥test1.txt’」と記述すると良い．

2.6.3.2

扱うファイルのエンコーディング，改行コードの指定

テキスト形式でファイルを開く場合は，対象のファイルのエンコーディングに注意する必要がある．Python の処理系がエンコーディングとして shift jis の扱いを前提としている場合，utf-8 など他のエンコーディングのファイルを読み込むとエラーが発生することがある．従って，ファイルをテキスト形式で開く場合は，次の例のように encoding を指定して，読み込むファイルのエンコーディングを指定しておくと安全である．
例．utf-8 のテキストファイルを開く場合

open(ファイルのパス,’r’,encoding=’utf-8’)
Python で扱えるエンコーディングは「2.1.1 プログラム中に記述するコメント」（p.6）で説明した表 1 のものを指定する．
テキストファイルの改行コードは OS 毎に異なることがあり，Windows 環境では CR + LF （0x0D，0x0A）が，Unix 系（Linux，macOS など）では LF が標準的である．この違いはテキストファイルの出力時に問題を起こすことがあるので注意が必要である．後に説明するファイル出力においては，open 関数にキーワード引数 ‘newline=改行
コード’ を与えると安全である．この場合の「改行コード」にはNone，’’，’￥n’，’￥r’，’￥r￥n’
といったものが指定できる．この際，None（デフォルト値）を指定すると，当該 OS の標準的な改行コード83 となり，空文字列 ’’ を指定すると ￥n となる．
ファイルからのデータ入力の例：
テキストファイルから 1 行ずつデータを取り出すプログラム test06-1.py を例示する．
プログラム：test06-1.py
1
2
3
4
5
6
7
8
9
10
11

# coding : utf -8
f = open ( ’ test06 -1. txt ’ , ’r ’)
while True :s = f . readline ()if s :
print ( s )else :break
f . close ()基本的な考え方：このプログラムはテキストファイル test06-1.txt を開き，それをファイルオブジェクト f としている．このファイル
オブジェクトに対して readline 84 メソッドを使用してデータを 1 行ずつ取り出して変数 s に与え，それを print 関数
で表示している．ファイルの内容を全て読み終わると，次回 readline 実行時にデータが得られない85 ので，break により while を終了する．

83 os モジュールの os.linesep に設定されている．
84 readline メソッドは，開かれているファイルのモードによって返す値の型が異なり，テキストモードで開いているときは文字列型で，バイナリモードで開いているときはバイト列（「2.6.3.4 バイト列の扱い」（p.98）参照）で返す．
85 変数 s に空文字列 ’’ がセットされる．

96

テキストファイル：test06-1.txt
1
2
3

1行 目
2行 目
3行 目

プログラム test06-1.py を実行すると次のように表示86 される．
1 行目
2 行目
3 行目

この実行例では余分に改行された形で表示されている．これは，readline が改行コード87 も含めて取得するため．変
数 s にセットされる文字列オブジェクトの末尾にも改行コードが含まれるからである．
文字列オブジェクトの行末の改行コードを削除するには rstrip メソッド88 を使用する．
《 改行コードの削除 》
書き方：

対象文字列.rstrip()「対象文字列」の末尾にある改行コードや余分な空白文字を削除する．

rstrip メソッドを用いた形に修正したプログラム test06-2.py を示す．
プログラム：test06-2.py
1
2
3
4
5
6
7
8
9
10
11

# coding : utf -8
f = open ( ’ test06 -1. txt ’ , ’r ’)
while True :s = f . readline (). rstrip ()if s :
print ( s )else :break
f . close ()このプログラムを実行すると次のように表示される．
1 行目
2 行目
3 行目

ファイルからの読込みが終われば，そのファイルを閉じる．
《 ファイルのクローズ 》
書き方： ファイルオブジェクト.close()
開かれている「ファイルオブジェクト」を閉じる．

テキスト読込みに伴うエンコーディングの不具合について：
テキスト形式の入力データのエンコーディングによっては，入力処理において問題を起こす場合がある．
（次の実行例）
1 陦檎岼
2 陦檎岼
3 陦檎岼

86 この時に不可解な文字列が表示されることがあるが，対処法については後で説明する．
87 バイトデータとしての実際のコードは OS 毎に異なる．例．Windows: CR

LF ，macOS,Linux: LF
使用している処理系の改行コードは os モジュールの os.linesep に設定されている．

88 rstrip メソッドは，対象文字列の改行文字だけでなく，右端の余分な空白文字も削除する．これと類似のものに lstrip メソッドも存在し，

これは文字列の左端の余分な空白文字を削除する．

97

ファイルのデータをテキスト形式として扱う際，エンコーディングが正しく識別されない場合にはこのような現象89が起こることがある．解決策としては，先に述べたように open 関数にキーワード引数 ‘encoding=’ を与えるのが基本的であるが，別の方法として，テキストファイルの読み込みにおいてもバイナリ形式でファイルを扱うということが挙げられる．バイナリ形式としてファイルからデータを入力すると，それらはデータ型とは無関係なバイト列とみなされる．
（p.98 「2.6.3.4 バイト列の扱い」参照）
バイト列として得られたデータを，プログラム側で明に各種のデータ型の値に変換することでより安全な処理が実現できる．すなわち，バイト列として得られたデータを，正しいエンコーディングの扱いを指定した上で文字列型のオブジェクトに変換し，更にそれらを目的のデータ型のオブジェクトに変換するという方法である．
次のプログラム test06-3.py について考える．
プログラム：test06-3.py
1
2
3
4
5
6
7
8
9
10
11

# coding : utf -8
f = open ( ’ test06 -1. txt ’ , ’ rb ’)while True :s = f . readline (). decode ( ’ utf -8 ’). rstrip ()if s :
print ( s )else :break
f . close ()このプログラムの 5 行目の部分に見られる decode メソッドは，バイト列のデータに対するメソッドであり，引数に指定したエンコーディングで文字列型に変換する．
このような形でファイルからデータを入力すると，多バイト系の文字も正しく処理される．

2.6.3.3

テキストファイルとバイナリファイルについて

ファイルシステム上のファイルは 8 ビット表現の 2 進数を 1 つの単位（1 バイト）とするバイト列として構成されたものであるが，コンピュータのデータファイルはテキストファイルとバイナリファイルの 2 種類に区別して扱うことが多い．テキストファイルはアスキー文字を始めとする可読な文字90 と，表示の制御のための制御文字から成るもの91 であり，それらに該当しないバイト値を含むファイルはバイナリファイルとして扱われる．

Python 言語処理系では，可読な文字と表示のための制御文字から成るデータを文字列型（str 型）の値として扱う．
またそのようなデータをテキストデータ（あるいは「テキスト形式データ」）と呼ぶことがある．
文字列型のデータとしてファイルの入出力を行う場合は open 関数の第 2 引数に与えるモードとして ’r’（入力時）
や ’w’（出力時）を指定する．また，モードに ’rb’（入力時）や ’wb’（出力時）を指定すると，対象のファイルをバ
イナリファイルとして扱う．バイナリファイルに対する入出力は，次に説明するバイト列（bytes 型）の値として行う．
テキストファイルを敢えてバイナリファイルとして扱う（open 関数の第 2 引数に ’rb’ や ’wb’ を与える）ことも可能である92 が，その場合は入出力の値を文字列（str 型）としてではなく，バイト列（bytes 型）の値として扱う．

2.6.3.4

バイト列の扱い

バイト列は文字列型や数値型とは異なるオブジェクトであり，ファイル入出力や通信に用いる際の基本的なオブジェクトである．これは，テキスト形式ではないいわゆるバイナリデータを扱う場合に用いられるデータ型である．バイ
ト列のデータ型は bytes である．
コンピュータで扱うデータは，記憶資源上の実体としては（メモリに格納される実体としては）数値，文字列に限らず全てバイト列であり，処理系が扱う際には，それらバイト列を数値や文字列といった目的の型に解釈して処理を行う．例えば文字列型オブジェクトを用いると，多バイト系文字列も次の例のように正しく表示することができる．

89 いわゆる「文字化け」

90 日本語などの多バイト文字も含む．
91 1 バイトで表現できる可読文字と制御文字に関しては巻末付録「J.2 アスキーコード表」（p.437）を参照のこと．
92 コンピュータで扱うあらゆるデータは元来バイナリデータである．

98

例．多バイト文字列（日本語）の扱い>>> a = ’ 日本語’
>>> a
Enter
’ 日本語’←日本語文字列の作成

Enter←内容の確認←正しく表示されている

これは Python 処理系が多バイト系文字列データの文字コード体系（エンコーディング）を正しく解釈して処理しているからであるが，この文字列はバイト列としては（記憶資源上の内部表現としては），（16 進数表現）

e6 97 a5 e6 9c ac e8 aa 9eというバイト値93 の列であり，ファイルとして保存する場合もディスクにはこのようなバイト値の並びとして記録されている．すなわち，Python を始めとする処理系は日本語など多バイト文字をディスプレイに表示する際，正しい記号として表示するように処理系内部で処理している．
【バイト列に関すること】

Python では，通信やファイル入出力において各種のオブジェクトの内容を実際のデバイスとやりとりする際に，それらをバイト列として扱っている．デバイスに出力する際にはデータをバイト列に変換して出力し，デバイスから入力する際にはバイト列として入力した後に適切なデータ型に変換する．先の例で扱った日本語の文字列型オブジェク
トも明にバイト列に変換することができる．
（次の例参照）
例．文字列をバイト列に変換する（先の例の続き）>>> b = a.encode(’utf-8’)Enter←バイト列に変換

>>> b
Enter
←内容の確認b’￥xe6￥x97￥xa5￥xe6￥x9c￥xac￥xe8￥xaa￥x9e’←バイト列データ
このように encode メソッドを使用することで，文字列型オブジェクトをバイト列に変換することができる．

encode メソッドの引数には，元の文字列のエンコーディングを与える．
バイト列として表現されている多バイト文字列のデータを文字列型に変換するには，そのバイト列に対して

decode メソッドを用いる．
例．バイト列を文字列に変換する>>> b = b’￥xe6￥x96￥x87￥xe5￥xad￥x97’>>> b.decode(’utf-8’)
’ 文字’
←変換結果

Enter

Enter

←バイト列

←それを utf-8 の文字列に変換《 バイト列⇔多バイト系文字列の変換 》
・ バイト列⇒文字列の変換： 対象バイト列.decode(エンコーディング)
・ 文字列⇒バイト列の変換： 対象文字列.encode(エンコーディング)

戻り値は文字列型オブジェクト
戻り値はバイト列応用：

encode，decode メソッドを組み合わせて「文字列→バイト列→文字列」と変換することで，エンコーディングの変換処理が実現できる．
参考：エンコーディングを指定してバイト列を文字列に変換するには str を使う方法もある．
書き方：

str( バイト列, エンコーディング )例．バイト列を文字列に変換する：その 2（先の例の続き）>>> str( b, ’utf-8’ )Enter← utf-8 の文字列に変換’ 文字’←変換結果（decode メソッドと同じ結果）■ バイト列の作成方法

bytes コンストラクタでバイト列を作成する方法について説明する．
書き方：

bytes( 整数値のリスト )93 0〜255 の整数値（16 進数では 00〜ff）

99

「整数値のリスト」94 の要素は 0〜255 の整数である．
例．整数値のリストをバイト列に変換する>>> b = bytes( [230,150,135,229,173,151] )
>>> b
Enter
←内容確認
b’￥xe6￥x96￥x87￥xe5￥xad￥x97’←整数のリストをバイト列に変換←バイト列←文字列に変換Enter>>> b.decode(’utf-8’)
’ 文字’
←変換結果

Enter

次のような書き方で文字列をバイト列に変換することもできる．
書き方：

bytes( 文字列, エンコーディング )「文字列」を「エンコーディング」に従ってバイト列に変換する．これは encode メソッドと同じ結果となる．
例．文字列をバイト列に変換する←文字列をバイト列に変換>>> bytes( ’ 日本語’, ’utf-8’ )Enter
b’￥xe6￥x97￥xa5￥xe6￥x9c￥xac￥xe8￥xaa￥x9e’←変換結果注意）bytes 型のデータは作成後に変更することができない．
（イミュータブルである）ミュータブル（変更可能）なバイト列に関しては「4.13 編集可能なバイト列： bytearray」（p.285）で解説する．

2.6.3.5

バイト列のコード体系を調べる方法

ファイルや通信デバイスから入力されたバイトデータを多バイト系文字列として解釈する場合に，それを表現する
ためのエンコーディングが分からないことがある．そのような場合は，chardet 95 ライブラリを用いてかなり正確にエンコーディングを識別することができる．
例．chardet ライブラリによるエンコーディングの識別>>> import chardet>>> s = ’ 私は Python’Enter←ライブラリの読込み←文字列の設定Enter>>> b = s.encode(’utf-8’)Enter←バイト列への変換>>> d = chardet.detect(b)Enter←エンコーディングの識別処理>>> print( d[’encoding’] )Enter ←結果を調べる
utf-8← utf-8 であることがわかる．
このように detect 関数の引数に調べたいバイト列を与えると，識別結果が辞書オブジェクトとして返される．結果の辞書オブジェクトのキー ’encoding’ に対する値として，エンコーディングの名称が得られる．

2.6.3.6

指定したバイト数だけ読み込む方法

バイナリファイルとして開いているファイル f から指定したバイト数だけ読み込むには read メソッドの引数にバイト数を整数で与える．
例．バイナリファイル f から 256 バイト読み込む

b = f.read(256)
この例では，f から読み取った 256 バイト分のデータが b に格納される．

2.6.3.7

ファイルの内容を一度で読み込む方法

入力用のファイルオブジェクトに対して read メソッドを引数なしで実行すると，ファイルの内容を全て読み込むことができる．
例．ファイルの内容を全て読み込む

f = open(ファイル名,’r’,encoding=’utf-8’)
text = f.read()f.close()94 リストに限らずイテラブルであれば良い．
95 詳しくはインターネットサイト https://chardet.readthedocs.io/ を参照のこと．PSF 版 Python におけるインストール方法に関しては「A.4 PIP によるライブラリ管理」を参照のこと．Anaconda の場合は，Anaconda Navigator でパッケージ管理を行う．

100

ただし，ファイルのデータサイズが大きい場合は注意が必要であり，行単位の読み込みをする等の工夫が必要になることがある．既存のファイルのサイズを予め調べる方法については「2.6.7.5 ファイルのサイズの取得」（p.107）を参
照のこと．
応用：
テキストファイルの内容を read メソッドで一度に読み込んだ後，先に解説した splitlines 96 を応用すると，テキストの各行を要素とするリストが得られる．
ファイルを開くための別の方法を「2.6.8 パス（ファイル，ディレクトリ）の扱い：その２ - pathlib モジュール」（p.109）で説明する．

2.6.3.8

ファイルをイテラブルとして読み込む方法

open 関数で開いたファイルはイテラブルなオブジェクト97 として扱うことができる．この場合にテキストファイルから取り出す 1 つの要素は，ファイルの行である．例えば，次に示すテキストファイル dat1.txt をイテラブルとして読み込むことを考える．
テキストファイル：dat1.txt
1
2
3

1行 目
2行 目
3行 目

これを読み込む例を次に示す．
例．ファイルをイテラブルと見て読み込む>>> f = open(’dat1.txt’,’r’,encoding=’utf-8’)

Enter←ファイルのオープン>>> for s in f: Enter←ファイル f をイテラブルとして繰り返しを始める...
print( s.rstrip() )Enter←取り出した要素を表示
...
Enter
←繰り返しの記述の終了
1 行目
2 行目
3 行目

←取り出した要素を表示←取り出した要素を表示←取り出した要素を表示>>> f.close()Enter←ファイルのクローズファイル f に対して readline メソッドで行を取り出す処理に似ているが，これはあくまで「イテラブル」としての扱いである．
課題． ファイルオブジェクトをイテラブルとして扱うことができることから，ファイルオブジェクト f に対してlist(f) とすると何が得られるかについて考察し，その応用可能性について考えよ．

2.6.3.9

readlines メソッドによるテキストファイルの読み込み

先に説明した readline メソッドは，テキスト形式のファイルオブジェクトから内容を 1 行ずつ読み込む．これに対して readlines メソッドはテキストファイルの内容を全て読み込み，その各行を要素とするリストを返す．
例．readlines によるテキストファイルの読み込み（先の例の続き）>>> f = open(’dat1.txt’,’r’,encoding=’utf-8’)>>> txtL = f.readlines()

Enter

Enter

←ファイルのオープン←ファイルの内容をすべて読み込んでリストにする>>> print(txtL)Enter←得られたリストを表示[’1 行目￥n’, ’2 行目￥n’, ’3 行目￥n’]←リストの内容>>> f.close()Enter←ファイルのクローズ得られたリストの各要素には改行コード「￥n」も含まれる．

96 p.33「splitlines メソッドによる行の分離」を参照のこと．
97 「2.5.1.1 イテラブルなオブジェクト」（p.75），「2.5.1.8 イテレータ」（p.78）を参照のこと．

101

データを読み込む際のファイル中の位置について

2.6.3.10

入力用のファイルオブジェクトに対して tell メソッドを実行すると，次にデータを読み込む位置（ファイル中でのバイト位置）が得られる．
例．ファイル中の読み取り位置を調べる（先の例の続き）>>> f = open(’dat1.txt’,’r’,encoding=’utf-8’)>>> f.tell()
0

Enter

Enter

←ファイルのオープン←ファイルをオープンした直後の読み取り位置を調べる← 0 バイト目から読み取る状態← 1 行目の読み込み>>> f.readline().rstrip()Enter’1 行目’←読み込んだ内容>>> f.tell()
9

Enter

←次の読み取り位置を調べる← 9 バイト目から読み取る状態>>> f.readline().rstrip()Enter← 2 行目の読み込み’2 行目’←読み込んだ内容>>> f.tell()
18

Enter

←次の読み取り位置を調べる← 18 バイト目から読み取る状態>>> f.readline().rstrip()Enter← 3 行目の読み込み’3 行目’←読み込んだ内容>>> f.tell()
27

Enter

>>> f.close()Enter←最終的なファイルの位置を調べる← 27 バイト目←ファイルのクローズ

tell メソッドは出力用のファイルオブジェクトに対して使用することもできる．その場合は「ファイル中での出力位置」が得られる．
ファイルへの出力2.6.4開かれたファイルに対してデータを出力することができる．ファイルのオープンとクローズについては先の「2.6.3
ファイルからの入力」のところで説明したとおりであり，ここではファイルオブジェクトに対する出力について解説する．
ファイルオブジェクトに対する出力には write メソッドを使用する．
《 write メソッド 》
書き方： ファイルオブジェクト.write(データ)「ファイルオブジェクト」に対して「データ」を出力する．
「データ」に与えるオブジェクトの型は，ファイル
オブジェクトのモードによる．すなわち，ファイルオブジェクトがテキストモードのときは文字列型で，バイナ
リモードの場合はバイト列で与える．
このメソッドが正常に実行されると，出力したデータの長さ（テキストモードの場合は文字数，バイナリモー
ドの場合はバイト数）が返される．
テキストデータ出力時のエンコーディング，改行コードの指定に関しては，先の「2.6.3.2 扱うファイルのエンコー
ディング，改行コードの指定」（p.96）を参照のこと．

2.6.4.1

print 関数によるファイルへの出力

print 関数もファイルへの出力の機能を持つ．
《 print 関数によるファイルへの出力 》
書き方：

print( …, ﬁle=ファイルオブジェクト )出力内容に続いてキーワード引数 ‘file=’ を与え，これに出力先のファイルオブジェクトを指定する．

102

2.6.4.2

writelines メソッドによる出力

ファイルオブジェクトに対して writelines メソッドを用いてデータを出力することができる．
《 writelines メソッドによるファイルへの出力 》
書き方：

ファイルオブジェクト.writelines( リスト )「リスト」の要素を順番に「ファイルオブジェクト」が示すファイルに出力する．

write，print，writelines をそれぞれ用いてファイルに出力するサンプルプログラム writeTest03.py を次に示す．
プログラム：writeTest03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8
f = open ( ’ writeTest03 . txt ’ , ’w ’ , encoding = ’ utf -8 ’)print ( ’ w r i t e メ ソ ッ ド を 実 行 す る 直 前 の フ ァ イ ル 中 で の バ イ ト 位 置 : ’ , f . tell () )f . write ( ’ w r i t e メ ソ ッ ド に よ る 出 力 \n ’)print ( ’ p r i n t 関 数 を 実 行 す る 直 前 の フ ァ イ ル 中 で の バ イ ト 位 置 : ’ , f . tell () )print ( ’ p r i n t 関 数 に よ る 出 力 ’ , file = f )print ( ’ w r i t e l i n e s メ ソ ッ ド を 実 行 す る 直 前 の フ ァ イ ル 中 で の バ イ ト 位 置 : ’ , f . tell () )L = [ ’ w r i t e l i n e s に よ る 連 続 出 力 ： 1 行 目 \n ’ , ’2 行 目 \ n ’ , ’3 行 目 \ n ’]
f . writelines ( L )print ( ’ フ ァ イ ル を 閉 じ る 直 前 の フ ァ イ ル 中 で の バ イ ト 位 置 : ’ , f . tell () )f . close ()これを実行すると次のようなファイル writeTest03.txt ができる．
出力されたファイル：writeTest03.txt
1
2
3
4
5

writeメソッドによる出力
print関数による出力
writelinesによる連続出力：1行目
2行 目
3行 目

また，各出力処理の直前での出力位置（ファイル中でのバイト位置）が標準出力に出力される．
（次の例）
出力例

write メソッドを実行する直前のファイル中でのバイト位置: 0
print 関数を実行する直前のファイル中でのバイト位置: 34
writelines メソッドを実行する直前のファイル中でのバイト位置:
ファイルを閉じる直前のファイル中でのバイト位置: 123

2.6.4.362

出力バッファの書き出し

write メソッドなどによるファイルへのデータの出力においては，出力内容は一旦出力バッファに蓄えられ，それが一杯になった時点で実際にストレージに書き込まる．そして出力バッファは空になり，次の出力内容を受け付けて蓄える．この他にも，ファイルが閉じられる際や，プログラム自体が終了（Python 処理系が終了）する時点でも出力バッファの内容がストレージに書き込まれる．出力バッファの内容を意図して（強制的に）ストレージに書き込むには，出力ファイルのファイルオブジェクトに対して ﬂush メソッドを実行する．
書き方：

2.6.5

ファイルオブジェクト.ﬂush()

標準エラー出力

標準出力によく似た働きを持つ標準エラー出力というものがある．sys モジュールの stderr に対して write メソッドを実行すると，標準出力の場合と同様にディスプレイに出力結果が表示される．次のプログラム test06-4.py の動作について考える．

103プログラム：test06-4.py
1
2
3
4
5
6
7
8
9

# coding : utf -8# モジュールの読込み
import sys
for i in range (50):sys . stdout . write ( str ( i )+ ’ , ’)if i > 0 and i % 10 == 0:
sys . stdout . write ( ’\n ’)sys . stderr . write ( str ( i )+ ’ ま で 出 力 し ま し た ． \ n ’)

これは 0 から 49 までの整数を標準出力に出力するプログラムであるが，値が 10,20,30,40 のときに標準エラー出力に対してメッセージ「〜まで出力しました」を表示するものである．
（次の実行例参照）
実行例 1. Windows 環境での実行
C:￥Users￥student>py test06-4.py
0,1,2,3,4,5,6,7,8,9,10,
10 まで出力しました．
11,12,13,14,15,16,17,18,19,20,
20 まで出力しました．
21,22,23,24,25,26,27,28,29,30,
30 まで出力しました．
31,32,33,34,35,36,37,38,39,40,
40 まで出力しました．
41,42,43,44,45,46,47,48,49,

この例では，標準出力と標準エラー出力が同じ働きをしているように見える．ただし，これら 2 種類の出力はそれ
ぞれ別のものであり，出力先のリダイレクト98 により，別の出力先に送り出すことができる．
（次の実行例参照）
実行例 2. Windows 環境での実行

C:￥Users￥student>py test06-4.py 1> test06std.txt 2> test06err.txt
この処理の結果，標準出力への出力がファイル test06std.txt に，標準エラー出力への出力がファイル test06err.txt に書き込まれる．
（次の例参照）
ファイル test06std.txt
1
2
3
4
5

0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,
11 ,12 ,13 ,14 ,15 ,16 ,17 ,18 ,19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30 ,
31 ,32 ,33 ,34 ,35 ,36 ,37 ,38 ,39 ,40 ,
41 ,42 ,43 ,44 ,45 ,46 ,47 ,48 ,49 ,ファイル test06err.txt
12
3
4

10 ま で 出 力 し ま し た ．
20 ま で 出 力 し ま し た ．
30 ま で 出 力 し ま し た ．
40 ま で 出 力 し ま し た ．

■ 標準エラー出力の主な用途
ターミナル系のプログラム（標準入出力を基本的な UI とするプログラム）では，エラーメッセージや各種ログの出力（プログラム実行中の報告出力）などを，主たる出力とは区別する習慣がある．そのような場合に標準エラー出
力が出力先として用いられる．
ターミナル系のプログラムでは図 6 に示すように，標準的に出力が 2 系統，入力が 1 系統存在している．
■ sys.stderr のエンコーディング設定

io モジュールを使用することで，sys.stderr に write メソッドで文字列を出力する際のエンコーディングを指定することができる．

98 標準出力や標準入力は通常ではディスプレイやキーボードに接続されているが，これらをファイルに接続することができる．

104

図 6: ターミナル系プログラムの入出力の概観
例．sys.stderr のエンコーディングを utf-8 にする

import sys, io
sys.stderr = io.TextIOWrapper( sys.stderr.buffer, encoding=’utf-8’ )このように，io モジュールの TextIOWrapper オブジェクトを sys.stderr に設定する．この際，キーワード引数 ‘encoding=’にエンコーディングを指定する．
注）標準エラー出力にバイナリデータを出力する方法については次の「2.6.6 標準入出力でバイナリデータを扱う方法」（p.105）で解説する．

2.6.6

標準入出力でバイナリデータを扱う方法

sys モジュールを用いて標準入出力，標準エラー出力でバイナリデータを扱う方法を表 17 に示す．

記述

2.6.7

表 17: 標準入出力，標準エラー出力でのバイナリデータの扱い
解説

sys.stdin.buffer.read( n )標準入力からバイナリデータを n バイト読み込んで返す．

sys.stdin.buffer.read( )標準入力からバイナリデータをファイル終端（EOF）まで
読み込んで返す．

sys.stdout.buffer.write( b )bytes オブジェクト b を標準出力へ出力し，出力したバイト数を返す．

sys.stderr.buffer.write( b )bytes オブジェクト b を標準エラー出力へ出力し，出力したバイト数を返す．

パス（ファイル，ディレクトリ）の扱い：その１ - os モジュール

ここではパス（ファイル，ディレクトリ）に対する各種の操作について説明する．パスに対する操作をするには os
モジュールを使用するので，次のようにして読み込んでおく．

import os
2.6.7.1

カレントディレクトリに関する操作

相対パスを指定してファイルの入出力を行う場合はカレントディレクトリを基準とする．Python のプログラム実行
時には，処理系を起動した際のディレクトリがカレントディレクトリとなるが，プログラムの実行時にこれを変更することができる．
【カレントディレクトリの取得】

os モジュールの getcwd メソッドを使用する．
例．カレントディレクトリを調べる>>> import os

Enter←モジュールの読込み>>> os.getcwd()
Enter←カレントディレクトリを調べる’C:￥￥Users￥￥katsu←カレントディレクトリ
結果は文字列の形式で得られる．これは Windows における実行例であり，「￥」はエスケープされて「￥￥」となる．
【カレントディレクトリの変更】

os モジュールの chdir メソッドを使用する．

105

例．カレントディレクトリの変更（先の続き）

Enter>>> os.chdir(’..’)←カレントディレクトリを変更（1 つ上へ）>>> os.getcwd()
Enter←カレントディレクトリを調べる’C:￥￥Users’←カレントディレクトリが変更されている
2.6.7.2

ホームディレクトリの取得

カレントユーザ99 のホームディレクトリは OS の環境変数が保持している．環境変数は os モジュールの辞書 environ
から参照できる．これに関しては後の「4.23.4 環境変数の参照」（p.311）で解説するが，ここではホームディレクト
リを取得する方法について例示する．
例．ホームディレクトリの取得（macOS の場合）100>>> import os

Enter←モジュールの読込み>>> print( os.environ[’HOME’] )← OS の環境変数 HOME を出力/Users/katsu←ホームディレクトリ
例．ホームディレクトリの取得（Windows の場合）>>> import os

Enter←モジュールの読込み←ホームディレクトリの取得>>> home = os.environ[’HOMEDRIVE’] + os.environ[’HOMEPATH’] Enter>>> print( home )C:￥Users￥katsu
2.6.7.3

Enter←ホームディレクトリの出力←ホームディレクトリ

ディレクトリ内容の一覧 (1)os モジュールの listdir 関数を使用する．
例．ディレクトリ内容の一覧（先の続き）>>> os.listdir()Enter←内容リストの取得[’file1.txt’,’a.exe’, … ]←実行結果
結果はリストの形式で得られる．この例の様に，listdir 関数の引数を省略するとカレントディレクトリの内容の一覧が得られるが，キーワード引数 path=’ パス’ に対象のパス（ディレクトリ）を指定することもできる101 ．

listdir 関数は，サブディレクトリを再帰的に検索しない．
2.6.7.4

ディレクトリ内容の一覧 (2)os モジュールの walk 関数を使用すると，サブディレクトリを再帰的に検索する形で内容の一覧を取得する．
書き方：

walk( 対象ディレクトリ )「対象ディレクトリ」の内容をもたらすジェネレータを返す．得られるジェネ
レータは次のような形式のタプルをもたらす．

(格納ディレクトリ, サブディレクトリのリスト, ファイルのリスト)※ ジェネレータに関しては，後の「4.7 ジェネレータ」（p.270）で解説する．

例えば，カレントディレクトリに右図のような階層構造（’<…>’ はディレクト
リ）を持つディレクトリ exdir がある場合の walk 関数の実行例を次に示す．

< exdir >|+ - <emp >|+ - file1 . txt|+ - < subdir >|+ - file2 . txt|+ - file3 . txt|+ - < subsubdir >|+ - file4 . txt

例．walk 関数の使用例（先の例の続き）>>> for x in os.walk(’./exdir’): Enter←内容取得の反復...
print(x)Enter←内容項目の出力...
Enter← for 文の記述の終了(’./exdir’, [’emp’, ’subdir’], [’file1.txt’])←↓内容項目の一覧(’./exdir/emp’, [], [])(’./exdir/subdir’, [’subsubdir’], [’file2.txt’, ’file3.txt’])(’./exdir/subdir/subsubdir’, [], [’file4.txt’])99 ログインしているユーザのこと．
100 Linux の場合も同様の方法を取ることができる．
101 第一引数に文字列として対象のディレクトリを与えてもよい．

106この処理を応用して，ディレクトリ項目，ファイル項目を 1 つずつ取得するジェネレータを実装する例を巻末付録「I.3

os.walk 関数の応用例」（p.431）に示す．
2.6.7.5

ファイルのサイズの取得

os.path.getsize 関数で，既存のファイルのサイズを取得することができる．この関数の引数には，調査対象のファイルのパスを与える．
例．ファイルサイズの取得>>> import os

Enter←モジュールの読込み>>> os.path.getsize(’file1.txt’)31← 31 バイト
2.6.7.6←ファイル’ﬁle1.txt’ のサイズの取得

Enter

ファイル，ディレクトリの検査

指定したパス p が存在するかどうかを検査するには os.path.exists( p ) を実行する．
例．パスの存在検査（先の例の続き）←存在するファイル file.txt の検査>>> os.path.exists(’file.txt’)
Enter
True
←真（存在する）>>> os.path.exists(’xxx’)
Enter
False
←偽（存在しない）←存在しないファイル xxx の検査

戻り値は真理値（True / False）である．ディレクトリの存在を調べる場合も同様の方法で検査できる．
指定したパス p がファイルかどうかを検査するには os.path.isﬁle( p ) を，ディレクトリかどうかを検査するには

os.path.isdir( p ) を実行する．どちらも戻り値は真理値である．
例．ファイル／ディレクトリの検査（先の例の続き）>>> os.path.isfile(’file.txt’)
Enter
True
←真（ファイルである）←存在するパス file.txt がファイルかどうかを検査>>> os.path.isdir(’file.txt’)Enter←それがディレクトリかどうかを検査すると…
False←偽（ディレクトリではない）>>> os.path.isdir(’.’)
Enter←カレントディレクトリ ‘.’ がディレクトリかどうかを検査
True←真（ディレクトリである）
2.6.7.7

ファイル，ディレクトリの削除

ファイルを削除するには remove 関数を使用して，

os.remove(削除対象のファイルのパス)とする．また空ディレクトリを削除するには rmdir 関数を使用して，

os.rmdir(削除対象のディレクトリのパス)とする．削除対象のディレクトリの配下にはファイルやディレクトリがあってはならない．

os モジュールにはこの他にも様々なメソッドが用意されている．詳しくは巻末付録「A.1 Python のインターネット
サイト」（p.359）を参照のこと．

2.6.7.8

実行中のスクリプトに関する情報グローバル変数 ﬁle は，実行中のスクリプトのファイルのパスの文字列102 を保持している．この値を os.path.abspath
関数の引数に与えると，そのファイルの絶対パスの文字列が得られる103 ．パスの文字列からディレクトリの部分のみを取り出すには os.path.dirname 関数を使用する．
これらを応用したプログラム selfpath01.py を示す．

102 古い版の Python ではファイル名の文字列を保持している場合があるので注意されたい．
103 この処理は特にﬁleがファイル名のみの文字列を保持している場合に有用である．

107

プログラム：selfpath01.py
1
2
3
4
5
6
7
8
9
10
11

# coding : utf -8# モジュールの読込み
import os
print ( ’ グ ロ ー バ ル 変 数 __file__ : ’ , __file__ )p = os . path . abspath ( __file__ )print ( ’ 絶 対 パ ス : ’ , p )d = os . path . dirname ( p )print ( ’ デ ィ レ ク ト リ : ’ , d )このプログラムは，自身のファイル名，自身の絶対パス，自身のディレクトリを表示するものである．実行例を次に示す．
実行例．
C:￥Users￥katsu>py selfpath01.py
Enter ←プログラムの実行開始: C:￥Users￥katsu￥selfpath01.py
絶対パス : C:￥Users￥katsu￥selfpath01.py
ディレクトリ : C:￥Users￥katsu

グローバル変数 file

2.6.7.9

パスの表現に関すること

ファイルのパスを表現する文字列を分解，あるいは合成する方法について説明する．
例．パス文字列の分解（os モジュールは読込み済みとする）

Enter>>> p = ’/home/katsu/python/prog1.py’
>>> b
Enter
’prog1.py’←右端の要素を取り出す

Enter>>> b = os.path.basename( p )←パス文字列の作成←内容確認←ファイル名が得られた>>> d = os.path.dirname( p )
>>> d
Enter
←内容確認
’/home/katsu/python’Enter←右端の要素を除外したものを取り出す←ディレクトリ名が得られた

この例では変数 p にパス文字列を作成し，それを basename 関数，dirname 関数で分解している．basename 関数はパス文字列の右端の要素を，dirname 関数は右端の要素を除外したものを返す．またこの例では，パス文字列中のディレ
クトリの区切りの文字としてスラッシュ「/」を用いているが，Windows 環境ではディレクトリの区切り文字は「￥」が基本104 である．

basename，dirname 関数と同様のことが os.path.split 関数でも可能である．
例．split 関数によるパス文字列の分解（先の例の続き）>>> os.path.split( p )Enter←パス文字列の分解(’/home/katsu/python’, ’prog1.py’)←戻り値split 関数は分解結果をタプルにして返す．
ファイル名などの文字列が拡張子を持つ場合，splitext 関数で拡張子とそれ以外の部分に分解することができる．
例．拡張子を持つ文字列の分解（先の例の続き）>>> os.path.splitext( b )Enter←ファイル名の分解(’prog1’, ’.py’)←分解結果のタプル
パス文字列を連結するには os.path.join 関数を使用する．だだしこの場合は，ディレクトリの区切り文字に注意する必要がある．
例．Windows 環境でのパス文字列の連結：その 1（先の例の続き）>>> os.path.join( d, b )Enter’/home/katsu/python￥￥prog1.py’←パス文字列を連結する試み←得られたパス文字列の区切り文字が適切でない

104 Windows 環境でも多くの場合，パス文字列中にスラッシュ「/」が使える．

108

Windows 環境ではディレクトリの区切り文字が「￥」であるのでこのような結果となる．使用しているシステムでのディレクトリの区切り文字は os.sep を参照105 して確認できる．
例．Windows 環境でのディレクトリの区切り文字の確認（先の例の続き）>>> os.sep
’￥￥’

Enter
←確認
←「￥」が区切り文字であることがわかる

Windows 環境での正しい実行例を次に示す．
例．’C:￥Users￥katsu’ と ’programing￥python’ を連結する>>> p = os.path.join( ’C:￥￥Users￥￥katsu’, ’programing￥￥python’ ) Enter>>> print( p )
Enter
←内容確認
C:￥Users￥katsu￥programing￥python←パスの連結←結果表示■ 絶対パス／相対パスの判定表現されたパスが絶対パスであるかどうかを判定するには isabs 関数を使用する．
例．絶対パス／相対パスの判定（先の例の続き）>>> p1 = ’/etc/passwd’; p2 = ’taro/prg1.py’Enter>>> os.path.isabs(p1)
True

Enter

← p1 は←絶対パスである>>> os.path.isabs(p2)
False

Enter

← p2 は←絶対パスではない←パスの文字列 2 種

Windows のパスの場合，パスの左端に「C:￥」もしくは「￥」があると True となる．
この他にも os モジュールには多くの機能が提供されている．更に詳しくは Python の公式インターネットサイトなどを参照されたい．

2.6.8

パス（ファイル，ディレクトリ）の扱い：その２ - pathlib モジュール

Python 3.4 から標準ライブラリとして導入された pathlib は，ファイルとディレクトリを扱うための別の方法を提供する．このライブラリを使用するには次のようにして読み込む．

from pathlib import Path
2.6.8.1

パスオブジェクトの生成

pathlib では，パスを文字列（str オブジェクト）としてではなく，Path クラスのオブジェクトとして扱う．Path オ
ブジェクトを生成するにはコンストラクタの引数にはパスの文字列を与える．
例．/Users/katsu/test01.txt を表すパスオブジェクト

p = Path(’/Users/katsu/test01.txt’)
この例はファイルへのパス /Users/katsu/test01.txt を表す Path オブジェクトを p として生成するものである．

2.6.8.2

カレントディレクトリ，ホームディレクトリの取得

カレントディレクトリ，ホームディレクトリのパスを取得する方法について，Windows 環境における実行例を示す．
例．カレントディレクトリを取得する Path.cwd() メソッド>>> Path.cwd()
Enter←カレントディレクトリの取得
WindowsPath(’C:/Users/katsu/Python’)←カレントディレクトリ
例．ホームディレクトリを取得する Path.home() メソッド>>> Path.home()Enter←ホームディレクトリの取得
WindowsPath(’C:/Users/katsu’)←ホームディレクトリ

105 os.path.sep も同様．

109

2.6.8.3

パスの存在の検査

パスオブジェクトに対して exists メソッドを使用することで，そのパスが存在するかどうかを調べることができる．
（exists の引数は空にする）そのパスが存在する場合は True を，存在しない場合は False を返す．

2.6.8.4

ファイル，ディレクトリの検査

パスオブジェクト p がファイルかディレクトリかを調べるには，例えば表 18 のようにして is ﬁle，is dir メソッドを使用する．

2.6.8.5

p.is file()

表 18: ファイル，ディレクトリの判定
p がファイルの場合に True を，それ以外の場合に False を返す．

p.is dir()p がディレクトリの場合に True を，それ以外の場合に False を返す．

ディレクトリの要素を取得する

パスオブジェクト p がディレクトリの場合，glob メソッド106 を使用して，配下の要素（ファイル，サブディレク
トリなど）を取得することができる．glob メソッドの引数にはワイルドカード（表 19）を含むパターンを文字列型で
与える．

記号

*

表 19: 重要なワイルドカード（一部）意味
記号 意味
任意の長さの任意の文字列?

任意の 1 文字例えば，

plst = list( p.glob(’*’) )とすると，ディレクトリ p の配下の要素のリスト plst が得られる．また，plst = list( p.glob(’*.jpg’) )とすると，ファイル名の末尾が ‘.jpg’ であるような要素をディレクトリ p の配下から探す．

glob メソッドの戻り値は Path オブジェクトの generator 107 であり，上の説明ではそれをリストに変換している．
2.6.8.6

ディレクトリ名，ファイル名，拡張子の取り出し

Path オブジェクトのプロパティには表 20 のようなものがある．

プロパティ

表 20: Path オブジェクトのプロパティ（一部）
説明

.name

Path オブジェクトの末尾の名前（文字列型）.suﬃx

Path オブジェクトの拡張子（文字列型）.parent

Path オブジェクトのディレクトリ部分（Path オブジェクト）

例．Path オブジェクトのプロパティ（Windows での例）>>> from pathlib import PathEnter>>> p = Path(’C:\\Users\\katsu\\a.exe’)←モジュールの読込み

Enter← Path オブジェクトの生成>>> p.nameEnter←ファイル名の取得’a.exe’←ファイル名の部分>>> p.suffix
Enter←拡張子の取得’.exe’←拡張子の部分>>> p.parent
Enter←上位ディレクトリ名の取得
WindowsPath(’C:/Users/katsu’)←上位ディレクトリ（Path オブジェクト）

106 同様のメソッドが使える glob モジュールも存在するが，pathlib モジュールの方が便利である．
107 p.270「4.7 ジェネレータ」で説明する．

110

2.6.8.7

パスの連結

パスオブジェクトに対して二項演算子 ’/’ を使用することで，パスの連結ができる．例えば，p = Path(’/Users’)に対して p / ’katsu’ と記述すると，それは’/Users/katsu’ を意味するパスオブジェクトとなる．

2.6.8.8

ファイルシステム毎のパスの表現

pathlib では基本的なパスのクラスとして Path を使用するが，Python 処理系を実行する OS によってパスのオブジェクトの表現が異なる．次に示すのは Apple 社の macOS における実行例である．
例．macOS 上の Python3 での Path.home() の実行>>> Path.home()Enter←ホームディレクトリの取得←ホームディレクトリ

PosixPath(’/Users/katsu’)

パスオブジェクトは Windows 環境下では WindowsPath クラス，macOS などの UNIX 系 OS の環境下では PosixPath
クラスのオブジェクトとして扱われる．

2.6.8.9

URI への変換

パスオブジェクトに as uri メソッドを実行すると URI （Uniform Resource Identiﬁer）108 形式の文字列が得られる．
例．パスオブジェクトを示す URI の取得>>> p = Path.home()>>> p.as uri()Enter’file:///C:/Users/katsu’
2.6.8.10← p にホームディレクトリのパスを取得

Enter← p を URI に変換←得られた URI

ファイルのオープン

パスオブジェクトに対して open メソッドを使用してファイルを開くことができる．このとき open メソッドの引数にモードやエンコーディングを与える．例えば，パスオブジェクト p をエンコーディングが utf-8 のテキスト形式
として読取り用に開くには次のようにする．

f = p.open(’r’,encoding=’utf-8’)
処理の結果，ファイルオブジェクト f が返される．

2.6.8.11

ファイル入出力

pathlib はファイル入出力のための簡便な方法を提供する．
（pathlib はパスの扱いやファイル入出力に関する一連の機能を提供する）109
テキストファイルのパスを表す Path オブジェクトに対して read text メソッドを実行することで，そのファイルの内容を全て読み取って文字列として返す．
書き方： Path オブジェクト.read text( encoding=エンコーディング )この処理の前後にオープンやクローズの処理は必要ない．
例．Path オブジェクトが示すテキストファイルから内容を読み込む>>> p = Path(’./dat1.txt’)

Enter←テキストファイルのパス>>> txt = p.read text( encoding=’utf-8’ )>>> print( txt )
1 行目
2 行目
3 行目

Enter

Enter

←内容の読み込み

←内容確認

←内容表示

この例では，カレントディレクトリにあるテキストファイル ’dat1.txt’ の内容を全て読み取り，それを txt に与えている．

Path オブジェクトに対して write text メソッドを実行することで，それが示すファイルに文字列を出力することができる．
108 RFC 3986
109 ここで説明する機能は Python3.5 以降で有効である．

111

書き方： Path オブジェクト.write text( 文字列, encoding=エンコーディング )この処理の前後にオープンやクローズの処理は必要ない．処理の後，出力した文字数を返す．
例．Path オブジェクトが示すファイルに文字列を出力する（先の例の続き）>>> p2 = Path(’./dat2.txt’)←出力先のパス

Enter

Enter

>>> p2.write text( txt, encoding=’utf-8’ )12←出力した文字数が返される←文字列の出力

この例では，文字列 txt をファイル ’dat2.txt’ に出力している．
ファイルのパスを表す Path オブジェクトに対して read bytes メソッドを実行することで，そのファイルの内容を全て読み取ってバイト列として返す．
書き方： Path オブジェクト.read bytes( )この処理の前後にオープンやクローズの処理は必要ない．これはバイナリデータをファイルから読み込む手段となる．
例．Path オブジェクトが示すファイルから内容をバイナリデータとして読み込む（先の例の続き）>>> buf = p.read bytes()>>> txt2 = buf.decode(’utf-8’)>>> print( txt2 )
1 行目
2 行目
3 行目

←内容の読み込み（バイナリデータ）

Enter←それをテキスト形式（文字列）に変換

Enter

←内容確認

Enter

←内容表示

この例では，先の例で作成した Path オブジェクトからバイナリデータとして内容を読み込んでいる．読み込んだ内容はバイト列として buf に得られている．

Path オブジェクトに対して write bytes メソッドを実行することで，それが示すファイルにバイト列を出力することができる．
書き方： Path オブジェクト.write bytes( バイト列 )この処理の前後にオープンやクローズの処理は必要ない．処理の後，出力したバイト数を返す．これはバイナリデー
タをファイルに出力する手段となる．
例．Path オブジェクトが示すファイルにバイト列を出力する（先の例の続き）>>> p3 = Path(’./dat3.txt’)Enter←出力先のパス>>> p3.write bytes( buf )Enter←バイト列の出力27←出力したバイト数が返される
この例では，先の例で得たバイト列 buf をファイル ’dat3.txt’ に出力している．

2.6.8.12

ディレクトリの作成

Path オブジェクトに対して mkdir メソッドを実行することで，それが示すディレクトリを作成することができる．
書き方： Path オブジェクト.mkdir( )例．ディレクトリの作成（先の例の続き）>>> p4 = Path(’./dir01’)>>> p4.mkdir()

Enter

Enter

←作成するディレクトリのパス←ディレクトリの作成

この例では，ディレクトリ ’dir01’ を作成している．

2.6.8.13

ファイル，ディレクトリの削除

Path オブジェクトに対して unlink メソッドを実行すると，それが示すファイルを削除することができる．
書き方： Path オブジェクト.unlink( )戻り値は無い．
（None）

112

例．ファイルの削除（先の例の続き）>>> p2.unlink()Enter← Path オブジェクト p2 が示すファイルを削除>>> p3.unlink()Enter← Path オブジェクト p3 が示すファイルを削除

Path オブジェクトに対して rmdir メソッドを実行すると，それが示すディレクトリを削除することができる．
書き方： Path オブジェクト.rmdir( )戻り値は無い．
（None）
例．ディレクトリの削除（先の例の続き）>>> p4.rmdir()Enter← Path オブジェクト p4 が示すディレクトリを削除

付録「I.4 pathlib の応用例」（p.432）に pathlib を応用したサンプルプログラムを掲載する．
コマンド引数の取得

2.6.9

ソースプログラムを Python 処理系（インタプリタ）にスクリプトとして与えて実行を開始する際，起動時に与えたコマンド引数を取得するには sys モジュールのプロパティ argv を参照する．次のプログラム test17.py の実行を例にして説明する．
プログラム：test17.py
1
2
3
4
5
6

# coding : utf -8# 必要なモジュールの読込み
import sys# コマンド引数の取得
print ( ’ args > ’ , sys . argv )このプログラムは，起動時のコマンド引数の列をリストにして表示するものであり，実行すると次のように表示される．
C:￥Users￥katsu> py test17.py 1 2 3 a b
Enter← OS のコマンドラインから起動（Windows の場合）
args> [’test17.py’, ’1’, ’2’, ’3’, ’a’, ’b’] ←与えた引数が得られる

このように，ソースプログラム名から始まる引数が文字列のリストとして得られることがわかる．コマンド引数からプログラムに数値を与える場合は，文字列として得られた引数を，int 関数 や ﬂoat 関数を用いて適切な型に変換すると良い．

Python で実用的なコマンドツールを作成する際には，コマンド起動時に与えられた引数を解析するための更に高度な機能が求められることがある．それに関しては後の「4.26 コマンド引数の扱い：argparse モジュール」（p.317）で解説する．

2.6.10

入出力処理の際に注意すること

実際のシステムにおける入出力処理の際には，エラー（例外）が発生することがある．例えば，ファイルのオープンや読込み，書き出しの際に，その処理が実行できない状況が発生しうる．具体的な例外事象としては，存在しないファイルを読込み用にオープンしようとしたり，アクセス権限の無いシステム資源に対して入出力を試みたりと枚挙にいとまがない．従って，実用的なアプリケーションプログラムを作るにあたっては，発生しうる例外事象を十分に想定して対応策の処理110 を行う形で実装しなければならない．

Python では，with 構文を用いた記述が可能であり，ファイルのオープンとクローズや例外処理のハンドリングを簡潔に記述することができる．これに関しては「4.20 with 構文」（p.302）で説明する．

2.6.11

CSV ファイルの取り扱い： csv モジュール

表形式のデータを表現するものに CSV 形式のデータフォーマット111 があり，多くのアプリケーションソフトウェ
ア112 においてこの形式のデータを取り扱うことができ，異なるアプリケーション間での表形式データの交換に広く
110 「2.4.1.6 例外処理」（p.51），「4.18 例外（エラー）の処理」（p.299）を参照のこと．
111 RFC4180 として標準化されている．
112 Microsoft 社の Excel などが有名．

113

用いられている．

CSV 形式では値をコンマ「, 」で区切って表現し，そのようなデータ並びで行（レコード）を構成する．また，CSV
形式のデータファイルはそのような複数の行から構成される．

Python 言語ではリストに対する join メソッドを応用することで CSV 形式のデータ（文字列）を構成することがで
き，逆に，文字列に対する split メソッドを応用することで CSV の各値を分離することができるが，ファイル入出力の目的で CSV データをより簡便な形で取り扱うために csv モジュールが標準的に提供されており，これを利用することができる．csv モジュールを利用するには

import csv
として Python 処理系に読み込み，「csv.」の接頭辞を付けて各種の機能を呼び出す．

2.6.11.1

CSV ファイルの出力

ここでは，CSV データのファイルへの出力に関して例を挙げて説明する．まず次のような処理によってサンプル
データをリストの形で作成する．
例．サンプルデータ（リスト）の作成>>> tbl = [[x+y for y in range(1,5)] for x in range(10,40,10)] Enter ←サンプルデータの作成>>> for r in tbl:...

print( r )Enter←内容確認（繰り返し処理）←繰り返し処理の記述の終了

Enter← 3 行 4 列の表がリストの形式で tbl に得られている[11, 12, 13, 14][21, 22, 23, 24][31, 32, 33, 34]

この例で得られたデータ tbl を CSV 形式ファイルに出力するには for などによる反復制御で tbl の各要素を出力しても良いが，csv モジュールを利用することでその処理が簡略化される．
【CSV ファイルの出力の手順】

1. open 関数で出力対象ファイルのファイルオブジェクトを作成する．
2. 上で作成したファイルオブジェクトから writer オブジェクト を作成する．
3. 上で作成した writer オブジェクトに対して writerow メソッドもしくは writerows メソッドを用いてCSV データを出力する．
4. 出力処理が終われば，1 で作成したファイルオブジェクトに対して close メソッドを実行してファイルを閉じる．
この手順に従って，先に作成したリスト tbl の内容を出力する例を示す．
例．writerow による CSV ファイルの出力（先の例の続き）>>> import csv

Enter←モジュールの読み込みEnter>>> f = open(’csvTest01.csv’,’w’,newline=’’)>>> cw = csv.writer(f)>>> f.close()Enter←上記 f から writer オブジェクトを作成

Enter>>> for r in tbl: Enter...
b = cw.writerow(r)
...
Enter

←出力ファイルのオープン113←繰り返し処理によって← CSV を 1 行ずつ出力する←繰り返しの記述の終了

Enter←出力ファイルのクローズ

この例では writerow メソッドで CSV データを 1 行ずつ出力している．
書き方：

writer オブジェクト.writerow(リスト)

1 次元の「リスト」の内容を「writer オブジェクト」を通して CSV 形式で 1 行出力する．writerow メソッドの内部
では，ファイルオブジェクトに対する write メソッドの処理を応用しており，内部で実行した write メソッドの戻り値を結果として返す．
例に示した処理によって次のような CSV ファイル csvTest01.csv が作成される．
113 このように「newline=”」として改行コードを指定すると安全である．

114

CSV ファイル：csvTest01.csv
1
2
3

11 ,12 ,13 ,14
21 ,22 ,23 ,24
31 ,32 ,33 ,34

上の例と同様の処理は writerows メソッドを用いることで更に簡潔に記述できる．
例．writerows による CSV ファイルの出力（先の例の続き）

Enter>>> f = open(’csvTest01.csv’,’w’,newline=’’)←出力ファイルのオープン>>> cw = csv.writer(f)Enter← writer オブジェクトの作成>>> cw.writerows(tbl)Enter← tbl の内容を一度に出力>>> f.close()←出力ファイルのクローズ

Enter

この例では writerows メソッドで CSV データを複数行まとめて出力している．
書き方：

writer オブジェクト.writerows(リスト)

入れ子になった 2 次元の「リスト」の内容を「writer オブジェクト」を通して CSV 形式で出力する．すなわち「リスト」の各要素を各行とする CSV データとして出力する．
参考）writerow，writerows にはリスト以外のイテラブルなオブジェクトを引数に与えることもできる．
■ 区切り文字の指定方法

CSV 形式はコンマで区切られたものであるが，別の文字を区切り文字に用いることもできる．具体的には writer
オブジェクト生成時にキーワード引数 ‘delimiter=区切り文字’ を与える．
例．出力ファイルの区切り文字をタブ「￥t」にする（先の例の続き）←出力ファイルのオープン>>> f = open(’csvTest02.tsv’,’w’,newline=’’)Enter>>> cw = csv.writer(f,delimiter=’￥t’)← writer オブジェクト作成：区切り文字を指定

Enter>>> cw.writerows(tbl)>>> f.close()Enter← tbl の内容を一度に出力←出力ファイルのクローズ

Enter

この処理によって次のような CSV ファイル csvTest02.tsv が作成される．

CSV ファイル：csvTest02.tsv
1
2
3

11
21
31

12
22
32

13
23
33

14
24
34

■ 辞書オブジェクトを CSV ファイルに出力する方法

DictWriter オブジェクトを用いることで，辞書オブジェクトを CSV データとして出力することができる．次のよ
うにして作成した辞書オブジェクトを CSV データとして出力する例を示す．
例．サンプルの辞書オブジェクトの作成（先の例の続き）>>> d = { ’col1’:1, ’col2’:2, ’col3’:3, ’col4’:4, ’col5’:5 } Enter ←辞書オブジェクト作成
>>> d
Enter
{’col1’: 1, ’col2’:←内容確認
2, ’col3’: 3, ’col4’:

4, ’col5’:

5}DictWriter による出力では，出力対象の CSV ファイルの各列はフィールド名（カラム名）を持つ．そして，出力する辞書オブジェクトの各キーを CSV のフィールドに対応させる．次に，実際に辞書オブジェクトを CSV ファイルに出力（1 行のみ）する例を示す．

115

例．辞書オブジェクトを CSV データとして出力する（先の例の続き）>>> f = open(’csvTest03.csv’,’w’,newline=’’)>>> cn = [’col5’,’col3’,’col1’]

Enter

Enter

←出力ファイルのオープン← CSV 用の見出し（フィールド）の定義>>> dw = csv.DictWriter( f, fieldnames=cn, extrasaction=’ignore’ ) Enter ← DictWriter 作成>>> dw.writeheader()Enter←見出し行の出力
16←上記処理の戻り値>>> b = dw.writerow( d )>>> f.close()

Enter

Enter

←辞書 d を CSV データの 1 つの行として出力←出力ファイルのクローズ

辞書オブジェクト d は ’col1’〜’col5’ の 5 つのエントリを持つが，この例では ’col1’，’col3’，’col5’ の 3 つのエントリを出力対象としており，そのリストを変数 cn に与えている．この出力対象のフィールドのリストは DictWriter オブ
ジェクト生成時にキーワード引数

ﬁeldnames=出力するフィールドのリストとして与える．またこの例のように，辞書オブジェクトが出力対象としないエントリを含んでいる場合はキーワード
引数「extrasaction=’ignore’」を与える114 ．

CSV 形式ファイルは先頭の行がフィールド名になっていることが一般的である．上の例の writeheader メソッドは
出力先の CSV ファイルにフィールド名の見出しを出力するものである．
上の例の処理によって次のような CSV ファイル csvTest03.csv が作成される．

CSV ファイル：csvTest03.csv
1
2

col5 , col3 , col1
5 ,3 ,1

DictWriter オブジェクトに対して writerows メソッドを用いると，複数の辞書を連続して出力することができる．
そのことをプログラム Dic2Csv01.py で示す．
プログラム：Dic2Csv01.py
1
2
3
4
5
6
7
8
9
10
11
12

# coding : utf -8
import csv# 出 力 用 デ ー タ （3 レ コ ー ド 分 の 辞 書 を リ ス ト 形 式 で 用 意 ）dLst = [ { ’A ’:11 , ’B ’:12 , ’C ’:13 , ’D ’:14 , ’E ’:15 } ,# 辞 書1{ ’A ’:21 , ’B ’:22 , ’C ’:23 , ’D ’:24 , ’E ’:25 } ,# 辞 書2{ ’A ’:31 , ’B ’:32 , ’C ’:33 , ’D ’:34 , ’E ’:35 } ]# 辞 書3# 出力処理f = open ( ’ csvTest03 -2. csv ’ , ’w ’ , newline = ’ ’)
# 出力ファイルをオープン
dw = csv . DictWriter (f , fieldnames =[ ’A ’ , ’C ’ , ’E ’] , extrasaction = ’ ignore ’)
dw . writeheader ()# 見出し行の出力dw . writerows ( dLst )# リストの各要素（辞書）を出力
f . close ()# 出力ファイルのクローズ

解説）
このプログラムでは，出力する複数のレコードとなる辞書をリスト dLst として用意（4〜6 行目）している．そして dLst の全ての要素について，キー ’A’,’C’,’E’ のエントリを抽出して writerows メソッドで出力（11 行目）している．
このプログラムを実行すると，ファイル csvTest03-2.csv のような CSV データが出来上がる．

CSV ファイル：csvTest03-2.csv
1
2
3
4

A ,C , E
11 ,13 ,15
21 ,23 ,25
31 ,33 ,35

114 DictWriter による辞書オブジェクトの出力では，辞書オブジェクトの全てのエントリのキーが出力先 CSV のフィールドに対応しなければならない．この制限を解除するためにこのキーワード引数 extrasaction を与える．

116

2.6.11.2

CSV ファイルの入力

CSV 形式のテキストファイルを入力する方法について解説する．
【CSV ファイルの入力の手順】

1. open 関数で入力ファイルのファイルオブジェクトを作成する．
2. 上で作成したファイルオブジェクトから reader オブジェクト を作成する．
3. 上で作成した reader オブジェクトをイテラブルとみなしてデータを順次取り出す．
4. 入力処理が終われば，1 で作成したファイルオブジェクトに対して close メソッドを実行してファイルを閉じる．
先の例で作成した CSV ファイル csvTest01.csv（p.115）を読み込む処理を例に挙げて，CSV ファイルの入力について解説する．
例．CSV ファイルの読み込み（先の例の続き）

Enter>>> f = open(’csvTest01.csv’,’r’)Enter>>> cr = csv.reader(f)← CSV ファイルのオープン← reader オブジェクト作成>>> for r in cr: Enter ← reader オブジェクトからデータを取り出す反復制御...
print(r)Enter ←入力した行を表示...
Enter ←反復制御の記述の終了←入力したデータ（リスト）[’11’, ’12’, ’13’, ’14’][’21’, ’22’, ’23’, ’24’][’31’, ’32’, ’33’, ’34’]←入力ファイルのクローズ

Enter>>> f.close()

この例では，入力用の CSV ファイルを開き，それを元に reader オブジェクト cr を作成し，cr からデータを 1 行ず
つ読み込んでいる．このとき各行はリストの形で得られる．reader オブジェクトはイテラブルであるので様々な形で応用することができる．
例．CSV ファイルの内容を全て読み込む（先の例の続き）

Enter>>> f = open(’csvTest01.csv’,’r’)Enter>>> cr = csv.reader(f)>>> tbl = [r for r in cr]>>> tblEnter← reader オブジェクト作成

Enter←リストの内包表記によって全ての内容を読み込む←入力ファイルのクローズ

Enter>>> f.close()← CSV ファイルのオープン←内容確認[[’11’, ’12’, ’13’, ’14’],[’21’, ’22’, ’23’, ’24’],[’31’, ’32’, ’33’, ’34’]]←得られたデータ

この例ではリストの内包表記 tbl = [r for r in cr] を用いて CSV ファイルの全内容を読み込んでいるが，reader
オブジェクト cr はイテラブルであるため list(cr) として全てを一度にリストに変換することもできる．
■ 見出し行をスキップする方法

CSV ファイルの先頭行が見出し行である場合，先頭行がデータでないことからそれを排除する場合がある．先頭行を排除する最も単純な方法として，CSV から得られたリストの先頭要素を排除する方法がある．例えば，上の例で得られたリスト tbl の先頭要素を排除するには次のようにする．
例．見出し行の排除（先の例の続き）>>> tbl[1:]Enter←先頭行の排除[[’21’, ’22’, ’23’, ’24’],[’31’, ’32’, ’33’, ’34’]]←先頭要素が排除されている

根本的な方法としては，reader オブジェクトから読み込む時点で最初の行をスキップしておくという方法もある．
（次
の例）

117

例．見出し行の排除：その２（先の例の続き）>>> f = open(’csvTest01.csv’,’r’)>>> cr = csv.reader(f)>>> r = next(cr)Enter>>> tbl

Enter

Enter

← reader オブジェクト作成← cr の最初の要素を読み飛ばすEnter>>> tbl = list(cr)>>> f.close()Enter← CSV ファイルのオープン

Enter← CSV ファイルの全ての内容を読み込む←入力ファイルのクローズ←内容確認[[’21’, ’22’, ’23’, ’24’],[’31’, ’32’, ’33’, ’34’]]←先頭要素が排除されている

この例では，CSV データをリスト tbl に取得する前に next 関数で最初の要素（行）を読み飛ばしている．
■ CSV データの値を数値として読み込む方法

reader オブジェクトから読み込む値は文字列である．これを数値（整数，浮動小数点数）として読み込むには読み込み時に型を変換する．例えば先の例で使用した CSV ファイルの第 1 列を整数として，第 2 列を浮動小数点数として読み込むには次のような方法がある．
例．型を指定して読み込む（先の例の続き）>>> f = open(’csvTest01.csv’,’r’)>>> cr = csv.reader(f)

Enter

Enter

>>> tbl = [ [int(r[0]),float(r[1])]+r[2:]>>> f.close()>>> tbl

Enter

Enter

for r in cr]←型を変換しながらリストに変換Enter←入力ファイルのクローズ←内容確認[[11, 12.0, ’13’, ’14’],[21, 22.0, ’23’, ’24’],[31, 32.0, ’33’, ’34’]]←第 1 列が整数，第 2 列が浮動小数点数，
それ以降の列は文字列として得られている

注意）
この方法では，CSV ファイルの中に数値に変換できないものが値として含まれていると ValueError が発生する．
例えば次のような CSV ファイル csvTest01-err.csv を読み込む場合について考える．

CSV ファイル：csvTest01-err.csv
1
2
3

11 ,12 ,13 ,14
xx ,22 ,23 ,24
31 , yy ,33 ,34

このファイルの 2 行目，3 行目に数値でないものが含まれている．先の例と同様の方法でこのファイルを読み込む
試みを次に示す．
例．数値に変換できない値を数値として読み込む試み（先の例の続き）>>> f = open(’csvTest01-err.csv’,’r’)>>> cr = csv.reader(f)

Enter

Enter

>>> tbl = [ [int(r[0]),float(r[1])]+r[2:]for r in cr] Enter ←数値として読み込もうとすると…

Traceback (most recent call last):←エラーが発生するFile "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
ValueError: invalid literal for int() with base 10: ’xx’

← ValueError

これは，整数に変換しようとする値として文字列 ’xx’ が存在していることに起因するエラーである．このような場合，数値として解釈できない値を nan（非数）として扱うなどの工夫が必要となる．次にそのための工夫の 1 例を示す．
まず，文字列を ﬂoat に変換するための関数 toFloat を次のように定義する．

118

例．文字列を ﬂoat 型に変換する関数の定義（先の例の続き）>>> def toFloat(s):
...
...
...
...
...
>>>

← nan を使用するために math ライブラリを読み込む

Enter>>> import math

←関数定義115 の開始

Enter

try: Enter
return float(s)Enter←文字列を ﬂoat に変換したものを返す
except: Enter
return math.nan
Enter←エラーが発生した場合は nan を返す
Enter←関す定義の記述の終了←対話モードのプロンプトに戻った

これは「try…except〜」の構文116 を応用して，ﬂoat に変換できないものを ﬂoat に変換しようとした場合に発生するエラーを受けて nan を返す関数である．この関数 toFloat を用いた例を次に示す．
例．数値に変換できない値を nan に変換して読み込む（先の例の続き）

Enter>>> f = open(’csvTest01-err.csv’,’r’)>>> cr = csv.reader(f)Enter
for r in cr] Enter ← toFloat で変換>>> tbl = [ [toFloat(r[0]),toFloat(r[1])]+r[2:]>>> f.close()>>> tbl

Enter
←内容確認

Enter

[[11.0, 12.0, ’13’, ’14’],[nan, 22.0, ’23’, ’24’],[31.0, nan, ’33’, ’34’]]←’xx’ が nan に変換されている←’yy’ が nan に変換されている

読み込んだデータの第 1 列と第 2 列が ﬂoat の型に変換されている．nan（非数）は ﬂoat 型であるので，この例では
第 1 列，第 2 列共に ﬂoat に変換することとした．
■ 区切り文字の指定方法

CSV ファイルの区切り文字がコンマ以外のものである場合，reader オブジェクト作成時にキーワード引数 ‘delimiter=
区切り文字’ を与える．
例．区切り文字を指定して入力する（先の例の続き）>>> cr = csv.reader(f,delimiter=’￥t’)>>> tbl = [r for r in cr]>>> f.close()>>> tbl

Enter

Enter

← CSV ファイルのオープン

Enter>>> f = open(’csvTest02.tsv’,’r’)← reader オブジェクト作成：区切り文字指定

Enter←リストの内包表記によって全ての内容を読み込む

Enter←入力ファイルのクローズ←内容確認[[’11’, ’12’, ’13’, ’14’],[’21’, ’22’, ’23’, ’24’],[’31’, ’32’, ’33’, ’34’]]←得られたデータ

これは p.115 で作成したタブ区切りの CSV ファイル csvTest02.tsv を読み込む処理である．
■ CSV ファイルからの入力を辞書オブジェクトにする方法

DictReader オブジェクトを用いることで，CSV ファイルから読み取った行を辞書オブジェクトにすることができる．
例．CSV ファイルの各行を辞書オブジェクトとして得る（先の例の続き）>>> f = open(’csvTest03.csv’,’r’)← CSV ファイルのオープン

Enter>>> dr = csv.DictReader( f )Enter← DictReader オブジェクト作成>>> d = [dict(r) for r in dr]Enter←読み取った各行を辞書にして，それらのリストを取得>>> f.close()Enter←入力ファイルのクローズ

>>> d
Enter
←内容確認
[{’col5’: ’5’, ’col3’: ’3’, ’col1’:’1’}]

115 def 文による関数の定義に関しては「2.7 関数の定義」（p.122）で解説する．
116 詳しくは「2.4.1.6 例外処理」（p.51），「4.18 例外（エラー）の処理」（p.299）を参照のこと．

119

この例では p.116 で作成した CSV ファイル csvTest03.csv の内容を読み取って，その行を辞書オブジェクトにしている．また，読み取った全内容はそれら辞書オブジェクトのリストとして得ている．得られた辞書オブジェクトのキーは

CSV ファイルの先頭行（見出し行）の項目から得ている．またこの例ではリストの内包表記を応用して d = [dict(r)for r in dr] として CSV ファイルの全内容を読み取っているが，DictReader オブジェクト dr はイテラブルなので list(dr) として全内容を読み取ることもできる．

CSV ファイルの全ての行（先頭行も含む）をデータとみなして読み込むには DictReader オブジェクト作成時にキー
ワード引数

ﬁeldnames=フィールド名のリストを与える．これにより「フィールド名のリスト」の要素をキーとする辞書オブジェクトが得られる．
例．全ての行をデータとみなして辞書オブジェクトの形で読み込む（先の例の続き）>>> f = open(’csvTest03.csv’,’r’)>>> cn = [’A’,’B’,’C’]Enter← CSV ファイルのオープン

Enter←フィールド名のリスト>>> dr = csv.DictReader( f, fieldnames=cn )>>> d = list(dr)>>> f.close()
>>> d

Enter

← DictReader 作成：フィールド名指定←読み取った各行を辞書にして，それらのリストを取得

Enter

Enter

Enter

←入力ファイルのクローズ←内容確認[ {’A’: ’col5’, ’B’: ’col3’, ’C’: ’col1’},{’A’: ’5’, ’B’: ’3’, ’C’: ’1’} ]←先頭の行もデータとして読み込んでいる←次の行のデータ

この例では入力用 CSV ファイルの各列のフィールド名を ’A’，’B’，’C’ と見なしている．それらのリストを変数 cnに与えて，それを DictReader のキーワード引数 ‘ﬁeldnames=’ に与えている．これによって CSV ファイルの先頭行もデータとして読み込まれている．
■ クォート文字を含む CSV ファイルの読み込み

CSV 形式ファイルの中の値（項目）はクォート文字を含むものがある．例えば，コンマ文字を含む項目を 1 つの値として取り扱う場合は，データ項目の区切り文字としてのコンマ文字と区別する必要がある．例えば表計算ソフト
ウェアで図 7 のような表を作成した状況を考える．

図 7: Microsoft Excel で CSV ファイルを作成する
この表は 1 つのセル（B4）の内容がコンマ文字を含んでおり，これを CSV ファイルとして保存117 すると次に示すファイル csvExcel01.csv のようになる．

CSV ファイル：csvExcel01.csv
番号, 語, 意味1,dog, 犬2,cat, 猫
3,"knife,blade", ナイフ
このファイルの 4 行目の 2 番目の項目を見ると，データとしてのコンマ文字を区切り文字と区別するために二重引
用符「”」で括られているのがわかる．このファイルを DictReader オブジェクトで読み込む例を示す．

117 保存時のファイルの種類として「CSV UTF-8 (カンマ区切り) (*.csv)」を選択する．

120

例．コンマ文字を含む項目の取り扱い>>> import csv

Enter←モジュールの読み込み>>> f = open(’csvExcel01.csv’,’r’,encoding=’utf-8-sig’) Enter ← CSV ファイルのオープン118>>> dr = csv.DictReader( f )Enter← DictReader 作成>>> d = [dict(r) for r in dr]Enter←読み取った各行を辞書にして，それらのリストを取得>>> f.close()
>>> d

Enter

Enter

←入力ファイルのクローズ←内容確認[ {’ 番号’: ’1’, ’ 語’: ’dog’, ’ 意味’: ’ 犬’},
←読み込んだ内容{’ 番号’: ’2’, ’ 語’: ’cat’, ’ 意味’: ’ 猫’},{’ 番号’: ’3’, ’ 語’: ’knife,blade’, ’ 意味’: ’ ナイフ’} ]データとしてのコンマ文字がデータとして読み込まれていることがわかる．これに対して，このファイル csvExcel01.csv
を通常のテキストファイルのように読み込み，改行コードとコンマ文字で split すると問題が起こる．
（次の例参照）
例．コンマ文字を含む項目を正しく取り扱えないケース（先の例の続き）>>> f = open(’csvExcel01.csv’,’r’,encoding=’utf-8-sig’) Enter ← CSV ファイルのオープン>>> lines = f.read().splitlines()←ファイルの全内容を読み込み行を分割

Enter>>> tbl = [lin.split(’,’) for lin in lines]>>> f.close()>>> tbl

Enter

Enter

Enter

←各行をコンマ文字で分割←入力ファイルのクローズ←内容確認[ [’ 番号’, ’ 語’, ’ 意味’],[’1’, ’dog’, ’ 犬’],[’2’, ’cat’, ’ 猫’],[’3’, ’"knife’, ’blade"’, ’ ナイフ’]]←コンマ文字の取り扱いが正しくない

データの最後の行の中の項目 ’knife,blade’ のコンマ文字が区切り文字として認識され，その項目が正しくない形で分割されている．この例からもわかるように，CSV ファイルの扱いには csv モジュールを使用すべきであることがわかる．
参考）配列処理用のライブラリ NumPy や，データ処理用ライブラリ pandas などを用いると更に簡便な方法でCSV 形式ファイルを取り扱うことができる119 ．

118 Microsoft Excel の表を「BOM 付き UTF-8」のエンコーディングで保存した CSV ファイルを読み込む際はこのようにしてオープンする．
119 NumPy については拙書「Python3 ライブラリブック」で，pandas については拙書「Python3 によるデータ処理の基礎」で解説しています．

121

関数の定義2.7関数とは，関数名（引数列）の形式で呼び出すサブプログラムで，メインプログラムや他のサブプログラムから呼び出す形で実行する．関数は，処理結果を何らかのデータとして返す（戻り値を持つ）ものである．Python 言語処理系は，予め多くの組込み関数を提供している120 が，利用者が独自に関数を定義121 して使用することもできる．
《 関数定義の記述 》
書き方：

def

関数名（仮引数列）:（処理内容）
return 戻り値「処理内容」から return までの行は，def よりも右の位置に同一の深さのインデント（字下げ）を施したスイー
トとして記述する．関数の処理は return のところで終了し，呼び出し元に実行の制御が戻る．処理の結果の戻り
値を return の右側に記述するとその値が呼び出し元に返される．return の右側の戻り値は省略することができ，また return 文を省略してスイートの記述を終えることもできる．その場合は戻り値は None となる．
関数定義の例．加算する関数 kasan の定義（プログラム test08-1.py）
プログラム：test08-1.py
1
2
3
4
5
6
7
8

# coding : utf -8# 加算する関数
def kasan (x , y ):z = x + yreturn z# メインルーチン
a = kasan (12 ,34)
print ( a )このスクリプトファイルを Python 処理系が読み込むと内容が上から順番に解釈されるが，この時 3〜5 行目の関数は「定義の記述」として扱われ，読み込みの段階ではまだ実行されない．そして処理系が 7 行目を読み込んだ時点で関数

kasan が実際に実行され，その戻り値（return による計算結果）が変数 a に割当てられ，8 行目の print によってその値が出力される．実行結果として46と表示される．
■ 実引数，仮引数
引数は関数名の後ろに括弧 ‘( )’ で括って記述する．関数の定義を記述する際に書き並べる引数を仮引数と呼び，その関数を呼び出す際に与える引数を実引数と呼ぶ．
（図 8）
仮引数（定義を記述する側）

def tasu( x, y ):return x+ya = tasu( 1, 2 )print( a )実引数（実行する側）

図 8: 引数の名称

2.7.1

引数について関数はそれを呼び出したプログラムから仮引数に値を受け取って処理を行う．先のプログラム test08-1.py では関数

kasan は 2 つの仮引数を持ち，それらに受け取った値の加算を行っている．呼び出す側の実引数と関数定義に記述さ120 全ての組込み関数の名前は dir(builtins ) で得られるリストに含まれているので確認できる．

121 ユーザ定義関数と呼ぶことがある．

122

れた仮引数は，記述された順序でそれぞれ対応する．この形式の引数を位置引数という．位置引数以外にも引数の受け渡しの形式があり，それらについては後に説明する．

2.7.1.1

引数に暗黙値を設定する方法

関数の引数には暗黙値を設定することができる．
（次の例）
例．引数に暗黙値を取る関数>>> def kasan2( x, y=1 ): Enter←関数 kasan2 の定義の記述の開始...
return x+y
Enter
...
Enter
←関数 kasan2 の定義の記述の終了>>> kasan2( 1, 2 )
Enter
3
←評価結果

←引数を 2 つ与えて評価（実行）>>> kasan2( 1 )
Enter
2
←評価結果

← 2 つ目の引数を省略して評価（実行）

この例では，関数 kasan2 の 2 番目の引数には暗黙値として 1 が設定されている．これにより，この関数の 2 番目の引数を省略して評価（実行）すると関数内では y=1 として扱われる．

2.7.1.2

仮引数のシンボルを明に指定する関数呼び出し（キーワード引数）

関数を呼び出す際の実引数に，関数定義の記述にある仮引数の記号を明に指定することが可能である．例えば次のように定義された関数 fn があるとする．
例．サンプル用の関数 fn>>> def fn(x,y): Enter...
print(’ 第 1 引数 x:’,x)...
print(’ 第 2 引数 y:’,y)
...
Enter
>>>

Enter
Enter

← Python のプロンプトに戻った

この関数を呼び出す際に，仮引数の記号を使って fn(y=2,x=1) などと記述することができる．
例．上記関数 fn の呼び出し（先の例の続き）

Enter>>> fn(1,2)
第 1 引数 x:
第 2 引数 y:

1
2>>> fn(y=2,x=1)
第 1 引数 x:
第 2 引数 y:←通常の呼び出し形式

Enter

1
2

←仮引数の記号を指定した呼び出し←仮引数の記述の順序とは無関係に
正しく値を受け取っている

このような引数の形式はキーワード引数と呼ばれ，仮引数の記述とは異なる順序で実引数を与えることができる．

2.7.1.3

引数の個数が不定の関数

仮引数の個数が予め決まっていない関数も定義できる．それを実現する場合は，関数定義の仮引数にアスタリスク「＊」で始まる名前を指定する．
書き方：

kansu( *args ) { （定義内容） }このように記述すると，仮引数 args がタプルとして解釈される．すなわち関数内では，args は受け取った値を要素として持つタプルとなる．これを応用したプログラムの例を test08-2.py に示す．
プログラム：test08-2.py
1
2
3
4
5
6
7
8

# coding : utf -8# 個数未定の引数を取る関数
def argtest1 ( * a ):print ( ’ 引 数 に 受 け 取 っ た も の : ’ , a )for m in a :print ( m )return len ( a )

123

9
10
11

# メインルーチン
n = argtest1 ( ’a ’ ,1 , ’b ’ ,2)print ( ’ 引 数 の 個 数 ’ , n )これを実行すると次のような表示となる．
引数に受け取ったもの:a1b2
引数の個数 42.7.1.4(’a’, 1, ’b’, 2)

実引数に ‘*’ を記述する方法

実引数に ‘*’ を記述することができる．この場合は，‘*’ の直後に記述されたデータ構造の要素が，個々の引数として展開されて関数に渡される．これに関してはサンプルプログラム argTest01.py で動作を確認できる．
プログラム：argTest01.py
1
2
3
4
5
6
7
8
9
10
11
12
13

# coding : utf -8# テスト用関数
def f ( * arg ):print ( ’ 引 数 列 : ’ , arg )# リストの全要素を引数列として渡す
a = [ ’x ’ , ’y ’ , ’z ’]; f ( * a )# タプルの全要素を引数列として渡す
a = ( ’s ’ , ’t ’ , ’u ’); f ( * a )# 文字列を構成する文字を引数列として渡す
a = ’ arguments ’;f( *a )

このプログラムを実行すると次のような結果となる．
引数列:
引数列:
引数列:

(’x’, ’y’, ’z’)(’s’, ’t’, ’u’)(’a’, ’r’, ’g’, ’u’, ’m’, ’e’, ’n’, ’t’, ’s’)

データ構造の各要素が個々の引数として関数に渡されていることがわかる．この記述方法は，多数の引数を関数に渡す際の簡便な方法となる

2.7.1.5

キーワード引数を辞書として受け取る方法

Python の関数ではキーワード引数が使える，次のプログラム例 test08-3.py について考える．
プログラム：test08-3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# coding : utf -8# - - - キ ー ワ ー ド 引 数 を 取 る 関 数 --def argtest2 ( ** ka ):print ( ’ 名 前 : ’, ka [ ’ name ’] )print ( ’ 年 齢 : ’, ka [ ’ age ’] )print ( ’ 国 籍 : ’, ka [ ’ country ’] )n = len ( ka )return n# - - - メ イ ン ル ー チ ン --a = argtest2 ( name = ’ Tanaka ’ , country = ’ Japan ’ , age =41 )print ( ’ 引 数 の 個 数 : ’,a , ’\n ’)# キーワード引数を辞書の形で与える方法
d = { ’ name ’: ’ John ’ , ’ country ’: ’ USA ’ , ’age ’: ’35 ’}a = argtest2 ( ** d )このようにアスタリスク 2 つ「**」で始まる仮引数を記述すると関数側でその仮引数は辞書型オブジェクトとして扱える．
（関数側ではキーは文字列型）

124

このプログラムの 11 行目にargtest2( name=’tanaka’, country=’japan’, age=41 )という形の関数呼び出しがある．キーワード引数を用いると「キーワード=値」という形式で引数を関数に渡すことができることを先に解説した．このプログラムを実行すると次のような表示となる．
名前: Tanaka
年齢: 41
国籍: Japan
引数の個数: 3
名前:
年齢:
国籍:

2.7.1.6

John
35
USA

実引数に ‘**’ を記述する方法

先のプログラム test08-3.py の 16 行目に

a = argtest2( **d )という形の関数呼び出しがある．これは一連のキーワード引数を辞書オブジェクトとして関数に与えるための方法であり，辞書オブジェクトの直前に ‘**’ を記述し，それを実引数とする．

2.7.1.7

引数に与えたオブジェクトに対する変更の影響

関数が引数に受け取ったオブジェクトを変更する場合，その変更が元のオブジェクトに及ぼす影響ついて例を挙げて示す．次の例のように定義された関数 f は，引数として受け取ったものを関数内で変更する．
例．引数に受け取ったものを関数内で変更する関数 fEnter>>> def f(nm,flt,c,strng,tpl,lst,dct,s):
Enter

...

nm *= 2...

print(’ 関数内の nm:’,nm)...

flt = flt**0.5...

print(’ 関数内の flt:’,flt)...

c = 2+3j...

print(’ 関数内の c:’,c)

Enter

...

strng = ’ 新しい文字列’

Enter

...

print(’ 関数内の strng:’,strng)...

tpl = (7,8,9)...

print(’ 関数内の tpl:’,tpl)...

lst[0],lst[-1] = lst[-1],lst[0]...

print(’ 関数内の lst:’,lst)

Enter

...

dct[’newKey’] = ’newValue’

Enter

...

print(’ 関数内の dct:’,dct)

Enter

...

s.add(’z’)...

print(’ 関数内の s:’,s)

...
>>>

Enter

Enter

Enter
Enter

Enter

Enter

Enter
Enter
Enter

Enter
Enter

←関数定義の記述の終了←対話モードのプロンプトに戻った

次に関数 f の実行結果を観察する．まず各種のデータ型のオブジェクトを次のようにして用意する．

125

例．各種オブジェクトの用意（先の例の続き）>>> nm = 3

←整数

Enter

>>> flt = 5.0

Enter←浮動小数点数>>> c = 1+2j

Enter

←複素数

>>> strng = ’ 元の文字列’>>> tpl = (4,5,6)

←文字列

Enter

←タプル

Enter

←リスト

Enter

>>> lst = [’a’,’b’,’c’]>>> dct = {’apple’:’ りんご’,’orange’:’ みかん’}>>> s = {’x’,’y’}

Enter

←辞書
←セット

Enter

この状況で関数 f を実行する．
例．関数 f の実行（先の例の続き）>>> f(nm,flt,c,strng,tpl,lst,dct,s)←関数の呼び出し（実行）Enter

関数内の nm: 6←関数内で変更された通りの値が出力されている関数内の flt: 2.23606797749979↓
関数内の c: (2+3j)：関数内の strng: 新しい文字列
関数内の tpl: (7, 8, 9)関数内の lst: [’c’, ’b’, ’a’]関数内の dct: {’apple’: ’ りんご’, ’orange’: ’ みかん’, ’newKey’: ’newValue’}関数内の s: {’y’, ’x’, ’z’}
関数 f が受け取った引数の内容を変更したものを出力していることがわかる．この処理の後で，引数に与えた変数の値を確認する例を次に示す．
例．変数の値の確認（先の例の続き）>>> nm3

Enter>>> flt
5.0

Enter←整数：変化していない←浮動小数点数：変化していない

>>> c
Enter
(1+2j)←複素数：変化していない>>> strngEnter’ 元の文字列’←文字列：変化していない>>> tplEnter(4, 5, 6)←タプル：変化していない>>> lstEnter[’c’, ’b’, ’a’]

←リスト：変化している>>> dctEnter{’apple’:’ りんご’, ’orange’:’ みかん’, ’newKey’:’newValue’}
>>> s
Enter
{’y’, ’x’, ’z’}

←辞書：変化している←セット：変化している

この例から，関数の引数に与えたオブジェクトの内容（値）が関数内での処理によってどのように影響を受けるかがわかる．上の例の結果から表 21 のようなことがわかる．
表 21: 関数内の処理が引数のオブジェクトに与える影響
引数に与えるオブジェクトの型 関数内部での変更が及ぼす影響
整数，浮動小数点数，複素数

関数内部でのみ引数の内容が変更される．

文字列，タプル関数内部でのみ引数の内容が変更される．

リスト，辞書，セット

関数内での変更処理が関数の実行終了後にも影響する．

126

2.7.1.8

引数に関するその他の事柄■ 厳格な位置引数
関数の引数を厳格な形の位置引数として定義するには，関数定義の仮引数の記述の後にスラッシュ ’/’ を置く．
例．厳格な位置引数を持つ関数 fn>>> def fn(a,b,/):←仮引数の終わりに ’/’ を記述する

Enter

...

print(’a =’,a)

Enter

...

print(’b =’,b)

Enter

...

Enter
← Python のプロンプトに戻った>>>

この関数 fn を呼び出す例を次に示す．
例．関数 fn を呼び出す試み（先の例の続き）>>> fn(1,2)
a = 1
b = 2

←正しい呼び出しEnter>>> fn(a=1,b=2)←キーワード引数を与えようとすると…

Enter

Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: fn() got some positional-only arguments passed as keyword arguments:’a, b’

この例からわかるように，キーワード引数を与えるとエラーが発生する．
■ 厳格なキーワード引数
関数の引数を厳格な形のキーワード引数として定義するには，関数定義の仮引数の記述の前にアスタリスク ’*’ を置く．
例．厳格なキーワード引数を持つ関数 fk>>> def fk(*,a):...
...

print(a)Enter←仮引数の前に ’*’ を記述する

Enter

Enter
← Python のプロンプトに戻った>>>

この関数 fk を呼び出す例を次に示す．
例．関数 fk を呼び出す試み（先の例の続き）>>> fk(a=2)
2

Enter
Enter

>>> fk(2)←正しい呼び出し←位置引数を与えようとすると…

Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: fk() takes 0 positional arguments but 1 was given
この例からわかるように，位置引数を与えるとエラーが発生する．また，期待されないキーワード引数を与えてもエラーとなる．
仮引数の ’*’ の替わりには不定個数の仮引数（p.123「2.7.1.3 引数の個数が不定の関数」で解説）を置いた場合も，その後に記述した仮引数は厳格なキーワード引数となる．
例．不定個数の仮引数と厳格なキーワード引数を持つ関数 fk2>>> def fk2(*p,a):

Enter

...

print(p)

Enter

...

print(a)

Enter

...
>>>

Enter
← Python のプロンプトに戻った

127この関数 fk2 を呼び出す例を次に示す．
例．関数 fk2 を呼び出す試み（先の例の続き）>>> fk2(1,2,3,a=4)(1, 2, 3)4Enter← fk2 の呼び出し

例．関数 fk2 の最後の引数の誤った与え方（先の例の続き）>>> fk2(1,2,3,4)
Enter← fk2 の呼び出し（最後の引数が誤り）
Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: fk2() missing 1 required keyword-only argument: ’a’■ 応用
上に説明した ’/’，’*’ を組み合わせることができる．その場合はdef

関数名 ( 厳格な位置引数の並び, /, 通常の引数の並び, *, 厳格なキーワード引数の並び):（関数内部の記述）と記述する．

2.7.2

変数のスコープ（関数定義の内外での変数の扱いの違い）

関数の内部で生成したオブジェクトは基本的にはその関数のローカル変数（局所変数）であり，その関数の実行が終了した後は消滅する．関数の外部で使用されているグローバル変数（大域変数）を関数内部で更新するには，それらを当該関数内でグローバル変数として宣言する必要がある．具体的には関数定義の内部で，

globalグローバル変数の名前と記述する．次に示すプログラム test08-4.py は，大域変数 gv の値が関数呼出しの前後でどのように変化するかを示す例である．
プログラム：test08-4.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# coding : utf -8# 変数のスコープのテスト
gv = ’ 初 期 値 で す ， ’# 大域変数# - - - 関 数 内 部 で 大 域 変 数 を 使 用 す る 例 --def scopetest1 ():global gv# 大域変数であることの宣言
print ( ’ scopetest1 の 内 部 で は : ’ , gv )gv = ’ s c o p e t e s t 1 が 書 き 換 え た も の で す ． ’# - - - 大 域 変 数 と 同 名 の 局 所 変 数 を 使 用 す る 例 --def scopetest2 ():gv = ’ s c o p e t e s t 2 の 局 所 変 数 g v の 値 で す ． ’
print ( gv )# - - - メ イ ン ル ー チ ン --print ( ’ 【 大 域 変 数 g v の 値 】 ’)print ( ’ scopetest1 呼 び 出 し 前 : ’ , gv )scopetest1 ()print ( ’ scopetest1 呼 び 出 し 後 : ’ , gv )scopetest2 ()print ( ’ scopetest2 呼 び 出 し 後 : ’ , gv )このプログラムを実行した例を次に示す．
【大域変数 gv の値】
scopetest1 呼び出し前: 初期値です，
scopetest1 の内部では: 初期値です，
scopetest1 呼び出し後: scopetest1 が書き換えたものです．
scopetest2 の局所変数 gv の値です．
scopetest2 呼び出し後: scopetest1 が書き換えたものです．

128

注意）

Python とそれ以外の言語を比較すると，大域変数とローカル変数の扱いに違いが見られるので特に注意すること．
先に global の宣言により関数内部で大域変数を使用することを述べたが，この宣言をしなくても関数内部で大域変数の参照のみは可能であることも注意すべき点である．安全なコーディングのために推奨される指針を以下にいくつか挙げる．
・ 関数に値を渡すには引数を介して行い，関数内部から外部への値は return を用いて返すことを基本とする．
・ 関数内部で使用する変数の大域／ローカルの区別を強く意識し，可能な限り，関数の内部と外部で異なる変数名を使用する．
・ 関数内部で大域変数を使用する場合は，その関数の定義の冒頭で global 宣言する．
（あまり推奨されない）
・ 関数内部でのみ使用するローカル変数については，その関数の定義の冒頭で値の設定をしておく．
特に設定すべき値がなくとも何らかの初期値を強制的に与えておくのが良い．

2.7.3

関数の再帰的定義

Python では関数を再帰的に定義することができる．例えば，0 以上の整数 n の階乗 n! は次のように再帰的に定義
できる．


n! =

n=0

→ 1

n>0 →

n × (n − 1)!

これを Python の関数 fct として次のように定義することができる．
例．n! を関数 fct として実装する>>> def fct(n): Enter←定義の記述の開始...
if n == 0: Enter...
return 1Enter...
else: Enter...
return n*fct(n-1)
Enter
...
Enter
←定義の記述の終了←対話モードのプロンプトに戻った>>>

この関数を評価する例を次に示す．
例．10! の計算（先の例の続き）>>> fct(10)3628800

Enter← 10! の計算
←計算結果

正しく計算できていることがわかる．

2.7.3.1

再帰的呼び出しの回数の上限

関数を再帰的に呼び出す深さ（再帰的呼び出し回数）には上限があり，それを超えて再帰的呼び出しを実行することはできない．
（次の例参照）
例．1000! の計算：深すぎる再帰的呼び出し（先の例の続き）>>> fct(1000)

Enter← 1000! の計算を試みると…

Traceback (most recent call last):←再帰的呼び出しの上限を超えているので実行できない
File "<stdin>", line 1, in <module>
ことを意味するエラーが発生する．
File "<stdin>", line 5, in fct
File "<stdin>", line 5, in fct
File "<stdin>", line 5, in fct[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded
再帰的呼び出し回数の上限は sys モジュールの getrecursionlimit で調べることができる．

129

例．再帰的呼び出し回数の上限を調べる（先の例の続き）>>> import sys

Enter← sys モジュールの読み込み>>> sys.getrecursionlimit()Enter←再帰的呼び出し回数の上限を調べる
1000←呼び出し回数は 1000 未満に制限されていることがわかる
先の例で試みた 1000! の計算では関数 fct の呼び出し回数が 1000 を超えているためエラーとなった．

sys モジュールの setrecursionlimit を用いると，関数の再帰的呼び出し回数の上限を変更することができる．
例．再帰的呼び出し回数の上限を大きくする（先の例の続き）>>> sys.setrecursionlimit(2048)

Enter←再帰的呼び出し回数を大きく設定 (2,048) する

この後で関数 fct を評価すると次のように正しく実行される．
例．関数 fct を再度実行（先の例の続き）

Enter>>> fct(1000)← 1000! の計算を試みると…

40238726007709377354370243392300398571937486421071463254379991042993851
23986290205920442084869694048004799886101971960586316668729948085589013
23829669944590997424504087073759918823627727188732519779505950995276120：（途中省略）：
00000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000
1000! の計算結果が得られていることがわかる．
補足） 再帰的関数呼び出しの理解を深めるための考察
先に示した関数 fct がその内部で次々と自分自身を呼び出して最終的に n == 0 となるまでの様子を次のようにして眺める．
例．関数の処理の開始時と終了時にメッセージを出力する関数 fct2>>> def fct2(n): Enter...
print(’entered with’,n)
Enter
...
if n==0: r=1
Enter
...
else: r=n*fct2(n-1)
Enter
...
print(’exited with’,r)
Enter
...
return r
Enter
...
Enter
>>>
← Python のプロンプトに戻った
このように定義された関数 fct2 は先の fct と本質的には変わらないが，関数が呼び出された時点と関数の処理が終了する時点でメッセージを出力する形となっている．この fct2 を実行する例を次に示す．
例．関数 fct2 の実行（先の例の続き）>>> fct2(3)Enterentered with 3
entered with 2
entered with 1
entered with 0
exited with 1
exited with 1
exited with 2
exited with 66← fct2(3) の処理開始← fct2(2) の処理開始← fct2(1) の処理開始← fct2(0) の処理開始← fct2(0) の処理終了← fct2(1) の処理終了← fct2(2) の処理終了← fct2(3) の処理終了←最終的な計算結果

関数 fct2 がその内部で次々と関数 fct2 を呼び出している様子がわかる．

130

再帰的呼び出しを応用する際の注意

2.7.3.2関数の再帰的呼び出しを応用する際には，先に示したような呼び出し回数の上限の問題や，計算量や記憶資源に関する問題についても注意する必要がある．これに関しても例を挙げて説明する．

0 以上の整数 n に対するフィボナッチ数 Fn は次のように再帰的に定義することができる．
⎧⎪⎪⎨ n=0 → 0
Fn =n=1 → 1⎪⎪
⎩ n>1 → F
+F
n−1

n−2

これを再帰的な関数呼び出しで実装する次のようなプログラム ﬁbonacci01.py について考える．
プログラム：ﬁbonacci01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# coding : utf -8
import time
# フィボナッチ数を算出する関数
def fib ( n ):if n == 0:
return 0
elif n == 1:
return 1
else :
return fib (n -1)+ fib (n -2)# F0〜F19 ま で の フ ィ ボ ナ ッ チ 数 列
print ( ’ F0 - F19 ’ ,[ fib ( n ) for n in range (20)])# F0〜F35 ま で の フ ィ ボ ナ ッ チ 数 列
t1 = time . time ()print ( ’\ nF0 - F35 ’ ,[ fib ( n ) for n in range (36)])
t2 = time . time ()print ( ’ 計 算 時 間 : ’ , t2 - t1 , ’( sec ) ’)

このプログラムではフィボナッチ数を算出する関数 ﬁb を再帰的関数呼び出しで実装している．13 行目ではこの関数を用いて F0 · · · F19 の数列を作成して表示している．この部分の実行には大きな時間はかからないが，17 行目の

F0 · · · F35 の数列の作成と表示にはかなり時間がかかる．この部分の実行時間を time.time() を用いて122 計測して表示する．
このプログラムを実行した例を次に示す．
実行例．ﬁbonacci01.py を実行した例（Intel Corei7-6670HQ, 2.6GHz, RAM 16GB, Windows10 Pro の環境で実行）
F0-F19 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
F0-F35 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181,
6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269,
2178309, 3524578, 5702887, 9227465]
計算時間: 9.258679389953613 (sec)上のプログラム ﬁbonacci01.py では関数 ﬁb(n) の計算量は 2n に比例する形となり123 計算時間が大きくなる．従って，この形での実装は好ましくないことがわかる．
課題．関数の再帰的呼び出しに依らない形でフィボナッチ数を算出する関数 fib2 を実装せよ．
ヒント．リストなどのデータ構造に F0 · · · Fn を順次生成してゆく方法などがある．

2.7.4

内部関数

関数定義の記述の中に，別の関数定義を記述することができる．これに関してサンプルプログラム innerFunc01.py
を挙げて説明する．

122 後の「4.1.2.4 時間の計測」（p.213）で解説する．
123 O(2n ) の規模

131

プログラム：innerFunc01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# coding : utf -8# - - - 関 数 定 義 --def f1 ( x ):y = 2* x#--- 内 部 関 数 （ こ こ か ら ） - - def f2 ( a ):y = 3* aprint ( ’ f 2 内 部 の y : ’ , y )return y#--- 内 部 関 数 （ こ こ ま で ） - - f2 ( y )print ( ’ f 1 内 部 の y : ’ , y )return y# - - - メ イ ン --print ( ’ ● f1 (5) の 実 行 ’ )f1 (5)# エラーとなる実行
print ( ’ ● f2 (5) の 実 行 を 試 み る と … ’ )f2 (5)

このプログラムでは，関数 f1 の定義の記述の中に，別の関数 f2 が定義されている．この場合，関数 f2 は関数 f1の内部でのみ呼び出す（実行する）ことができる．この例における関数 f2 は，関数 f1 の内部関数である．
このプログラムを実行した例を次に示す．
● f1(5) の実行

f2 内部の y: 30
f1 内部の y: 10● f2(5) の実行を試みると…
Traceback (most recent call last):
File "C:￥Users￥katsu￥innerFunc01.py", line 21, in <module>f2(5)^^NameError: name ’f2’ is not defined. Did you mean: ’f1’?

この例からもわかるように，プログラムのメイン部分から直接関数 f2 を呼び出すことができず，それを試みると上記のようなエラーが発生する．

2.7.4.1

内部関数におけるローカル変数

先の例 innerFunc01.py の関数 f2 の内部では，f2 のためのローカル変数 y が使用されている．この y のスコープはf2 内部に限られ，関数 f1 直下のローカル変数 y とは別のものである．このことが先の実行例から理解できる．
内部関数の内側でその上の関数の変数を使用するには，内部関数側で nonlocal 宣言する．これに関してサンプルプ
ログラム innerFunc02.py を例に挙げて考える．
プログラム：innerFunc02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# coding : utf -8# - - - 関 数 定 義 --def f1 ( x ):y = 2* x#--- 内 部 関 数 （ こ こ か ら ） - - def f2 ( a ):nonlocal y # 上 の 階 層 の 変 数 y の 使 用
y += aprint ( ’ f 2 内 部 の y : ’ , y )#--- 内 部 関 数 （ こ こ ま で ） - - f2 ( 3 )print ( ’ f 1 内 部 の y : ’ , y )return y# - - - メ イ ン --print ( ’ ● f1 (5) の 実 行 ’ )f1 (5)

132

このプログラムの 7 行目で変数 y を nonlocal 宣言している．これにより，関数 f2 内部の変数 y は上位の関数 f1のものと同じものになる．
このプログラムを実行した例を次に示す．
● f1(5) の実行

f2 内部の y:
f1 内部の y:1313

関数 f1，f2 の両方において変数 y は同じものであることがわかる．

2.7.4.2

内部関数はいつ作成されるのか

内部関数は，それを含む上位の関数が評価（実行）された時点で生成される．このことについて次の例で確かめる．
例．内部関数 f2 を持つ関数 f1>>> def f1():
...
...

Enter

←関数 f1 の定義の開始

def f2(): Enter
pass
Enter

←内部関数 f2 の定義の開始

...
...

return f2Enter←関数 f1 は内部関数 f2 の関数オブジェクトを返す
Enter←関数 f1 の定義の終了>>>← Python のプロンプトに戻った

この関数 f1 は，その内部関数 f2 の関数オブジェクトを返すものである．
（次の例）
例．関数 f1 の評価（先の例の続き）>>> f1()Enter←関数 f1 の評価（実行）<function f1.<locals>.f2 at 0x000001D373DC2B88>←内部関数 f2 の関数オブジェクト

次に，f1 の評価を複数回実行した戻り値をリストにして，その要素を確認する．
例．複数の関数 f1 の戻り値を確認（先の例の続き）>>> for r in [f1(),f1(),f1()]: Enter←関数 f1 の評価を 3 回実行した結果を確認...
print( r )Enter←各値を出力...
Enter←繰り返しの記述の終了<function f1.<locals>.f2 at 0x000001D373DC2828><function f1.<locals>.f2 at 0x000001D373DF60D8><function f1.<locals>.f2 at 0x000001D373DF6168>← 1 回目の評価結果← 2 回目の評価結果← 3 回目の評価結果

この実行例から，内部関数 f2 は上位の関数 f1 を評価する毎に異なるものとして定義されていることがわかる．

2.7.4.3

内部関数の応用：クロージャ，エンクロージャ関数はその処理が終了すると，実行の制御を呼び出し元に返し，関数内部のローカル変数などは廃棄されるので，関数の実行の前後で関数内の状態を保存することができない．関数内の状態を保存するにはクロージャとエンクロー
ジャという機構を構成する方法がある．これは内部関数と変数の nonlocal 宣言を用いて実現できる．これに関して例
を示して説明する．
次のように，内部関数 clsr を持つ関数 encl を考える．
例．内部関数 clsr を持つ関数 encl の定義>>> def encl( ):...
x = [ ]
...
...
...
...
...
...
>>>

Enter
Enter

←外側の関数 encl の記述の開始←関数 encl のローカル変数

def clsr( n ): Enter←内部関数 clsr の記述の開始
nonlocal x
Enter←外側の関数 encl の変数を使用する宣言
x.append(n)Enter←それの末尾に clsr が受け取った値を追加する処理
return xEnter←処理結果を返す
return clsrEnter
←上のように定義された内部関数を返す
Enter←外側の関数 encl の記述の終了← Python のプロンプトに戻った133

このように定義された関数 encl は内部関数 clsr を生成して返す．
（次の例）
例．関数 encl を実行して内部関数を取得する（先の例の続き）←内部関数を c1 として受け取るEnter>>> c1 = encl( )この処理により，c1 が関数として実行できる．
（次の例）
例．関数 c1 の実行（先の例の続き）←関数 c1 の実行
←戻り値

Enter

>>> c1(1)[1]関数 c1 の実行結果として [1] が得られているが，これは外側の関数 encl のローカル変数 x に保存されているものである．ここで注目すべき点が，「関数 encl は既に終了しているにも関わらず，そのローカル変数 x の内容が保持されている」ということである．通常の場合は関数の実行が終了すると，そのローカル変数は廃棄されるが，上の例では，関数 encl のローカル変数 x を関数 c1 がまだ参照している（参照カウントが 0 でない）ので encl 終了後も存在
している．
（次の例）
例．引き続き使用可能な変数 x（先の例の続き）>>> c1(2)[1, 2]

Enter←引き続き c1 を実行←変数 x の値が得られている>>> c1(3)[1, 2, 3]Enter←更に c1 を実行←変数 x の値が得られている当然であるが，再度 encl を実行して内部関数を別の関数オブジェクトとして生成すると得られた内部関数は先に作成
した c1 とは別の状態を保持する．
（次の例）
例．再度関数 encl を実行して内部関数を生成する（先の例の続き）

Enter>>> c2 = encl( )←新たな内部関数 c2 を作成>>> c2(100)
[100]

Enter

←それを実行←戻り値（c2 が独自に持つ変数 x の値）>>> c2(101)[100, 101]

Enter

←続けて c2 を実行←戻り値（c2 が独自に持つ変数 x の値）←先の c1 を実行すると…
← c1 が独自に持つ変数 x の値が得られている>>> c1(4)Enter[1, 2, 3, 4]

今回の例で示した「外側の関数」encl は内部関数 clsr の内部状態を保持するエンクロージャとして働く．またこの場合の内部関数 clsr はエンクロージャの状態を使用するクロージャとして働く．
エンクロージャは複数のクロージャを生成する形で実装することもできる．次に示す例は，2 つのクロージャを持つエンクロージャを実装するものである．
例．2 つのクロージャを持つエンクロージャ>>> def enc():
...
x = 0

Enter
Enter

←エンクロージャ←クロージャが共有する変数

...
...
...
...

def inc(): Enter←クロージャ(1)nonlocal xEnterx += 1Enter
return x
Enter

...
...
...
...

def dec(): Enter←クロージャ(2)nonlocal xEnterx -= 1Enter
return x
Enter

...
...
>>>

return (inc,dec)Enter
クロージャを返す
Enter←エンクロージャの記述の終了← Python のプロンプトに戻った

この関数 enc は 2 つのクロージャを返すエンクロージャで，それらクロージャが変数 x を共有する．クロージャ inc
は変数 x の値を 1 増やし，dec は 変数 x の値を 1 減らすものである．

134

例．上記関数を使用する（先の例の続き）>>> f1, f2 = enc()

Enter←クロージャを作成>>> [f1(),f1(),f1()][1, 2, 3]Enter←クロージャ(1) を 3 回実行←実行結果 (1)>>> [f2(),f2(),f2()][2, 1, 0]Enter←クロージャ(2) を 3 回実行←実行結果 (2)2 つのクロージャがエンクロージャのローカル変数 x を共有している様子がわかる．
内部状態を保持する関数の実装と同様のことを実現する（更に高機能な）方法として，後に説明するオブジェクト
指向プログラミングがある．これに関しては「2.8 オブジェクト指向プログラミング」（p.136）で解説する．

2.7.5

定義した関数の削除

def 文で定義した関数は del 文によって削除することができる．
（次の例参照）
例．関数の定義と削除>>> def dbl(x): return 2*x
Enter
...
Enter
←定義の記述の終了←与えた数の 2 倍を算出する関数 dbl の定義>>> dbl(3)6Enter← 3 の 2 倍を算出する←計算結果>>> del dbl

Enter←関数 dbl の削除>>> dbl(3)Enter←先と同じ計算を試みると…
Traceback (most recent call last):←関数 dbl が定義されていないことによるエラー
File "<stdin>", line 1, in <module> ←メッセージが表示される．
NameError: name ’dbl’ is not defined ←（関数 dbl が削除されたことがわかる）
この例は，一旦定義された関数 dbl が del 文によって削除されることを示すものである．削除した後に当該関数を呼び出そうとすると，未定義のため実行できない旨のエラーが発生する．

135

オブジェクト指向プログラミング

2.8

Python におけるオブジェクト指向の考え方も他の言語のそれと概ね同じである．ここでは，オブジェクト指向についての基本的な考え方の説明は割愛して，クラスやメソッドの定義方法やインスタンスの取り扱いといった具体的な事柄について説明する．
クラスの定義2.8.1

クラスの定義は class で開始する．
《 class の記述 》その 1
書き方：

class

クラス名:
（定義の記述）「定義の記述」は class よりも右の位置に同一の深さのインデント（字下げ）を施してスイートとして記述する．
別のクラスをスーパークラス（上位クラス，基底クラスなどと呼ぶこともある）とし，その拡張クラス（サブクラス，派生クラスと呼ぶこともある）としてクラスを定義するには次のように記述する．
《 class の記述 》その 2
書き方：

class

クラス名 ( スーパークラス ):（定義の記述）「スーパークラス」はコンマで区切って複数記述することができる．

Python では多重継承が可能である．拡張クラスがスーパークラスの定義を引き継ぐことを継承という．
2.8.1.1

コンストラクタとファイナライザ

クラスのインスタンスを生成する際のコンストラクタは，クラスの定義内に次のようにinitを記述する．
（init の前後にアンダースコアを 2 つ記述する）《

init の記述 》

書き方：

def

init ( self, 仮引数 ):（定義の記述）

仮引数はコンストラクタを呼び出す際に与えられる実引数を受け取るものである．仮引数は複数記述することができる．また仮引数は省略可能である．
「定義の記述」は def よりも右の位置に同一の深さのインデント（字下げ）を施してスイートとして記述する．self は生成するインスタンス自身を指しており，第 1 仮引数に記述する．
ただし，コンストラクタを呼び出す際には引数に self は記述しない．
スーパークラスを持つクラスのコンストラクタ内ではsuper(). init (引数の列)を記述して，スーパークラスのコンストラクタを呼び出すことができる．コンストラクタはクラスのインスタンスを生成する際に実行される初期化処理である．インスタンスの生成はインスタンス名 = クラス名 ( 引数 )とする．
「引数」にはコンストラクタの

init に記述した self より右の仮引数に与えるものを記述する．

クラスのインスタンスは，使用されなくなると自動的に廃棄される124 ．この際の処理をファイナライザ125 として記述することができる．ファイナライザは

delの名前で定義する．

124 ガベージコレクション（GC：Garbage Collection）
125 デストラクタと呼ばれることもある．

136

《

del の記述 》

書き方：

def

del ( self ):（定義の記述）「定義の記述」は def よりも右の位置に同一の深さのインデント（字下げ）を施してスイートとして記述する．

self は廃棄するインスタンス自身を指しており，第 1 仮引数に記述する．
スーパークラスを持つクラスのファイナライザ内ではsuper(). del ( )を記述して，スーパークラスのファイナライザを呼び出すことができるが，これは推奨されない．拡張クラスがスーパークラスのファイナライザを呼び出すと，ファイナライザの連鎖の動きがプログラマにとって予想しにくいものとなることがあるというのが理由である．
■ インスタンスの生成と廃棄に関するサンプルプログラム
クラスのインスタンスが生成あるいは廃棄される際の動作を示すサンプルプログラム ConstFinal01.py を次に示す．
プログラム：ConstFinal01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# coding : utf -8# - - - ク ラ ス 定 義 --class C :def __init__ ( self ):print ( ’ ク ラ ス C の イ ン ス タ ン ス ’ , self , ’ が 作 成 さ れ ま し た ． ’ )def __del__ ( self ):print ( ’ ク ラ ス C の イ ン ス タ ン ス ’ , self , ’ が 廃 棄 さ れ ま し た ． ’ )# - - - イ ン ス タ ン ス の 作 成 と 廃 棄 --print ( ’ ク ラ ス C の イ ン ス タ ン ス を 生 成 し ま す ． ’)
x = C ()
print ( ’ ク ラ ス C の イ ン ス タ ン ス を 廃 棄 し ま す ． ’)
x = None# - - - 終 了 待 ち --s = input ( ’ E n t e r で 終 了 し ま す > ’)

解説：
このプログラムは，クラス C のインスタンス x を生成し，それを廃棄する例を示すものである．11 行目でクラス

C のインスタンスが生成されて変数 x に与えられているが，この処理の際にコンストラクタが働き，インスタンスが生成されたことを通知するメッセージを表示する．

13 行目では，変数 x に None が代入されており，先に保持されていたクラス C のインスタンスは自動的に廃棄される．この処理の際にファイナライザが働き，インスタンスが廃棄されたことを通知するメッセージを表示する．
このプログラムは最後に Enter を押すことで終了する．このプログラムを実行した例を次に示す．
クラス C のインスタンスを生成します．
クラス C のインスタンス < main .C object at 0x000001CDDEBCBD88> が作成されました．
クラス C のインスタンスを廃棄します．
クラス C のインスタンス < main .C object at 0x000001CDDEBCBD88> が廃棄されました．
Enter で終了します>

次に，スーパークラスを持つクラスのインスタンスを生成，廃棄するサンプルプログラム ConstFinal02.py を示す．
プログラム：ConstFinal02.py
1
2
3
4
5
6
7
8
9

# coding : utf -8# - - - ク ラ ス 定 義 --class B :# 基 底 ク ラ スBdef __init__ ( self ):print ( ’ 基 底 ク ラ ス B の コ ン ス ト ラ ク タ が 呼 び 出 さ れ ま し た ． ’)def __del__ ( self ):print ( ’ 基 底 ク ラ ス B の フ ァ イ ナ ラ イ ザ が 呼 び 出 さ れ ま し た ． ’)class C ( B ):# 拡 張 ク ラ スC

137

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

def __init__ ( self ):super (). __init__ ()print ( ’ 拡 張 ク ラ ス C の イ ン ス タ ン ス ’ , self , ’ が 作 成 さ れ ま し た ． ’ )def __del__ ( self ):super (). __del__ ()print ( ’ 拡 張 ク ラ ス C の イ ン ス タ ン ス ’ , self , ’ が 廃 棄 さ れ ま し た ． ’ )# - - - イ ン ス タ ン ス の 作 成 と 廃 棄 --print ( ’ ク ラ ス C の イ ン ス タ ン ス を 生 成 し ま す ． ’)
x = C ()
print ( ’ ク ラ ス C の イ ン ス タ ン ス を 廃 棄 し ま す ． ’)
x = None# - - - 終 了 待 ち --s = input ( ’ E n t e r で 終 了 し ま す > ’)

解説：
このプログラムでは，クラス B とその拡張クラス C が定義されており，クラス C のインスタンスを生成，廃棄する際に，スーパークラス（基底クラス）である B のコンストラクタ，ファイナライザを呼び出している．
このプログラムを実行した例を次に示す．
クラス C のインスタンスを生成します．
基底クラス B のコンストラクタが呼び出されました．
拡張クラス C のインスタンス < main .C object at 0x0000024FA571AF88> が作成されました．
クラス C のインスタンスを廃棄します．
基底クラス B のファイナライザが呼び出されました．
拡張クラス C のインスタンス < main .C object at 0x0000024FA571AF88> が廃棄されました．
Enter で終了します>

このプログラムは最後に Enter を押すことで終了する．

2.8.1.2

インスタンス変数

クラスのインスタンスとしてのオブジェクトはインスタンス変数126 （属性：attribute，プロパティ:property と呼ぶこともある）を持ち，それらが各種の値を保持する．インスタンス変数へのアクセスは(1) 参照時： インスタンス名. 変数名(2) 設定時： インスタンス名. 変数名 = 値とする．基本的には (2) の形で随時インスタンス変数を追加することができる．また Python では，クラスのコンス
トラクタの中でself. 変数名 = 値と記述してインスタンス変数を初期化するのが一般的である．

2.8.1.3

メソッドの定義

クラスの定義内容としてメソッドの定義を記述する．これは関数の定義の記述とよく似ている．インスタンスメソッ
ド（クラスのインスタンスに対するメソッド）の定義は次のように記述する．
《 メソッドの定義１ 》
書き方：

def

インスタンスに対するメソッド

メソッド名 ( self, 仮引数 ):（定義の記述）

仮引数は複数記述することができる．また仮引数は省略可能である．
「定義の記述」は def よりも右の位置に同一の深さのインデント（字下げ）を施してスイートとして記述する．self は対象となるインスタンス自身を指しており，第 1 仮引数に記述する．当該メソッド呼び出し時には引数には self は記述しない．
インスタンスメソッドとは別にクラスメソッドを定義することができ，それはクラス名. クラスメソッド ( 引数並び )と記述して実行する．クラスメソッドの定義は次のように記述する．
126 Python 以外の言語では「メンバ」と呼ばれることがある．

138

《 メソッドの定義２ 》
書き方：

クラスメソッド@classmethod
def メソッド名 ( cls, 仮引数 ):（定義の記述）

仮引数は複数記述することができる．また仮引数は省略可能である．
「定義の記述」は def よりも右の位置に同一の深さのインデント（字下げ）を施してスイートとして記述する．cls は当該クラスを指しており，第 1 仮引数に記述する．当該メソッド呼び出し時には引数には cls は記述しない．
クラスメソッドを定義するには，def の 1 行前に def と同じインデント位置に「@classmethod」というデコレー
タ127 を記述する．
継承関係のあるクラスの間で，拡張クラス側にスーパークラスのメソッドと同じ名前のメソッドを定義するとオーバーライドされ，拡張クラス側のメソッドが優先される．

2.8.1.4

クラス変数

インスタンスの変数ではなく，クラスそのものに属する変数をクラス変数という．クラス変数は，値の設定などをクラス定義の中で記述することで作成する．
一般的なオブジェクト指向の考え方では，クラス内にメンバと呼ばれるオブジェクトが定義され，そのクラスのイ
ンスタンスが個別に持つ属性の値を保持する．Python ではメンバの存在を明に宣言するのではなく，そのクラスのコ
ンストラクタやメソッドの定義の中で，self や cls の属性として値を与える（オブジェクトを生成する）ことでインスタンス変数やクラス変数を生成する．
【サンプルプログラム】
クラス，クラス変数，インスタンス，インスタンス変数，インスタンスに対するメソッド，クラスメソッドの使用方法を簡単に示すサンプルを test09.py に示す．
プログラム：test09.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# coding : utf -8# クラスに関する試み
class testClass :# - - - ク ラ ス 定 義 --classV = ’ t e s t C l a s s の ク ラ ス 変 数 ’# コンストラクタ
def __init__ ( self , v ):self . instanceV = ’ イ ン ス タ ン ス の 変 数 : ’ + str ( v )# クラスメソッド@classmethod
def cMethod ( cls , a ): # 第 1 仮 引 数 に は 当 該 ク ラ ス が 与 え ら れ る
print ( ’ 引 数 cls : ’ , cls )print ( ’ 引 数 a : ’ ,a )print ( ’ ク ラ ス 変 数 classV : ’ , cls . classV )print ( ’’ )# インスタンスに対するメソッド
def iMethod ( self , a ): # 第 1 仮 引 数 に は 当 該 イ ン ス タ ン ス が 与 え ら れ る
print ( ’ 引 数 self : ’ , self )print ( ’ 引 数 a : ’ ,a )print ( ’ イ ン ス タ ン ス 変 数 instanceV : ’ , self . instanceV )print ( ’ ク ラ ス 変 数 classV : ’ , testClass . classV )print ( ’’ )# - - - イ ン ス タ ン ス の 生 成 --m1 = testClass ( 1 )m2 = testClass ( 2 )# - - - イ ン ス タ ン ス に 対 す る メ ソ ッ ド の 実 行 --m1 . iMethod ( 1 )m2 . iMethod ( 2 )# - - - ク ラ ス メ ソ ッ ド の 実 行 --testClass . cMethod ( 3 )このプログラムを実行した例を次に示す．
127 Java のアノテーションとよく似た働きをする記述であるが，詳しくは「4.21 デコレータ」（p.306）を参照のこと．

139

引数 self: < main .testClass object at 0x0000023D31437F28>
引数 a: 1
インスタンス変数 instanceV: インスタンスの変数:1
クラス変数 classV: testClass のクラス変数
引数 self: < main .testClass object at 0x0000023D31437C50>
引数 a: 2
インスタンス変数 instanceV: インスタンスの変数:2クラス変数 classV: testClass のクラス変数
引数 cls: <class ’ main .testClass’>
引数 a: 3
クラス変数 classV: testClass のクラス変数

インスタンス変数が個別に値を保持している様子がわかる．またクラス変数はクラス自体に属する形で存在する様子がわかる．
もう 1 例，オブジェクト指向のプログラム test09-1.py を次に示す．
プログラム：test09-1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# coding : utf -8# クラス定義
class Person :# クラス変数
population = 7400000000# コンストラクタ
def __init__ ( self , Name , Age , Gender , Country ):self . name = Nameself . age = Ageself . gender = Genderself . country = Country# クラスメソッド@classmethod
def belongTo ( cls ):print ( cls , ’ は 人 類 に 属 し て い ま す ． ’ )return ’ Human ’# メソッドdef getName ( self ):print ( ’ 名 前 は ’ , self . name , ’ で す ． ’ )return self . namedef getAge ( self ):print ( ’ 年 齢 は ’ , self . age , ’ 才 で す ． ’ )return self . age
def getGender ( self ):print ( ’ 性 別 は ’ , self . gender , ’ 性 で す ． ’ )return self . genderdef getCountry ( self ):print ( self . country , ’ か ら 来 ま し た ． ’ )return self . country# メインルーチン
m1 = Person ( ’ 太 郎 ’ ,39 , ’ 男 ’ , ’ 日 本 ’ )m2 = Person ( ’ ア リ ス ’ ,28 , ’ 女 ’ , ’ ア メ リ カ ’ )m1 . getName ()m1 . getAge ()m1 . getGender ()m1 . getCountry ()m2 . getName ()m2 . getAge ()m2 . getGender ()m2 . getCountry ()Person . belongTo ()print ( ’ 現 在 の 人 口 は 約 ’ , Person . population , ’ 人 で す ． ’ )このプログラムを実行すると，次のように表示される．

140

名前は 太郎 です．
年齢は 39 才です．
性別は 男 性です．
日本 から来ました．
名前は アリス です．
年齢は 28 才です．
性別は 女 性です．
アメリカ から来ました．
<class ’ main .Person’> は人類に属しています．
現在の人口は約 7400000000 人です．

参考）Python ではスタティックメソッド（静的メソッド，staticmethod）というものも扱える．これに関しては後の「2.8.8.6 静的メソッド（スタティックメソッド）」（p.155）で解説する．

2.8.2

クラス，インスタンス間での属性の関係「インスタンス. クラス変数」の形式でクラス変数を参照することができる．またインスタンスに対してクラスメ
ソッドを実行することができる．このことについて例を挙げて解説する．まずサンプルとして，次のようなクラス Cを定義する．
例．サンプルのクラス定義>>> class C: Enter...
cv = ’ クラス変数の値’

Enter

...
...
...

@classmethodEnter
def cm(cls): Enter←クラスメソッド
print(’ クラスメソッドからの出力’)
Enter

...
...

def

...
...

def im(self): Enter←インスタンスメソッド
print(’ インスタンスメソッドからの出力’)
Enter

...
>>>

init (self): Enter←コンストラクタ
self.iv = ’ インスタンス変数の値’
Enter

Enter
← Python のプロンプトに戻った

まず当然のことではあるが，インスタンス変数，クラス変数が参照できる．
（次の例）
例．インスタンス変数，クラス変数の参照（先の例の続き）>>> i = C()←インスタンス i の作成

Enter>>> i.iv
Enter←インスタンス変数の確認’ インスタンス変数の値’>>> C.cv
Enter’ クラス変数の値’←クラス変数の確認

次に，インスタンス. クラス変数 の形式でクラス変数を参照できることを示す．
例．クラス変数の参照（先の例の続き）>>> i.cv
Enter’ クラス変数の値’←クラス変数の参照←正しく参照できている

ただしこれは参照のみであり，i.cv に値を代入すると cv は i のインスタンス変数となる．
（次の例）
例．代入の例（先の例の続き）>>> i.cv = ’ インスタンス i の変数 cv の値’Enter←これにより cv はインスタンス変数となる>>> i.cv
Enter
←内容確認
’ インスタンス i の変数 cv の値’>>> C.cv

Enter’ クラス変数の値’←正しい形でクラス変数を確認すると←元のままである

クラス変数は変更されておらず，インスタンス変数への代入の影響を受けていないことがわかる．

141

次にクラスメソッド，インスタンスメソッドについて考察する．当然のことではあるが，クラス名に対してクラスメソッドを，インスタンスに対してインスタンスメソッドを実行することができる．
（次の例）
例．通常の形でのメソッドの実行（先の例の続き）>>> i.im()Enter←インスタンスメソッドの実行
インスタンスメソッドからの出力←結果>>> C.cm()
Enter←クラスメソッドの実行
クラスメソッドからの出力←結果
次に インスタンス. クラスメソッド (引数) の形式でクラスメソッドが実行できることを示す．
例．インスタンスに対してクラスメソッドを実行する（先の例の続き）>>> i.cm()
Enter←クラスメソッドの実行
クラスメソッドからの出力←実行できている
次に，クラス名. インスタンスメソッド (引数) の形式による実行を試みる．
例．クラス名に対してインスタンスメソッドを実行する試み（先の例の続き）>>> C.im()Enter←インスタンスメソッドの実行を試みるが…

Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: C.im() missing 1 required positional argument:’self’

このようにエラーとなるが，クラス名. インスタンスメソッド (インスタンス, 引数…) の形式であれば実行できる．
例．クラス名に対してインスタンスメソッドを実行する試み：その 2（先の例の続き）>>> C.im(i)Enter←第 1 引数にインスタンスを与えるとインスタンスメソッドからの出力←実行できるこのことは，クラス定義の内部でのメソッドの定義の形式がdef

メソッド名 (self, 仮引数…):となっていることからも理解できる．

2.8.3

setattr，getattr による属性へのアクセス

インスタンス変数やクラス変数にアクセスする場合は基本的にドット表記
オブジェクト名. 属性名の形式を用いるが，setattr，getattr といった関数によってもアクセスすることができる．
《setattr 関数》
書き方：

setattr( オブジェクト名, 属性名, 値 )「オブジェクト名」で示されるオブジェクトの「属性名」（文字列）で示される属性に「値」を設定する．
《getattr 関数》
書き方：

getattr( オブジェクト名, 属性名 )「オブジェクト名」で示されるオブジェクトの「属性名」（文字列）で示される属性の値を取得する．
これら関数を使用することでオブジェクトの属性に柔軟な形でアクセスすることができる．例えば，オブジェクト mの属性 x に値 3 を設定する場合，ドット表記を用いて

m.x = 3などと記述することができるが，setattr 関数を用いると

a = ’x’setattr( m, a, 3 )という記述で同様のことが実現できる．後者の記述方法を採用することで，上記の変数 a に別の文字列を与えると，setattr の記述の部分を変更することなく m の別の属性に値を設定することが可能となる．

142

setattr，getattr 関数を用いたサンプルプログラム atracc.py を示す．
プログラム：atracc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# coding : utf -8class MyClass ():# クラス定義
cvar = ’ ク ラ ス 変 数 の 値 ’
def __init__ ( self ):self . x = 1
self . y = 2
self . z = 3
def disp ( self ):print ( ’ cvar = ’ , MyClass . cvar )print ( ’ x = ’ , self .x , ’ , y = ’ , self .y , ’ , z = ’ , self . z )m = MyClass ()# インスタンスの生成

print ( ’ - - - イ ン ス タ ン ス の 初 期 状 態 - - - ’)m . disp ()# リストに格納されたインスタンス変数名と値を用いた状態の変更
alst = [ ’x ’ , ’y ’ , ’z ’]# インスタンス変数の名前のリスト
vlst = [4 ,5 ,6]# 値のリスト
for a , v in zip ( alst , vlst ):setattr (m ,a , v )print ( ’ - - - s e t a t t r で 変 更 し た 後 の 状 態 - - - ’)m . disp ()print ( ’ - - - g e t a t t r に よ る イ ン ス タ ン ス 変 数 の 参 照 - - - ’)for a in alst :print ( ’ 変 数 ’ , a , ’ の 値 : ’ , getattr (m , a ))print ( ’ - - - s e t a t t r で ク ラ ス 変 数 の 値 を 設 定 - - - ’)setattr ( MyClass , ’ cvar ’ , ’ 新 た に 設 定 さ れ た ク ラ ス 変 数 の 値 ’ )m . disp ()解説．

x,y,z の 3 つのインスタンス変数と，クラス変数 cvar を持つ MyClass クラスが定義されている．またこのクラスは，それらの値を表示する disp メソッドを備えている．

12 行目で生成されたインスタンス m の属性を 20〜21 行目で変更しているが，このとき，18〜19 行目で用意した属
性名と値のリストを用いて setattr 関数で値の設定を行っている．また，27〜28 行目では getattr 関数で m の各種属性を取得して出力している．クラス変数に対しても setattr（31 行目）, getattr 関数でアクセスすることができる．
このプログラムの実行例を次に示す．
実行例．
---インスタンスの初期状態--cvar = クラス変数の値
x = 1 , y = 2 , z = 3---setattr で変更した後の状態--cvar = クラス変数の値
x = 4 , y = 5 , z = 6---getattr によるインスタンス変数の参照--変数 x の値: 4
変数 y の値: 5
変数 z の値: 6---setattr でクラス変数の値を設定--cvar = 新たに設定されたクラス変数の値
x = 4 , y = 5 , z = 6

2.8.4

組み込みの演算子や関数との連携定義したクラスのオブジェクトと，Python に元来備わっている演算子や関数，コンストラクタなどとの間の連携方
法について解説する．

143

2.8.4.1

各種クラスのコンストラクタに対するフック■ str コンストラクタに対する独自の処理の実装
多くの場合，値やオブジェクトを文字列に変換する場合

str( 値 )と記述するが，これは str クラスのコンストラクタを介したデータ変換である．この方法で，プログラマが独自に定義したクラスのオブジェクトを文字列に変換すると次のようになる．
例．独自に定義したクラスのインスタンスを str で文字列にする>>> class MyClass:
...
...
...

def
Enter

Enter

←クラス定義init (self): Enter
self.a = 1
Enter←クラス定義の記述の終了>>> x = MyClass()

Enter← MyClass のインスタンス生成>>> str(x)Enter←それを str で文字列に変換すると…
’< main .MyClass object at 0x00000183187A3E88>’←このようになる
インスタンスを str コンストラクタで文字列に変換する際の手順は，当該クラスにstr

メソッドとして定義することができる．このことについて次のサンプルプログラム hook4str01.py で示す．
プログラム：hook4str01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# coding : utf -8# ク ラ ス 定 義1 ： __str__の定義なし
class C1 :def __init__ ( self ):self . a = 1
self . b = 2
self . c = 3
x1 = C1 ()print ( ’ str ( x1 ): ’ , str ( x1 ) )# ク ラ ス 定 義2 ： __str__の定義あり
class C2 :def __init__ ( self ):self . a = 1
self . b = 2
self . c = 3
def __str__ ( self ):r = ’a = ’+ str ( self . a )+ ’ , b = ’+ str ( self . b )+ ’ , c = ’+ str ( self . c )return rx2 = C2 ()print ( ’ str ( x2 ): ’ , str ( x2 ) )このプログラムでは C1，C2 の 2 つのクラスが定義されている．クラス C1 は

str

メソッドが定義されておらず，

C2 にはそれが定義されている．すなわち，クラス C1 のインスタンスを str コンストラクタで文字列に変換すると’<クラス名 object at …>’ のような文字列となり，C2 のインスタンスの場合はstr

メソッドに記述された形で変換される．
このプログラムをスクリプトとして実行した例を次に示す．
実行例．
str(x1):str(x2):

このように< main .C1 object at 0x000002863B5B9CC8>
a=1,b=2,c=3

str

メソッドをクラス内に定義することで，str コンストラクタによる変換処理を所望の形式で実行することができる．
参考）クラス内にrepr

メソッドを同様の方法で実装することで，repr による変換処理を独自の形で実現できる．

144

■ 各種データ型のコンストラクタに対するフック
先に str コンストラクタに対する独自の処理の実装方法について解説したが，その他のデータ型のコンストラクタに対しても独自の処理を実装することができる．表 22 に，各種コンストラクタに対する独自処理を実装するためのメソッドの対応を記す．
表 22: クラス内に設置するメソッドとそれに対応するコンストラクタ（一部）
クラス内に定義
対象となるクラス内に定義
対象となるするメソッド
コンストラクタするメソッド
コンストラクタint (self)int(self)

float (self)

float(self)

complex (self)

complex(self)bool (self)bool(self)str (self)str(self)

bytes (self)

bytes(self)（注）簡単のため，self の後に続く引数の記述は省略している．

2.8.4.2

算術演算子，比較演算子，各種関数に対するフック

各種の算術演算子，比較演算子，関数に対するフックとなるメソッド名を表 23 に示す．
表 23: クラス内に設置するメソッドとそれに対応する演算子（一部）
クラス内に定義
対象となるクラス内に定義
対象となるするメソッド演算子, 関数するメソッド演算子, 関数add (self,x)

self + x

sub (self,x)

self - x

mul (self,x)

self * x

matmul (self,x)

truediv (self,x)

self / x

floordiv (self,x)

self // xmod (self,x)

self % x

divmod (self,x)

divmod(self,x)pow (self,x)

self ** xlshift (self,x)

self << xrshift (self,x)

self >> xand (self,x)

self & x

xor (self,x)

self ^ xor (self,x)

self | xpos (self)+ selfneg (self)- selfinvert (self)~ selfabs (self)abs(self)eq (self,x)

self == xne (self,x)

self != x

lt (self,x)

self < xle (self,x)

self <= x

gt (self,x)

self > xge (self,x)

self >= xround (self,n)round(self,n)trunc (self)

math.trunc(self)floor (self)

math.floor(self)ceil (self)

math.ceil(self)

self @ x(注)(注) NumPy ライブラリの行列積で使用■ インスタンスの比較演算に関する注意
プログラマが独自に定義したクラスのインスタンスに対して == を始めとする比較演算子で比較を行う際には表 23
に示した

eq

などのフックを実装すべきである．これに関して例を示して説明する．

例えば次のように定義されたクラス C のインスタンス c1，c2 を作成した場合を考える．
例．クラスの定義とインスタンスの作成>>> class C: passEnter
←クラス C の定義
...
Enter
←クラス定義の終了>>> c1 = C(); c1.a=1; c1.b=2

Enter←インスタンス c1 の作成と値の設定>>> c2 = C(); c2.a=1; c2.b=2

Enter←インスタンス c2 の作成と値の設定

一見すると c1 と c2 は同値であるかのように見えるが == で比較すると次のようになる．
例．== によるインスタンスの比較（先の例の続き）>>> c1 == c2
False

Enter

← c1 と c2 が同値か判定←同値ではない

これは c1 と c2 が別々のインスタンスであるので当然の結果であるが，一見して間違い易い．従って，異なるインス

145

タンスの同値性を調べるには当該クラスにeqを実装しなければならない．
（次の例参照）

例．クラスに == による比較を実装する

...
...
...

def
Enter

←クラス定義の開始

Enter>>> class C:

eq (self,x): Enter← == による比較演算の実装
return True if self.a == x.a and self.b == x.b else False←クラス定義の終了>>> c1 = C(); c1.a=1; c1.b=2

Enter←インスタンス c1 の作成と値の設定>>> c2 = C(); c2.a=1; c2.b=2

Enter←インスタンス c2 の作成と値の設定←比較の実行
←比較結果

Enter

>>> c1 == c2
True

Enter

== 以外の比較演算に関しても同様の考えに基づいてフックを実装すべきである．
■ 二項演算子の項の順序について
表 23 に示した例． addadd

メソッドを持つ次のようなクラス C1 について考える．

メソッドを持つクラスの定義>>> class C1:

Enter

...
...

def

init (self,s): Enter
self.a = s
Enter

...
...

def

add (self,x): Enter
return str(self.a)+’:’+str(x)

...

Enter

Enter
← Python のプロンプトに戻った>>>

このクラス C1 のオブジェクトにはC1 クラスのオブジェクト + 他のオブジェクトのような演算が可能である．
（次の例）
例．’+’ 演算の試み（先の例の続き）>>> d1 = C1(’ 左側’)>>> d1 + ’ 右側’Enter’ 左側:右側’← C1 クラスのインスタンス d1 を作成

Enter←それに対する ’+’ の演算←結果

しかし次のような演算ではエラーとなる．
例．逆の順で ’+’ を使用する試み（先の例の続き）>>> ’ 更に左側’ + d1

Enter

←逆順での ’+’ の演算はTraceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "C1") to str
これは，str クラス（文字列型）の ’+’ 演算に，クラス C1 のオブジェクトの扱いが定義されていないことによるエラーである．この場合は，クラス C1 にメソッド
例． radd

radd

メソッドを実装した C1 クラス（先の例の続き）>>> class C1:

Enter

...
...

def

init (self,s): Enter
self.a = s
Enter

...
...

def

add (self,x): Enter
return str(self.a)+’:’+str(x)

...
...

def

...
>>>

を実装することで解決できる．
（次の例）

Enter

radd (self,x): Enter←上のメソッドがだめな場合に実行される
return str(x)+’:’+str(self.a)Enter←演算の順序に注意！

Enter← Python のプロンプトに戻った146

これにより，他のクラスのオブジェクト + C1 クラスのオブジェクトが処理できない場合にradd

メソッドが実行される．
（次の例）

例．’+’ 演算の試み：その 2（先の例の続き）>>> d2 = C1(’ 左側’)Enter

← C1 クラスのインスタンス d2 を作成>>> ’ 更に左側’ + d2

Enter

←この演算では’ 更に左側:左側’>>> d2 + ’ 右側’←←もちろんこの演算ではEnter’ 左側:右側’が実行される

radd

←

add

が実行される’+’ 演算以外にも，二項演算におけるクラスの順序が原因でエラーとなる場合がある． add
radd

メソッドに対して

メソッドがあるように，他の演算子に対しても次のようなメソッド群がある．

radd ,
rfloordiv ,rrshift ,rsub ,
rmod ,
rand ,

rmul ,
rdivmod ,rxor ,

rmatmul ,rpow ,
ror

rtruediv ,rlshift ,詳しくは Python の公式インターネットサイトを参照のこと．

2.8.4.3

累算代入演算子に対するフック

表 24 に累算代入演算子に対するフックとなるメソッドを示す．
表 24: クラス内に設置するメソッドとそれに対応する累算代入演算子
クラス内に定義
対象となるクラス内に定義
対象となるするメソッド演算子
するメソッド演算子

iadd (self, x)

self += xisub (self, x)

self -= x

imul (self, x)

self *= x

imatmul (self, x)

self @= x (注)itruediv (self, x)

self /= xifloordiv (self, x)

self //= ximod (self, x)

self %= xipow (self, x)

self **= xilshift (self, x)

self <<= xirshift (self, x)

self >>= xiand (self, x)

self &= xixor (self, x)

self ^= xior (self, x)

self |= x(注) NumPy ライブラリで使用

2.8.5

コンテナのクラスを実装する方法

コンテナの性質を持つクラスを定義する方法について解説する．コンテナはリストや辞書型オブジェクトのように，複数の要素を保持し，スライス ’[ 部分指定の記述 ]’ によって内部にアクセスできるデータ構造であり，次のような機能を持つ．

1) len 関数によって要素の個数を返す．
（ len

メソッドの実装）2) in 演算子によって要素の存在を確かめる．
（ contains
3) スライスで指定した部分を参照する．
（ getitem

メソッドの実装）4) スライスで指定した部分に値を与える．
（ setitem
5) スライスで指定した部分を削除する．
（ delitem
また必要な場合は iter 関数でイテレータにする

128

メソッドの実装）

メソッドの実装）
メソッドの実装）

ことができる．

独自のコンテナを実装する例をプログラム ContainerTest01.py に示す．このプログラムはあまり実用的ではないが，上の 1)〜5) が実装されていることが簡単に理解できる例である．

128 これに関しては後の「2.8.6 イテレータのクラスを実装する方法」（p.148）で解説する．

147

プログラム：ContainerTest01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# coding : utf -8# コンテナクラスの定義
class MyContainer :def __init__ ( self , L ):# コンストラクタ
self . a = L
def __len__ ( self ):# len関数に対するフック
return len ( self . a )def __contains__ ( self , e ):# in演算子に対するフック
return e in self . a
def __getitem__ ( self , s ):# スライス指定の参照のためのフック
return self . a [ s ]def __setitem__ ( self ,s , v ): # ス ラ イ ス 指 定 の 代 入 の た め の フ ッ ク
self . a [ s ] = v
def __delitem__ ( self , s ):# スライス指定の削除のためのフック
del self . a [ s ]# 動作確認
if __name__ == ’ __main__ ’:c = MyContainer ([ ’a ’ , ’b ’ , ’c ’ , ’d ’ , ’e ’])print ( ’ c の 初 期 状 態 : ’ , c .a , ’ 長 さ : ’ , len ( c ))print ( ’" d " in c の 処 理 結 果 : ’ , ’d ’ in c )print ( ’ c [1] の 参 照 : ’ , c [1])print ( ’ c [2:4] の 参 照 : ’ , c [2:4])
c [3] = ’X ’
print ( ’ c [3] = " X " の 処 理 結 果 : ’ , c . a )del c [3:]print ( ’ del c [3:] の 処 理 結 果 : ’ , c . a )このプログラムではコンテナの機能を持った MyContainer クラスが定義されており，インスタンス c が作成されている．この c にスライスを付けてアクセスすると，そのスライスが整数値や slice オブジェクト129 としてや

setitemgetitemといったメソッドの 2 番目の仮引数に渡される．インスタンス c がコンテナとして機能することが次の実行結果からわかる．
実行結果．
c の初期状態: [’a’, ’b’, ’c’, ’d’, ’e’] 長さ: 5"d" in c の処理結果: Truec[1] の参照: bc[2:4] の参照: [’c’, ’d’]c[3] = "X" の処理結果: [’a’, ’b’, ’c’, ’X’, ’e’]del c[3:] の処理結果: [’a’, ’b’, ’c’]

2.8.6

イテレータのクラスを実装する方法

イテレータ130 の機能を持つクラスを定義する方法について解説する．イテレータとは iter 関数によって作成され，next メソッドによって次々と要素を返し，最後の要素以降の要素を要求すると StopIteration 例外が発生するオブジェクトである．このようなオブジェクトのクラスを定義するには，

1) iter 関数が呼ばれた際の処理を実行する iter メソッド2) next メソッドの処理を実行する next メソッドの 2 つのメソッドを実装する．
次に示す例は，0〜10 の整数を次々と返すイテレータオブジェクトのクラス MyIterator を定義するものである．

129 「2.4.5.2 スライスオブジェクト」（p.69）を参照のこと．
130 詳しくは「2.5.1.8 イテレータ」（p.78）を参照のこと．

148

例．イテレータオブジェクトのクラス定義>>> class MyIterator:←クラス定義

Enter

...
...

def

init (self): Enter
self.n = 0
Enter←コンストラクタ

...
...

def

iter (self): Enter
return selfEnter

← iter 関数に対するフック

...
...
...
...
...
...
...
>>>

def

next (self): Enter← next メソッドに対するフック
r = self.nEnter
self.n += 1Enter
if r > 10: Enter←最終要素を越えたことの判定
raise StopIteration()Enter← StopIteration 例外を発生させる
return r
Enter←クラス定義の記述の終了←対話モードのプロンプトに戻ったEnter

iter ， nextの各メソッドを実装している．この例では，iter 関数の呼び出しに対しては特に行うことが無く，自身のオブジェクト（self）をそのまま返している．また，next メソッドの実行によって返す値は「10」までとしているので，それ以降に要素が要求された場合に raise 文131 で StopIteration 例外を発生させている．
実際にこのクラスのオブジェクトを生成してイテレータとして使用する例を次に示す．
例．MyIterator クラスのインスタンスをイテレータとして使用する（先の例の続き）>>> It = MyIterator()←インスタンスの生成

Enter>>> for x in It: Enter←次々と要素を取り出し...
print(x,end=’ ’)Enter←それを出力（改行なし）して... else: print(’’)
Enter←最後に改行する...
Enter← for 文の記述の終了
0 1 2 3 4 5 6 7 8 9 10
2.8.7

←実行結果の出力

カプセル化

オブジェクト指向プログラミングの基本的な考え方においては，インスタンス内部の変数（インスタンス変数，プ
ロパティ，属性）にインスタンス外部から直接的にアクセスするのは良いことではないとされる．オブジェクトはデー
タ構造とメソッドを組にした構造物であり，内部構造には基本的には外部からアクセスできないように隠蔽しておき，アクセサと呼ばれるメソッドを介してのみオブジェクトの内部構造にアクセスすべきであるというのがカプセル化の考え方である．ここではカプセル化に関連する事柄について説明する．

2.8.7.1

変数の隠蔽

アンダースコア 2 つ ‘ ’ で始まるインスタンス変数，クラス変数は隠蔽され，オブジェクトの外部からはアクセスできない132 ．このことを次の例で示す．
例．クラス内の変数の隠蔽>>> class C:
...
...
...
...
...
...
...
>>>

def

Enter

←クラス定義の開始

init (self): Enter←コンストラクタ
self.a = 2
Enter←外部からアクセスできる変数
self. b = 3
Enter←隠蔽される変数

def show(self): Enter←内部状態を表示するメソッド
print(’ a:’,self.a)
print(’ b:’,self. b)←内部からは b にアクセスできる
Enter←クラス定義の終了←対話モードのプロンプトに戻った

131 詳しくは「4.18 例外（エラー）の処理」（p.299）で解説する．
132 実際には，変数名が装飾されて別の名前になっているだけである．

149

この例で定義されたクラス C のインスタンスは(1) 外部からアクセスできる変数 a(2) 隠蔽される変数bを持つ．(1)(2) それぞれの変数にアクセスする例を次に示す．
例．インスタンス変数へのアクセス（先の例の続き）>>> x.a2←クラス C のインスタンス x の作成

Enter>>> x = C()Enter←インスタンス変数 a の参照←参照できた>>> x. bEnter←インスタンス変数 b の参照を試みると…
Traceback (most recent call last):←そのようなものが存在しない旨のエラーとなる
File "<stdin>", line 1, in <module>
AttributeError: ’C’ object has no attribute ’ b’>>> x.show()Enter← show メソッドを介してアクセスすると
a: 2
b: 3
←参照できている
変数b は外部からは直接アクセスできないことがわかる．また，この例では show メソッドがアクセサとしての役割を果たしている．
▲注意▲
変数の前後にアンダースコア 2 つを付けると隠蔽されないので注意すること．

2.8.7.2

アクセサ（ゲッタ，セッタ）

先の例では通常のメソッドをアクセサとしたが，ここでは Python での標準的なアクセサの扱いを示す．
■ ゲッタ（getter）
隠蔽された変数の値を参照するためのアクセサをゲッタ（getter）と呼ぶ．ゲッタの実装方法について例を挙げて説明する．次の例は，人の身長と体重を保持し，BMI を算出するメソッドを持つクラスを定義するものである．
例．クラス Health の定義>>> class Health:Enter←クラス定義の開始

init (self,h,w): Enter
self. height = h
Enter
self. weight = w
Enter←コンストラクタ←隠蔽される変数←隠蔽される変数

...
...
...

def

...
...
...

@propertyEnter←デコレータ：参照用アクセサ（ゲッタ）def height(self): Enter←アクセサ：身長return self. height
Enter

...
...
...

@propertyEnter←デコレータ：参照用アクセサ（ゲッタ）def weight(self): Enter←アクセサ：体重
return self. weight
Enter

...
...
...
>>>

def bmi(self): Enter← BMI を求めるメソッド
return self.weight / self.height**2
Enter
Enter
←クラス定義の終了←対話モードのプロンプトに戻った

このクラスのインスタンスは身長 (m) と体重 (kg) を与えて作成する．height，weight メソッドの宣言の直前にデコレータ「@property」が記述されている．このデコレータにより，height，weight メソッドは引数を付けずに実行することができる．
（次の例）

150

例．Health クラスのインスタンスの扱い（先の例の続き）>>> taro = Health( 1.7, 65 )←クラス Health のインスタンス taro の作成

Enter>>> taro.weight
65

Enter

←引数を付けずに実行←値が得られている>>> taro.height
1.7

Enter

←引数を付けずに実行←値が得られている>>> taro.bmi()
Enter22.49134948096886←メソッド bmi の実行には引数のための括弧の記述が必要← BMI 値

height，weight はあたかもプロパティであるかのように扱える．Python では，インスタンス内部の変数を参照する
ためのアクセサ（ゲッタ）をこのような形で実装するのが標準的である．
■ セッタ（setter）
隠蔽された変数に値を設定するためのアクセサをセッタ（setter）と呼ぶ．基本的には，セッタはゲッタと対にして実装するものであり，ゲッタの定義の後に同名のセッタの実装を記述する．セッタとするメソッドの記述の直前にはデコレータ「@セッタの名前.setter」を記述する．
（プロパティ名としてゲッタと同じ名前とする）
セッタの実装方法について例を挙げて説明する．次の例は，隠蔽された変数

price を持つクラス D を定義する

ものである．
例．ゲッタとセッタを持つクラス D>>> class D:

Enter←クラス定義の開始

init (self): Enter
self. price = 0
Enter←コンストラクタ←隠蔽される変数

...
...

def

...
...
...

@propertyEnter←デコレータ：参照用アクセサ（ゲッタ）def price(self): Enter←ゲッタの定義
return self. price
Enter

...
...
...
...

@price.setterEnter←デコレータ：設定用アクセサ（セッタ）
def price(self,p): Enter←セッタの定義（ゲッタと同じメソッド名）
self. price = p
Enter
return self. price
Enter

...
...
...
>>>

def show(self): Enter←内部状態を表示するメソッド
print(’price:’,self.price)
Enter
Enter
←クラス定義の終了←対話モードのプロンプトに戻った

このクラスのインスタンスに対してセッタ，ゲッタを使用する例を次に示す．
例．クラス D のインスタンスの扱い（先の例の続き）>>> apple = D()←クラス D のインスタンス apple の作成

Enter>>> apple.show()Enter←内部状態の表示
price: 0←値が表示された>>> apple.price = 100

Enter←セッタを介して内部の変数に値を設定>>> apple.show()Enter←内部状態の表示
price: 100←値が表示された>>> apple.priceEnter←ゲッタを介して内部の変数を参照
100←参照された値
セッタのメソッドもゲッタと同一のメソッド名として定義している．セッタも引数を付けない形で実行することができる．結果として，インスタンス apple の隠蔽された変数
照の両方が実行できていることがわかる．

151

price に対して，apple.price という記述で設定と参

2.8.82.8.8.1

オブジェクト指向プログラミングに関するその他の事柄
クラス変数，インスタンス変数の調査

vars 関数を使用すると，クラスが持つクラス変数を調べることができる．同様にインスタンスが持つインスタンス
変数を調べることもできる．
例．サンプル用のクラス定義>>> class C: Enter
...
x = 1
Enter
...
y = 2
Enter
...
def init (self): Enter...
self.a = 3
Enter
...
self.b = 4
Enter
...
Enter
>>>

← Python のプロンプトに戻った

これは，クラス変数 x，y を，インスタンス変数 a，b を持つクラスの定義である．このクラスのインスタンスを作成し，それらを調べる例を次に示す．
例．インスタンス変数を調べる（先の例の続き）>>> x = C()Enter>>> vars(x)Enter{’a’: 3, ’b’: 4}←クラス C のインスタンス x を作成← x のインスタンス変数を調べる←辞書オブジェクトの形で得られる

このように結果が辞書オブジェクトの形で得られる．
例．クラス変数を調べる（先の例の続き）>>> vars(C)Enter←クラス C のクラス変数を調べる

mappingproxy({’ module ’: ’ main ’, ’x’:1, ’y’:2,← x，y が含まれていることがわかる’ init ’: <function C. init at 0x0000020FF4B677E0>,’ dict ’: <attribute ’ dict ’ of ’C’ objects>,’ weakref ’: <attribute ’ weakref ’ of ’C’ objects>, ’ doc ’: None})
クラス変数を vars 関数で調べると，mappingproxy オブジェクトの形で結果が得られる．

2.8.8.2

クラスの継承関係の調査

あるクラスが別のクラスの派生クラス（拡張クラス，サブクラス）となっているかどうか（継承関係）を調べるには issubclass 関数を使用する．以下に例を挙げて説明する．
例．継承関係のあるクラス定義>>> class A: pass
Enter
...
Enter
←定義の終了>>> class B(A): pass
Enter
...
Enter
←定義の終了>>> class C(B): pass
Enter
...
Enter
←定義の終了←クラス A の定義（中身は無し）←クラス A を継承するクラス B の定義（中身は無し）←クラス B を継承するクラス C の定義（中身は無し）

これで A → B → C の継承関係ができた．次にそれを調べる．
例．issubclass による継承関係の調査（先の例の続き）>>> issubclass(C,B)
Enter← C は B のサブクラスか？
True←真：C は B のサブクラスである>>> issubclass(C,A)
Enter← C は A のサブクラスか？
True←真：C は A のサブクラスである>>> issubclass(A,B)
Enter← A は B のサブクラスか？
False←偽：A は B のサブクラスではない
このように，直接の継承関係だけでなく，直系133 である場合も検査可能である．
133 「サブクラスのサブクラスの…」と継承関係の系列上にあるという意味．

152

2.8.8.3

インスタンスのクラスの調査

インスタンスのクラスを調べるには type 関数を用いる．また，あるインスタンスがあるクラスに属しているかど
うかを検査するには isinstance を用いる．
例．クラスの調査（先の例の続き）>>> x = C()Enter>>> type(x)Enter<class ’ main .C’>

←クラス C のインスタンス x を生成← x のクラスを調べる←クラス C のインスタンスである>>> isinstance(x,C)
True

Enter
← x はクラス C のインスタンスか？
←判定結果>>> isinstance(x,A)
True

Enter
← x はクラス A のインスタンスか？
←判定結果

このように isinstance は，属するクラスのスーパークラス（上位のクラス）の場合も True を返す．
インスタンスが属するクラスは，そのインスタンスの例． class

属性からも参照できる．

属性の参照（先の例の続き）>>> x. classEnter<class ’ main .C’>

← x のクラスを調べる← x のクラスは C である

課題．先のクラス定義において C. classについて考察せよ．

2.8.8.4

classの値はどのようなものであるか調べよ．また，それが意味すること属性の調査（プロパティの調査）

dir 関数を使用すると，オブジェクトの属性（プロパティ，メソッド）のリストを取得できる．
例．文字列クラス str の属性をリストとして取得する>>> dir(str)Enter← str クラスの調査[’ add ’, ’ class ’, ’ contains ’, ’ delattr ’, ’ dir ’, ’ doc ’, ’ eq ’, ’ format ’,’ ge ’, ’ getattribute ’, ’ getitem ’, ’ getnewargs ’, ’ gt ’, ’ hash ’, ’ init ’,（途中省略）’rindex’, ’rjust’, ’rpartition’, ’rsplit’, ’rstrip’, ’split’, ’splitlines’, ’startswith’,’strip’, ’swapcase’, ’title’, ’translate’, ’upper’, ’zfill’]

参考）dir 関数はインスタンスの属性を調べることもできる．
オブジェクトが特定の属性（プロパティ）を持つかどうかは hasattr 関数で調べることができる．
例．文字列クラス str の属性の調査>>> hasattr( str, ’split’ )Enter← str クラスが ’split’ を持つかTrue
← ’split’ という名の属性を持つ>>> hasattr( str, ’qwert’ )Enter← str クラスが ’qwert’ を持つか
False
← ’qwert’ という名の属性を持たない
2.8.8.5

多重継承におけるメソッドの優先順位

あるクラスが他の複数のクラスを基底クラスとして多重継承する場合，それら基底クラスに同じ名前のインスタン
スメソッドがある場合，どの基底クラスのインスタンスメソッドが実行されるかが問題となる．例えば次のようなクラス定義について考える．

153

例．クラス A,B を多重継承するクラス CEnter>>> class A:
...
...
...
...
...

def

init (self): Enter
self.a = ’ クラス A の属性 a の値’

def imethod(self): Enter
print(’ クラス A のインスタンスメソッドによる出力’)
Enter

...
...
...

def

init (self): Enter
self.b = ’ クラス B の属性 b の値’Enter

def imethod(self): Enter
print(’ クラス B のインスタンスメソッドによる出力’)Enter>>> class C(A,B):
...
...
...
>>>

def

Enter

Enter

>>> class B:
...
...

Enter

Enter

Enter

init (self): Enter
self.c = ’ クラス C の属性 c の値’

Enter

Enter
← Python のプロンプトに戻った

このような継承関係では，クラス A，B が同じ名前のインスタンスメソッド imethod を持っており，クラス C のイ
ンスタンスに対して imethod を実行すると，A，B どちらのものが実行されるかが問題となる．実際にクラス C のインスタンスを作成して実行する例を次に示す．
例．クラス C のインスタンスに対して imethod を実行する（先の例の続き）>>> m = C()Enter←インスタンス m を作成して>>> m.imethod()Enter←インスタンスメソッド imethod を実行すると
クラス A のインスタンスメソッドによる出力←クラス A のものが実行される
これは，クラス C を定義する際に class C(A,B): としたことによりクラス A が優先されたことによる．多重継承
で定義されたクラスにおいてメソッドの優先順を調べるには，当該クラスに対して mro メソッドを使用すると良い．
例．クラス間の優先順位を調べる（先の例の続き）>>> C.mro()
Enter←クラス C が継承しているクラスの間の優先順位を調べる[<class ’ main .C’>, <class ’ main .A’>, <class ’ main .B’>, <class ’object’>]
クラスの参照順が C → A → B → (その他) となっていることがわかる．
上のような状況で，インスタンス m にクラス B のインスタンスメソッド imethod を強制的に実行させるには次のような方法がある．
例．クラス B のインスタンスメソッドを実行する（先の例の続き）>>> B.imethod(m)Enter←クラス B 配下の imethod であることを明確に記述する
クラス B のインスタンスメソッドによる出力154

2.8.8.6

静的メソッド（スタティックメソッド）

クラス内に定義されたスタティックメソッドは通常の関数のように振る舞う．これに関して例を挙げて説明する．
例．静的メソッドを持つクラスの定義>>> class C:

Enter

...
...
...
...

@staticmethodEnter←静的メソッドの宣言
def smethod(x): Enter←仮引数に self や cls が無い
print(’x :’,x)Enter
return 2*x
Enter

...
...

def

...
...
...
...
>>>

init (self): Enter
self.a = 5
Enter

def imethod(self,x): Enter
print(’self :’,self,’x :’,x)
return x*self.a
Enter
Enter
← Python のプロンプトに戻ったEnter

このクラス C のインスタンスメソッドと静的メソッドの動作を比較する．
例．インスタンスメソッドの動作と静的メソッドの動作（先の例の続き）>>> m = C()Enter←クラス C のインスタンス m を作成>>> m.imethod(3)Enter← m に対してインスタンスメソッドを実行
self : < main .C object at 0x000002C9E92BF250> x : 3←引数 self が自身を受け取っている
15←戻り値>>> C.smethod(3)Enter←静的メソッドを実行
x : 3← self や cls などを受け取らずに実行している
6←戻り値
この例の smethod はインスタンス m に対しても同様に実行することができる．
このように静的メソッドは，self や cls といった仮引数を取らずに実装できるので，通常の関数のように扱うことができる．
課題．静的メソッドの用途について考察せよ．

155

データ構造に則したプログラミング

2.9

Python にはデータ列の要素に対して一斉に処理を適用する機能が提供されている．例えば 2 倍した値を返す関数
dbl が次にように定義されているとする．
例．2 倍する関数 dbl の定義

def dbl(n):return 2*n

通常は下記のように，これを 1 つの値に対して実行する．
例．通常の形式での関数の実行（先の例の続き）

Enter>>> dbl(3)6←関数の評価←評価結果

この評価方法とは別に，map 関数を使用する方法がある．map 関数を使うと，データ列の全ての要素に対して評価を適用することができる．このことを例を挙げて説明する．
例．map 関数による一斉評価（第一段階）>>> res = map( dbl, [1,2,3] )（先の例の続き）

Enter

これにより，関数の評価をリストの全要素に対して一斉に行うことができる．ただしこの段階では「関数の一斉評価のための式」が res に生成されただけであり，res の内容を確認すると次のようになっている．
例．map 関数の実行結果（先の例の続き）>>> res
Enter←内容の確認<map object at 0x000002BE46760DD8> ← map オブジェクトが格納されている
この res をリストとして評価すると，最終的な処理結果が得られる．
例．リストとしての処理結果（先の例の続き）>>> list( res )Enter[2, 4, 6]←処理結果←リストとして処理結果を求める>>> list( res )Enter[]←空になっている←再度実行すると

この例からもわかるように，変数 res に得られたものは map オブジェクトであり，これはイテレータの一種であるため，参照した後は消滅する．
ちなみに，次のようにして一回の処理で結果を得ることもできる．
例．リストとしての処理結果 (2)（先の例の続き）>>> list( map( dbl, [1,2,3] ) )[2, 4, 6]
←処理結果
2.9.1

Enter

←同様の処理を一度で行う

map 関数《 map 関数 》
書き方 1：

map(関数名, 対象のデータ構造)

書き方 2：

map(関数名, 対象のデータ構造 1，対象のデータ構造 2，…)

「対象のデータ構造」の全ての要素に対して「関数名」で表される関数の評価を実行するための map オブジェ
クトを返す．1 つの引数を取る関数の場合は「書き方 1」に，複数の引数を取る関数の場合は「書き方 2」に従う
こと．
得られた map オブジェクトは for などの繰り返し処理のためのイテレータとなる．また map オブジェクトを具体的なデータ構造に変換（list 関数でリストに変換するなど）することで実際の値が得られる．
リストの全要素に対して同じ関数を適用する処理を実現する場合，for 文を用いた繰り返し処理の形で記述することもできるが，map 関数を用いた方が記述が簡潔になるだけでなく，実行にかかる時間も概ね短くなる．

156

【サンプルプログラム】

map 関数と for 文の実行時間の比較

map 関数と for 文の実行時間を比較するためのサンプルプログラム map01.py を次に示す．これは，奇数／偶数を判定する関数 EvenOrOdd を，乱数を要素として持つリストに対して一斉適用する例である．
プログラム：map01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# coding : utf -8# 必要なモジュールの読込み
import timefrom random import randrange# 時間計測用# 乱数発生用##########################################################
偶数／奇数を判定する関数の定義##########################################################
def EvenOrOdd ( n ):if n % 2 == 0:
return ’ 偶 ’else :
return ’ 奇 ’##########################################################
試 み(1)########################################################### 乱 数 リ ス ト の 生 成(1) ：短いもの
lst = list ( map ( randrange , [100]*10 ) )# 偶数／奇数の識別結果
lst2 = list ( map ( EvenOrOdd , lst ))print ( ’10 個 の 乱 数 の 奇 数 ／ 偶 数 の 判 定 ’ )print ( lst )print ( lst2 , ’\n ’)##########################################################
試 み(2)########################################################### 乱 数 リ ス ト の 生 成 ( 2 ) ： 1 ,000 ,000 個
print ( ’1 ,000 ,000 個 の 乱 数 の 奇 数 ／ 偶 数 の 判 定 ’ )t1 = time . time ()lst = list ( map ( randrange , [100]*1000000 ) )t = time . time () - t1
print ( ’ 乱 数 生 成 に 要 し た 時 間 : ’ , t , ’ 秒 ’ )# 速 度 検 査(1) ： f o r に よ る 処 理
lst2 = []t1 = time . time ()for i in range (1000000):
lst2 . append ( EvenOrOdd ( lst [ i ]) )t = time . time () - t1
print ( ’ f o r に よ る 処 理 : ’ ,t , ’ 秒 ’ )# 速 度 検 査(2) ： m a p に よ る 処 理
t1 = time . time ()lst2 = list ( map ( EvenOrOdd , lst ))t = time . time () - t1
print ( ’ m a p に よ る 処 理 : ’ ,t , ’ 秒 ’ )# mapによる処理# 判定結果の確認# print ( lst2 )このプログラムを実行した例を次に示す．
10 個の乱数の奇数／偶数の判定[92, 3, 7, 26, 11, 22, 76, 61, 79, 10][’ 偶’, ’ 奇’, ’ 奇’, ’ 偶’, ’ 奇’, ’ 偶’, ’ 偶’, ’ 奇’, ’ 奇’, ’ 偶’]
1,000,000 個の乱数の奇数／偶数の判定
乱数生成に要した時間: 0.9250545501708984 秒
for による処理: 0.32311391830444336 秒
map による処理: 0.15199923515319824 秒

map 関数による処理の方が for 文による処理よりも実行時間が小さいことがわかる．
157

2.9.1.1

複数の引数を取る関数の map

2 つの引数の和を求める次のような関数 wa を考える．
例．2 つの引数の和を求める関数 wa>>> def wa(a,b):
...
Enter

←関数 wa の定義

return a+bEnter←定義の終了>>> wa(2,3)
Enter
5
←結果

←関数 wa の評価

この関数の map による実行例を示す．
例．関数 wa を map 関数で実行する（先の例の続き）>>> list( map(wa,[1,2],[3,4]) )[4, 6]←結果

Enter← map 関数に複数の引数（それぞれリスト）を与える

長さの異なるデータ列を map の引数に与えた場合は，長さが最も短いデータ列を基準に map の処理が行われる．
（次の例参照）
例．長さの異なるデータ列に対する map（先の例の続き）>>> list( map( wa, [2], [3,4] ) )
[5]
←結果

Enter

← map 関数に長さの異なるデータ列を与える

短い方のリスト ‘[2]’ の長さが基準になっていることがわかる．

2.9.1.2

map 関数に zip オブジェクトを与える方法

map 関数の処理対象のデータ列として zip オブジェクト134 を与えることができる．以下に例を挙げて解説する．
例．複数の引数を取る関数 csv を用いた map（その 1）>>> def csv( *arg ): Enter...
return ’,’.join(arg)
...

Enter

←与えた引数（文字列）を ’,’ で連結する関数
Enter ←連結処理←関数定義の記述の終了>>> q1 = [’a’,’b’,’c’,’d’]Enter← 1 番目のデータ列>>> q2 = [’1’,’2’,’3’,’4’]Enter← 2 番目のデータ列>>> q3 = [’ イ’,’ ロ’,’ ハ’]

Enter← 3 番目のデータ列（短い）>>> list( map(csv,q1,q2,q3) )Enter ← 3 つのデータ列に対する map[’a,1, イ’, ’b,2, ロ’, ’c,3, ハ’]←処理結果
これと同等の処理を zip オブジェクトを用いて実現する．
（次の例）
例．複数の引数を取る関数 csv を用いた map（その 2：先の続き）>>> z = zip(q1,q2,q3)

Enter← zip オブジェクトの生成>>> list( map(csv,*zip(*z)) )Enter← zip オブジェクトに対する map 処理[’a,1, イ’, ’b,2, ロ’, ’c,3, ハ’]←処理結果
map 関数にデータ列として zip オブジェクトを与えているが，その際 *zip(*z) としていることが重要である．これに関しては「2.5.1.10 zip 関数と zip オブジェクト」（p.80）でも取り上げているが，次の試みに関しても考察されたい．
例．1 つの試み（先の続き）>>> z = zip(q1,q2,q3)

Enter>>> list( map(csv,*z) )Enter[’a,b,c’, ’1,2,3’, ’ イ, ロ, ハ’]← zip オブジェクトの生成← zip オブジェクトに対する map 処理←処理結果

map 関数にデータ列として *z を与えるとこのような処理結果となる．

134 「2.5.1.10 zip 関数と zip オブジェクト」（p.80）を参照のこと．

158

2.9.2

lambda と関数定義

引数として与えられた値（定義域）から別の値（値域）を算出して返すものを関数として扱うが，Python のプロ
グラムの記述の中では関数名のみを記述する場合もある．map 関数の中に記述する関数名もその 1 例であるが，この「関数名のみ」の表記は実体としては関数オブジェクトもしくは lambda である．
■ 実体としての関数

map 関数の解説のところで示したサンプルプログラムで扱った偶数／奇数を判定する関数 EvenOrOdd について考える．この関数の定義を次のようにして Python インタプリタに与える．
例．Python インタプリタに関数定義を与える>>> def EvenOrOdd(n):
...
...
...
...
...

←定義の記述の開始Enter

if n % 2 == 0: Enter
return ’ 偶’Enter
else: Enter
return ’ 奇’
Enter
Enter
←定義の記述の終了（改行のみ）>>>← Python コマンドラインに戻る

この関数の評価を実行する際，次のようにして引数を括弧付きで与える．
例．上で定義した関数の評価（先の例の続き）←評価の実行>>> EvenOrOdd(13)
Enter
’ 奇’
←評価結果

次に，’EvenOrOdd’ という記号そのものには何が割当てられているのかを確認する．
例．関数名のみを参照する（先の例の続き）>>> print( EvenOrOdd )Enter←内容の確認<function EvenOrOdd at 0x000001D863C63E18>←関数オブジェクト
このように，記号 ’EvenOrOdd’ には関数オブジェクトが割当てられていることがわかる．このオブジェクトは，デー
タとして変数に割り当てることができるものであり，このような扱いができるオブジェクトは第一級オブジェクト135（ﬁrst-class object）と呼ばれる．この例で扱っている関数オブジェクトも，他の変数に割り当てて使用すること（評価，実行）が可能である．
（次の例を参照のこと）
例．変数への関数オブジェクトの割当てと実行（先の例の続き）>>> f = EvenOrOdd>>> f(13)’ 奇’←別の変数 f に関数オブジェクトを割当てる

Enter

Enter
←関数 f を実行
←値が得られている■ lambda 式
関数の定義を lambda 136 式として記述して取り扱うことができる．先に例示した「2 倍の値を返す関数」dbl を

lambda 式で実装する例を示す．
例．値を 2 倍する関数 dbl2 の実装例>>> dbl2 = lambda n:2*nEnter← lambda 式による実装>>> dbl2(3)
Enter
←実行
6
←結果が得られている
この例の dbl2 の内容を確認すると次のようになる．

135 変数に値として割り当てることができ，プログラムの実行時にデータとして生成と処理ができるオブジェクトを指す．

関数定義を第一級オブジェクトとして扱える言語処理系は少なく，一部のリスト処理系（LISP の各種実装）がそれを可能にしている．
136 数学の関数表記 f (x) の f を実体として扱い，対象となるデータにそれを適用して値を算出するラムダ計算が由来である．

ラムダ計算に関しては提唱者 A. チャーチの著書 “The Calculi of Lambda Conversion”, Princeton University Press, 1941
を参照のこと．

159

例．上記作成の dbl2 を参照する（先の例の続き）>>> dbl2Enter← dbl2 の内容確認<function <lambda> at 0x00000210D6EB3E18> ←結果
このように関数オブジェクト（lambda 式）が格納されていることがわかる．
《 lambda 式の記述 》
書き方 1：
書き方 2：

lambda 仮引数 : 戻り値の式
lambda 仮引数並び : 戻り値の式「仮引数並び」はコンマ ’,’ で区切る．

複数の仮引数を取る関数 wa の記述例を次に示す．
例． 2 つの引数の和を求める関数 wa の実装>>> wa = lambda a,b :← lambda 式を wa に割り当てる

Enter

a+b

←実行

>>> wa(2,3)
Enter
5
←結果

また，次の例のように lambda 式を記号に割当てずに適用することもできる．
例．lambda 式を直接引数に適用する．

>>> (lambda a,b :5←結果a+b)(2,3)■ lambda と関数定義の違い：← lambda 式の直接適用

Enter

属性

name

def 文による関数定義と lambda 式の記述は本質的に同じものであるように見えるが，それらの若干の相違点について考察する．そのために同様の機能を持つ関数を 2 種類用意する．
例．同じ機能を def 文と lambda でそれぞれ実装する>>> def f1(x,y):
...
Enter

return x+y>>> f2 = lambda x,y:x+y← def 文による定義

Enter← lambda 式による定義

Enter

この例で定義された f1，f2 共に加算を実行するものである．
例．上記 f1，f2 の実行（先の例の続き）>>> f1(2,3)
5

Enter

← f1 の実行←計算結果>>> f2(2,3)
5

Enter

← f1 の実行←計算結果

f1，f2 共に同様の処理を行っていることがわかる．次に f1，f2 の例． name

属性が異なることを示す．

属性を調べる（先の例の続き）>>> f1. name
’f1’

Enter

← f1 の name
←関数名 f1

属性は>>> f2. name’<lambda>’Enter← f2 の

属性は

2.9.3

name

name

ﬁlter

データ列の要素の内，指定した条件を満たす要素のみを取り出す関数に ﬁlter がある．

160

《 ﬁlter 関数 》
書き方：

ﬁlter( 条件判定用の関数名, 対象のデータ構造 )「対象のデータ構造」の要素の内，「条件判定用の関数」の評価結果が真（True）となるものを抽出して返す．
戻り値は ﬁlter オブジェクトであり，これを具体的なデータ構造に変換（list 関数でリストに変換するなど）することで実際のデータが得られる．
第一引数には関数名の他，lambda 式も指定できる．
整数を要素として持つリストの中から偶数の要素のみを取り出す処理を例として示す．
例．偶数の取り出し>>> from random import randrange←乱数発生用のライブラリの読込み

Enter←乱数リスト（17 要素）の生成Enter>>> lst = list( map( randrange, [100]*17 ) )>>> lstEnter←内容確認[15, 74, 64, 81, 58, 18, 70, 88, 45, 44, 3, 81, 36, 98, 57, 18, 27]>>> lst2 = list( filter( lambda n:n%2==0, lst ) )>>> lst2
Enter
←内容確認
[74, 64, 58, 18, 70, 88, 44, 36, 98, 18]
2.9.4

Enter

←乱数リスト←偶数のみの抽出←偶数のみのリスト

3 項演算子としての if〜else…

条件分岐のための「if〜else…」文に関しては「2.5.4 条件分岐」（p.84）のところで解説したが，3 項演算子としての「if〜else…」の記述も可能である．
《 if〜else… 演算子 》
書き方：

値 1 if 条件式 else 値 2

これは式であり，結果として値を返す．
「条件式」が真の場合は「値 1」を，偽の場合は「値 2」を返す．
この式は，条件による値の評価の選択を lambda 式などの中で簡潔に記述するのに役立つ．
例．偶数／奇数を判定する lambda 式>>> evod = lambda n :’ 偶’ if n % 2 == 0 else ’ 奇’>>> evod( 2 )
Enter
’ 偶’
←処理結果

← 2 は偶数か奇数か？

>>> evod( 3 )
Enter
’ 奇’
←処理結果

← 3 は偶数か奇数か？

2.9.5

Enter

← 1 行で条件分岐を記述

all, any による一括判定

リストやタプルといったデータ構造に格納された真理値を一括で評価するには all 関数や any 関数を用いる．
《all 関数》
書き方：

all( 真理値を要素とするデータ構造 )「真理値を要素とするデータ構造」の全ての要素が True の場合に True を，それ以外の場合は False を返す．
例．all 関数>>> p = [True,True,True,True]>>> all( p )
True

Enter

>>> p = [True,True,False,True]>>> all( p )
False

Enter

Enter

←全て True のリストに対する← all 関数の結果は← True（真）となるEnter← 1 つでも False があると← all 関数の結果は← False（偽）となる161

《any 関数》
書き方：

any( 真理値を要素とするデータ構造 )「真理値を要素とするデータ構造」に 1 つでも True の要素が含まれる場合に True を，それ以外の場合は False
を返す．
例．any 関数>>> p = [False,False,True,False]>>> any( p )
True

Enter

← 1 つでも True があると

← any 関数の結果は← True（真）となるEnter>>> p = [False,False,False,False]>>> any( p )
False

Enter

Enter

←全て False のリストに対する← any 関数の結果は← False（偽）となる

これらの関数が対象とするデータは真理値であるが，map 関数と組み合わせると，真理値以外の多量のデータに対して指定した条件を満たすかどうかを一括して検査することが可能となる．これに関してサンプルプログラム allany01.py
を例に挙げて説明する．
プログラム：allany01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# coding : utf -8# all , a n y の サ ン プ ル
import random# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##テストデータの作成## - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## 全 て の 要 素 が50 未 満 の 乱 数 デ ー タ の リ ス ト
d1 = [ random . randrange (0 ,50) for x in range (7) ]# 1 つ だ け50 よ り 大 き い 要 素 を 持 つ リ ス ト
d2 = [ random . randrange (0 ,50) for x in range (7) ]d2 [5] = 99
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -##テ ス ト 関 数 （50 未 満 か ど う か の チ ェ ッ ク ）## - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## テ ス ト 関 数1 （50 未 満 か ど う か の チ ェ ッ ク ）def chkU50 ( n ):return n < 50
# テ ス ト 関 数2 （50 以 上 か ど う か の チ ェ ッ ク ）def chkG50 ( n ):return n >= 50# 汎用テスト関数
def forAll ( f , d ):return all ( map (f , d ) )def ifAny ( f , d ):return any ( map (f , d ) )# dの全てがfか？

# dにfなるものがあるか？

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#
#
検査の実行
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#print ( ’ デ ー タ 1: ’ , d1 )print ( ’ 全 て 5 0 未 満 か ?: ’ , forAll ( chkU50 , d1 ) )print ( ’50 以 上 が あ る か ?: ’ , ifAny ( chkG50 , d1 ) , ’\n ’ )print ( ’ デ ー タ 2: ’ , d2 )print ( ’ 全 て 5 0 未 満 か ?: ’ , forAll ( chkU50 , d2 ) )print ( ’50 以 上 が あ る か ?: ’ , ifAny ( chkG50 , d2 ) )このプログラムは，乱数のリストに対して条件判定を一括して行うサンプルである．8 行目では「50 未満の整数」の乱数を要素として持つデータ d1 を，10〜11 行目では 1 つだけ 50 を超える整数を持つ乱数データ d2 を生成している．

17〜18 行目では「50 未満」を判定する関数 chkU50 を，21〜22 行目では「50 以上」を判定する関数 chkG50 を定義している．

162

25〜26 行目では，指定した条件判定関数が与えられた「全てのデータで真となる」ことを判定する関数 forAll を，
28〜29 行目では，指定した条件判定関数が与えられたデータに対して「少なくとも 1 つ真となる」ことを判定する関
数 ifAny を定義している．

allany01.py を実行した例を次に示す．
データ 1: [24, 32, 14, 26, 2, 33, 15]
全て 50 未満か?: True
50 以上があるか?: False
データ 2: [28, 40, 15, 25, 14, 99, 4]
全て 50 未満か?: False
50 以上があるか?: True

このサンプルで定義している forAll，ifAny 関数のような実装により，多量のデータに対する判定を行うための汎用の関数が定義できる．
高階関数モジュール：functools

2.9.6

本書では map，ﬁlter といった関数を取り上げているが，functools モジュールは「関数をオブジェクトに対して実行する際の高度な機能」を提供している．このモジュールは Python 処理系に標準的に添付されており，

import functools
として読み込んで使用する．ここでは functools の使用例を 1 つ紹介する．

2.9.6.1

reduce（次の例参照）
reduce は，2 つの引数をとる関数（あるいは lambda）をデータ列の要素に順番に累積的に適用する．
例．2 つの数の和を求める関数を用いて，データ列の合計を求める>>> import functoolsEnter←モジュールの読込み>>> def wa(a,b): return a+b
Enter
...
Enter ←定義の記述の終了← 2 つの引数の和を求める関数の定義>>> d = [1,2,3,4,5,6,7,8,9,10]

Enter← 1〜10 のデータを用意>>> functools.reduce( wa, d )
55
←処理結果

Enter

←データに対して reduce で処理を実行

この例で定義されている関数 wa(a,b) は，a+b を求めるものであるが，reduce を使用すると [a,b,c,d,e,f,g] というデータ列に対して，(((((a+b)+c)+d)+e)+f)+gという処理を施す．

163

2.10

代入式

イコール「=」による変数への値の割り当ては文であり，それ自体は値を返さない．Python 3.8 からは，「:=」を用いて変数に値を割り当てる代入式137 が導入された．代入式は代入した値を返す．
例．「=」と「:=」の違い>>> x = (a=3)

Enter←通常の代入文「a=3」を x に代入しようとすると…

File "<stdin>", line 1
x = (a=3)^^^
SyntaxError: invalid syntax.
>>> x = (a:=3)Enter←文法エラー（SyntaxError）となるMaybe you meant ’==’ or ’:=’ instead of ’=’?

←代入式「a:=3」は x に代入することができる>>> xEnter ←内容確認
3 ←結果表示
代入式を用いると，条件式の記述の中に代入処理を直接記述するといったことが可能となり，プログラムの可読性を高める場合がある．
（次の例参照）
例．標準入力（キーボード）から数値を入力するサイクル（0 で終了）>>> while (v:=int(input(’0 で終了>’))) != 0:...
print(’ 入力値:’,v)
Enter
...
Enter
←繰り返し文の終了

Enter←条件判定の中に代入式を用いる

0 で終了>1
Enter←値の入力（0 でない）
入力値: 1←出力
0 で終了>2
Enter←値の入力（0 でない）
入力値: 2←出力
0 で終了>0Enter←値の入力（0 で終了）>>>
←対話モードのプロンプトに戻った
代入式を使わずにこれと同じ処理を記述すると次のようになる．
例．上と同等の処理>>> while True: Enter←繰り返しの記述の開始...
v=int(input(’0 で終了>’))Enter←通常の代入文で値を読み取る...
if v != 0: Enter
←値の判定
...
print(’ 入力値:’,v)
Enter
...
else: Enter
...
break
Enter
...
Enter
←繰り返し文の終了
0 で終了>1
Enter←値の入力（0 でない）
入力値: 1←出力
0 で終了>2
Enter←値の入力（0 でない）
入力値: 2←出力
0 で終了>0Enter←値の入力（0 で終了）>>>
←対話モードのプロンプトに戻った

137 PEP572 – Assignment Expressions

164

2.11

構造的パターンマッチング

Python 3.10 の版から高度な分岐処理である構造的パターンマッチングの構文（match〜case 構文）138 が導入された．本書では，これに関して基本的な事柄について解説する．
《構造的パターンマッチング》
書き方：

match 値:
case パターンの記述 1:（対象の処理 1）

case パターンの記述 2:（対象の処理 2）：
検査対象の「値」を「パターンの記述」に順番に照らし合わせ，マッチングが成功した部分の「対象の処理」（スイートの形式）を実行する．
（C 言語の switch〜case 構文のようなフォールスルーは起こらない）
これは一見すると C 言語や Java 言語の switch〜case の構文に似ているが，それ以上の機能を実現する．この構文の最も単純な使用例をサンプルプログラム stpmatch01.py に示す．
プログラム：stpmatch01.py
1
2
3
4
5
6
7
8
9
10
11
12

# coding : utf -8
v = 1# これを様々な値に変更して試す
match v :case 1:
print ( ’ One ’)case 2:
print ( ’ Two ’)case 3:print ( ’ Three ’)case _ :print ( ’ Other ’)

これは，変数 v が保持する値を match〜case 構文に与え，パターンマッチが成功する case 部のスイートを実行するものである．この例にあるように変数 v の値が 1 である場合，実行結果として「One」と出力される．
（v の値を様々に変更して実行を試されたい）
このプログラムの 11 行目の「case :」という記述は，それより上に記述されているパターンにマッチしなかった
場合を意味する．この「 」（アンダースコア）の代わりに変数を記述して変数 v の値を受け取ることもできる．このことに関するサンプルプログラム stpmatch02.py を示す．
プログラム：stpmatch02.py
1
2
3
4
5
6
7
8
9
10
11
12

# coding : utf -8
v = 4# これを様々な値に変更して試す
match v :case 1:
print ( ’ One ’)case 2:
print ( ’ Two ’)case 3:print ( ’ Three ’)case x :print ( ’ Other : ’ , x )このプログラムの 11 行目で「case x:」としているが，これにより，上の 3 つの case にマッチしなかった場合に，変数 v の値を変数 x に受け取ることができる．
この例の通り v の値が 4 である場合の実行結果の出力は「Other:

138 PEP622 – Structural Pattern Matching

165

4」となる．

2.11.1

構造的なパターンcase の後に記述するパターンとして，変数を含むデータ構造（構造的なパターン）を記述することができ，matchに与えたデータ構造に対応する位置の値をパターン内の変数に受け取ることができる．このことをサンプルプログラ
ム stpmatch03.py で示す．
プログラム：stpmatch03.py
1
2
3
4
5
6
7
8
9
10
11
12

# coding : utf -8
v = [1 ,2]# リストの要素の個数を変更して試す
match v :case [ x ]:print ( ’1 要 素 の リ ス ト ： 要 素 = ’ , x )case [x , y ]:print ( ’2 要 素 の リ ス ト ： 要 素 = ’ , x , y )case [x ,y , z ]:print ( ’3 要 素 の リ ス ト ： 要 素 = ’ , x , y , z )case A :print ( ’ そ れ 以 外 ： ’ , A )このプログラムでは，変数 v にリスト [1,2] を与えており，これが 7 行目の「case [x,y]」にマッチし，x に 1 が，y に 2 が得られる．従って，このプログラムを実行すると「2 要素のリスト： 要素 = 1 2」が出力される．
2 行目を変更して変数 v に与えるリストの長さを様々に変えて実行を試みられたい．
構造的なパターンには具体的な値（リテラル）を含むことができる．このことに関してサンプルプログラム

stpmatch03-2.py を示す．
プログラム：stpmatch03-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8
L = [ ’ 加 算 ’ , 1 , 2]
# L = [ ’ 乗 算 ’ , 3 , 4]
# L = [ ’ 総 和 ’ , 1 ,2 ,3 ,4]# L = [ ’ 総 乗 ’ , 1 ,2 ,3 ,4]# L = [ ’ 関 数 名 ’ , 5 ,6 ,7 ,8]match L :case [ ’ 加 算 ’ , x , y ]:print (L , ’ - > ’ , x + ycase [ ’ 乗 算 ’ , x , y ]:print (L , ’ - > ’ , x * ycase [ ’ 総 和 ’ , * a ]:r = 0
for x in a : r = r
print (L , ’ - > ’ , r )case [ ’ 総 乗 ’ , * a ]:r = 1
for x in a : r = r
print (L , ’ - > ’ , r )case A :print (L , ’ - > ’ , A )

)
)

+ x

* x

このプログラムでは変数 L にリストを与えているが，その第 1 要素は計算処理を意味する文字列とし，残りの要素の値を用いて計算処理を実行するもの139 とする．この例では変数 L に [’ 加算’, 1, 2] を与えており「1 と 2 を加算する」処理を意図している．このプログラムを実行すると L の値が 9 行目の case にマッチし，「[’ 加算’, 1, 2] ->3」が出力される．
このプログラムの 2〜6 行目の部分のコメント「#」のどれか 1 つを外すことで実行結果が様々に変わることを確認されたい．
参考）match の次に与える値と case の次に記述するパターンが異なるデータ構造（例えばリストとタプルなど）であってもマッチすることがある．

139 代表的な Lisp 言語における S 式による表現に倣った．

166

2.11.2

条件付きのパターンマッチング

case の後のパターンに if の記述を付けることで条件（guard）を設定することができる．このことに関するサンプ
ルプログラム stpmatch04.py を示す．
プログラム：stpmatch04.py
1
2
3
4
5
6
7
8
9
10

# coding : utf -8
v = 3# これを様々な値に変更して試す
match v :case p if p > 0:
print (p , ’ は 正 の 値 で す ． ’ )case p if p < 0:
print (p , ’ は 負 の 値 で す ． ’ )case p :print (p , ’ は ゼ ロ で す ． ’ )このプログラムでは変数 v に 3 という値を与えているが，これが 5 行目の case にマッチする．この行のパターンの後ろには「if p > 0」が記述されており，この条件を満たすので，このプログラムを実行すると「3 は正の値です．
」と出力される．
このプログラムの 2 行目を変更して変数 v に与える値を様々に変えて実行を試みられたい．

2.11.3

クラスのインスタンスに対するパターンマッチング

あるクラスのインスタンスに対するパターンマッチングが可能であり，インスタンス変数（属性）の値を判りやす
い形で取り出すことができる．このことに関するサンプルプログラム stpmatch05.py を示す．
プログラム：stpmatch05.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# coding : utf -8
import mathclass Pos :# xy座標上の点を表すクラス
def __init__ ( self , ix , iy ):self . x = ix
self . y = iy
def show ( self ):print ( ’( ’ , self .x , ’ , ’ , self .y , ’) ’)
def norm ( self ):print ( ’ 原 点 か ら の 距 離 : ’ , math . sqrt ( self . x **2+ self . y **2))
p = Pos (3 , -4)
p . show (); p . norm ()# x成分，y成分の値を様々に変更して試す

match p :case Pos ( x =0 , y =0):
print ( ’ 原 点 で す ． ’ )case Pos ( x = v1 , y = _ ) if v1 ==0:
print ( ’ y 軸 上 に あ り ま す ． ’)case Pos ( x =_ , y = v2 ) if v2 ==0:
print ( ’ x 軸 上 に あ り ま す ． ’)case Pos ( x = v1 , y = v2 ) if v1 >0 and v2 >0:
print ( ’ 第 一 象 限 に あ り ま す ． ’ )case Pos ( x = v1 , y = v2 ) if v1 <0 and v2 >0:
print ( ’ 第 二 象 限 に あ り ま す ． ’ )case Pos ( x = v1 , y = v2 ) if v1 <0 and v2 <0:
print ( ’ 第 三 象 限 に あ り ま す ． ’ )case Pos ( x = v1 , y = v2 ) if v1 >0 and v2 <0:
print ( ’ 第 四 象 限 に あ り ま す ． ’ )このプログラムで定義されているクラス Pos は x-y 座標上の位置を表す（図 9）ものであり，このクラスのインスタンスに対するパターンマッチングを行っている．
このプログラムに記述されているように，あるクラスのインスタンスの状態（属性の値）をパターンとして表現するには case の記述を次のようにする．

case クラス名 ( 属性名 1=変数 1, 属性名 2=変数 2, … ):167

（if による guard の記述も可能）

y軸

第二象限

第一象限

原点
第三象限

x軸

第四象限

図 9: x-y 座標上の領域
この記述によって，match に与えられたインスタンスの「属性名」で示される属性の値を「変数」に受け取ることができる．またこの記述の際「変数」の代わりに具体的な値を記述して，それをパターンとすることもできる．
（17 行目の記述）
このプログラムでは第四象限の点 (3, −4) が Pos クラスのインスタンス p として作成されており，それに対してパ
ターンマッチングを行っている．このプログラムを実行すると( 3 , -4 )原点からの距離: 5.0
第四象限にあります．

と出力される．
プログラムの 13 行目を変更して Pos クラスのコンストラクタ に与える値を様々に変えて実行を試みられたい．

168

Kivy による GUI アプリケーションの構築

3

Kivy は MIT ライセンスで配布される GUI ライブラリであり，インターネットサイト https://kivy.org/から入手できる．インストール方法から API の説明まで当該サイトで情報を入手することができる．本書では Kivy の基本的な使用方法について解説する140 ．

3.1

Kivy の基本

Kivy によるアプリケーションプログラムは，App クラスのオブジェクトとして構築する．App クラスの使用に際して，下記のようにして必要なモジュールを読み込んでおく．

from kivy.app import App
3.1.1

アプリケーションプログラムの実装

具体的には，App クラスかそれを継承する（拡張する）クラス（以後「アプリケーションのクラス」と呼ぶ）をプ
ログラマが定義し，そのクラスのインスタンスを生成することでアプリケーションプログラムが実装できる．アプリ
ケーションのインスタンスに対して run メソッドを実行することでアプリケーションプログラムの動作が開始する．

run メソッドを呼び出すと，最初にアプリケーションのクラスのメソッド build が呼び出される．この build メソッ
ドは，App クラスに定義されたメソッドであり，これをプログラマが上書き定義（オーバーライド）する形で，アプ
リケーション起動時の処理を記述する．build メソッドで行うことは主に GUI の構築などである．

Kivy によるアプリケーションプログラム構築の素朴な例として，サンプルプログラム kivy01-1.py を示す．
プログラム：kivy01-1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# coding : utf -8
from kivy . app import App
from kivy . uix . label import Label# 基本となるアプリケーションクラス
# ラベルオブジェクト# アプリケーションのクラス
class kivy01 ( App ):def build ( self ):self . lb1 = Label ( text = ’ This is a test of Kivy . ’)return self . lb1# - - - - メ イ ン ル ー チ ン ----# アプリケーションのインスタンスを生成して起動
ap = kivy01 ()ap . run ()この例では，App クラスを拡張した kivy01 クラスとしてアプリケーションを構築している．kivy01 クラスの中ではbuild メソッドをオーバーライド定義しており，Label ウィジェット（文字などを表示するウィジェット141 ）を生成している．
このプログラムを実行すると図 10 のようなウィンドウが表示される．
■ Kivy 利用時のトラブルに関すること

Kivy を使用したプログラムを実行する際に，システムが使用するグラフィックス用 API の関係でエラーが発生する場合がある．これに関しては巻末付録「B.1 Kivy 利用時のトラブルを回避するための情報」（p.365）を参照されたい．

3.1.2

GUI 構築の考え方

先のプログラム kivy01-1.py においては，GUI 要素として Label ウィジェットを生成しており，このウィジェットを

build メソッドの戻り値としている．Kivy ではこのように，GUI の最上位のウィジェットを build メソッドの戻り値とする．

140 巻末付録「B Kivy に関する情報」（p.365）も参照のこと
141 ウィジェット：GUI を構成する部品のこと．

169

図 10: Kivy01-1.py の実行結果

Kivy では，GUI を階層構造として構築する．すなわち「親」のオブジェクトの配下に「子」のオブジェクト群が従属する形で GUI を構築する．Kivy には GUI の配置を制御する Layout や Screen といったクラスがあり，それらクラスのオブジェクト配下にウィジェットなどの要素を配置する形式で GUI を構築する．先のプログラム kivy01-1.py では，最も単純に GUI の導入説明をするために．Label オブジェクトが 1 つだけ存在するものとした．すなわち，このLabel オブジェクトが GUI の最上位の「親オブジェクト」となっている．実際のアプリケーション構築においては，Layout や Screen のオブジェクトなど，要素の配置のためのものを GUI の最上位オブジェクトとすることが一般的である．

Kivy における GUI のためのクラスは，大まかにウィジェット，レイアウト，スクリーンの 3 つに分けて考えることができる．

3.1.2.1

Widget（ウィジェット）

ボタンやラベル，チェックボックス，テキスト入力エリアといった基本的な要素である．代表的なウィジェットを表25 に挙げる．
クラス

表 25: 代表的なウィジェット
機能

Label

ラベル（文字などを表示する）

Buttonボタン

TextInput

テキスト入力（フィールド／エリア）

CheckBox

チェックボックス

ProgressBar

進捗バー

Sliderスライダ

Switchスイッチ

ToggleButton

トグルボタン

Image

画像表示

Video

動画表示

この他にも多くのウィジェットがあるが，詳しくは Kivy の公式サイトを参照のこと．

3.1.2.2

Layout（レイアウト）

レイアウトは GUI オブジェクトを配置するためのもので，一種の「コンテナ」（容器）と考えることができる．例
えば BoxLayout を使用すると，その配下にウィジェットなどを水平あるいは垂直に配置する（図 11）ことができる．
例えば，BoxLayout を入れ子の形で（階層的に）組み合わせると，図 12 のような GUI デザインを実現することができる．
利用できるレイアウトを表 26 に挙げる．

170

図 11: BoxLayout࣊ࢵࢲ࣮ࢼࣅࢤ࣮ࢩࣙࣥ

┠ḟࢥࣥࢸࣥࢶ࣌࢖ࣥ
ࣇࢵࢱ࣮
図 12: BoxLayout を組み合わせたデザインの例

クラス

表 26: 利用できるレイアウト
機能

BoxLayout

水平／垂直のレイアウト

GridLayout

縦横（2 次元）のグリッド配置

StackLayout

水平あるいは垂直方向に順番に追加される配置

AnchorLayout

片寄せ，中揃え（均等配置）の固定位置

FloatLayout

直接位置指定（絶対，相対）

RelativeLayout

直接位置指定（画面の位置：絶対，相対）

PageLayout

複数ページの切り替え形式

ScatterLayout

移動，回転などを施すためのレイアウト■ BoxLayout によるレイアウトの例
サンプルプログラム kivy01-BoxLayout01.py によって BoxLayout による GUI のレイアウトを例示する．
プログラム：kivy01-BoxLayout01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----import sys
from kivy . app import App
from kivy . uix . boxlayout import BoxLayout
from kivy . uix . button import Button
from kivy . core . window import Window# - - - - - ウ ィ ン ド ウ の 設 定 ----Window . size = (300 ,300)# - - - - - 最 上 位 の レ イ ア ウ ト ----root = BoxLayout ( orientation = ’ vertical ’)# - - - - - G U I の 構 築 ----row1 = BoxLayout ( orientation = ’ horizontal ’) # 1 行 目 の レ イ ア ウ ト
row1 . size_hint = (1.0 ,0.25)# 比率による高さの設定
b11 = Button ( text = ’11 ’);
b11 . size_hint = ( 0.2 , 1.0 )# 比率によるb12 = Button ( text = ’12 ’);b12 . size_hint = ( 0.8 , 1.0 )# 横幅の設定
row1 . add_widget ( b11 );row1 . add_widget ( b12 )root . add_widget ( row1 )row2 = BoxLayout ( orientation = ’ horizontal ’) # 2 行 目 の レ イ ア ウ ト
row2 . size_hint = (1.0 ,0.75)# 比率による高さの設定

171

25
26
27
28
29
30
31
32
33
34
35
36
37
38

b21 = Button ( text = ’21 ’);
b21 . size_hint = ( 2 , 1.0 ) # 整 数 比
b22 = Button ( text = ’22 ’);
b22 . size_hint = ( 3 , 1.0 ) # に よ る
b23 = Button ( text = ’23 ’);b23 . size_hint = ( 5 , 1.0 ) # 横 幅 の 設 定
row2 . add_widget ( b21 );row2 . add_widget ( b22 );row2 . add_widget ( b23 )root . add_widget ( row2 )# - - - - - ア プ リ ケ ー シ ョ ン の ク ラ ス ----class kivy01 ( App ):def build ( self ):return root
# - - - - - ア プ リ ケ ー シ ョ ン の 起 動 ----ap = kivy01 ()ap . run ()このプログラムは BoxLayout を入れ子にしてボタン142 を縦横に配置するものである．このプログラムを実行すると
図 13 の (a) のようなウィンドウが表示される．

0.25
(25%)

0.2
(20%)

0.8
(80%) 横幅の比率

1112

１行目の BoxLayout( horizontal )

高さの比率
0.75
(75%)

21

23

２行目の BoxLayout( horizontal )2(a) アプリケーションのウィンドウ223
横幅の整数比5最上位の BoxLayout( vertical )(b) ウィジェットの配置とサイズの比率

図 13: kivy01-BoxLayout01.py を実行した様子
このプログラムは垂直配置の BoxLayout である root（13 行目で作成）を最上位のウィジェットとして，その中に水平配置の BoxLayout である row1，row2（16,23 行目で作成）を子ウィジェットとして保持（21,29 行目で登録）している．row1 の中にはボタン b11,b12 が，row2 の中にはボタン b21,b22,b23 が水平方向に配置されている．
ウィジェットのサイズ指定の方法：
各ウィジェットのサイズは size hint プロパティで制御する．size hint プロパティには (横比率, 縦比率) の形式で親ウィジェットに対する比率として値を与える．例えば 2 つの BoxLayout である row1，row2 の高さの比は 17 行目と 24 行目にあるように 0.25:0.75 として値を設定している．同様に 2 つのボタン b11，b12 の横幅の比率は 18 行目と 19 行目にあるように 0.2:0.8 として設定している．また size hint プロパティの値はより柔軟に解釈され，ボタン

b21，b22，b23 の size hint の様な形式（合計が 1.0 にならないような形）で与えること（25〜27 行目）もできる．
ウィジェットの size hint の設定を行わない場合は，システムがサイズを自動的に調整する．上のプログラムで size hintの設定を全て抹消すると，全てのウィジェットが均等なサイズでレイアウトされるので試されたい．

3.1.2.3

Screen（スクリーン）スクリーンにはレイアウトやウィジェットを配置することができ，1 つのスクリーン（Screen）は 1 つの操作パネルと見ることができる．更に複数のスクリーンをスクリーンマネジャ（ScreenManager）と呼ばれるオブジェクト配下に設置することができ，それらスクリーンを切り替えて表示することができる．
スクリーンマネジャを用いて構築された GUI は，いわゆるプレゼンテーションスライドのように動作し，各スクリーンを遷移して切り替えること（transition）で異なる複数のインターフェースを切り替えることができる．

Screen，ScreenManager の扱いに関しては「3.9 GUI 構築の形式」（p.197）のところで説明する．

142 「3.3.2 ボタン：Button」（p.183）で解説する．

172

3.1.3ウィンドウの扱い

ウィンドウ（Window）は構築する GUI アプリケーション全体を表すオブジェクトであり，1 つのアプリケーショ
ンに 1 つのウィンドウオブジェクトが存在する．
ウィンドウオブジェクトを明に扱うには，次のようにして Window モジュールを読み込んでおく必要がある．

from kivy.core.window import Window
Window オブジェクトに対して，ウィンドウサイズの指定をはじめとする各種制御ができる．先のプログラムを改変した kivy01-2.py を次に示す．
プログラム：kivy01-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# coding : utf -8
from kivy . app import App
from kivy . uix . label import Labelfrom kivy . core . window import Window# 基本となるアプリケーションクラス
# ラベルオブジェクト# ウィンドウの操作に必要なもの# アプリケーションのクラス
class kivy01 ( App ):def build ( self ):self . lb1 = Label ( text = ’ This is a test of Kivy . ’)return self . lb1# - - - - メ イ ン ル ー チ ン ----# ウ ィ ン ド ウ サ イ ズ の 設 定 （400 ×100 ）Window . size = (400 ,100)# アプリケーションのインスタンスを生成して起動
ap = kivy01 ()ap . run ()このように Window オブジェクトの size プロパティに値を設定することで，アプリケーションのウィンドウサイズを変更することができる．
（図 14 参照）

Window の size プロパティを 400 × 100 に設定している

図 14: Kivy01-2.py の実行結果

Window のプロパティとしてはこの他にも clearcolor もあり，これの値143 を設定することでウィンドウの色を変更することもできる．

3.1.4

マルチタッチの無効化

Kivy ではポインティングデバイスのマルチタッチを受け付けるが，通常の PC のデスクトップ環境ではマルチタッチが使用できないことが多い．この場合，Kivy アプリケーションのウィンドウ内でマウスを右クリックすると，ウィンドウ内に小さな円が表示される．先に挙げたプログラム kivy01-2.py において実行中にマウスを右クリックした様子の例を図 15 に示す．

右クリックした場所に小さな円が表示される

図 15: 通常の PC 環境での右クリック

143 clearcolor の値は (R,G,B, α) のタプルで与える．この場合の各要素は 0〜1 の数値である．

173

ポインティングデバイスのマルチタッチを無効化するとこの反応はなくなる．そのためには，Kivy 関連モジュールの読込みに先立って次のように記述する．

from kivy.conﬁg import Conﬁg
Conﬁg.set(’input’, ’mouse’, ’mouse,disable multitouch’)
Kivy には各種の設定のための Conﬁg オブジェクトがあり，それに対して set メソッドを用いることで各種の設定作業を行う．

3.2

基本的な GUI アプリケーション構築の方法

3.2.1

イベント処理（導入編）

GUI アプリケーションプログラムはユーザからの操作をはじめとするイベントの発生を受けてイベントハンドラを起動する，いわゆるイベント駆動型のスタイルを基本とする．ここではサンプルプログラムの構築を通してイベント処理の基本的な実装方法について説明する．
先に挙げたサンプルプログラムを更に改変して，ラベルオブジェクトにタッチ144 が起こった際のイベント処理について説明する．

3.2.1.1

イベントハンドリング

ここでは，Label オブジェクトが touch down（タッチの開始／ボタンの押下），touch move（ドラッグ），touch up（タッチの終了／ボタンを放す）といったイベントを受け付ける例を挙げて説明する．ウィジェットには，それらイベントを受け付けるためのメソッド（on touch down，on touch move，on touch up）が定義されており，プログラマはウィジェットの拡張クラスを定義して，それらメソッドをオーバーライドして，実際の処理を記述する．
プログラム：kivy01-3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# coding : utf -8
from kivy . app import App
from kivy . uix . label import Labelfrom kivy . core . window import Window# 基本となるアプリケーションクラス
# ラベルオブジェクト# ウィンドウの操作に必要なもの# ラベルの拡張
class MyLabel ( Label ):# タッチ開始（マウスボタンの押下）の場合の処理
def on_touch_down ( self , touch ):print ( self . events ())
print ( ’ touch down : ’, touch . spos )# タッチの移動（ドラッグ）の場合の処理
def on_touch_move ( self , touch ):print ( ’ touch move : ’, touch . spos )# タッチ終了（マウスボタンの解放）の場合の処理
def on_touch_up ( self , touch ):print ( ’ touch up : ’, touch . spos )# アプリケーションのクラス
class kivy01 ( App ):def build ( self ):self . lb1 = MyLabel ( text = ’ This is a test of Kivy . ’)return self . lb1# - - - - メ イ ン ル ー チ ン ----# ウィンドウサイズの設定
Window . size = (400 ,100)# アプリケーションのインスタンスを生成して起動
ap = kivy01 ()ap . run ()解説：
このプログラムでは，Label クラスを拡張した MyLabel クラスを定義し（7〜17 行目），そのクラスでイベントハ
144 パーソナルコンピュータの操作環境ではマウスのクリックがこれに相当する．Kivy はスマートフォンやタブレットコンピュータでの処理を前提にしており，タッチデバイスを基本にしたイベント処理となっている．

174

ンドリングをしている．このクラスではそれぞれのイベントに対応するメソッドの記述をしており，仮引数として記述された touch に，イベント発生時の各種情報を保持するオブジェクトが与えられる．
アプリケーション全体は，App クラスの拡張クラス kivy01 クラスとして定義されている．
（20〜23 行目）．10 行目にあるように，events メソッドを実行すると，そのオブジェクトが対象とするイベントの一覧情報が得られる．また，
マウスやタッチデバイスのイベントが持つ spos プロパティには，イベントが発生した位置の情報が保持されている．
このプログラムを実行した際の標準出力の例を次に示す．
dict keys([ón ref press,́ ón touch down,́ ón touch move,́ ón touch up´])touch down: (0.0875, 0.45999999999999996)
touch move: (0.0875, 0.48)
touch move: (0.09, 0.48)
touch move: (0.0925, 0.48)
touch move: (0.095, 0.48)
touch move: (0.0975, 0.48)
touch move: (0.1, 0.48)
touch move: (0.0975, 0.47)
touch up : (0.0975, 0.47)

3.2.2

アプリケーション構築の例

ここでは，簡単な事例を挙げて，GUI アプリケーションプログラムの構築について説明する．事例として示すアプ
リケーションは簡単な描画アプリケーションで，概観を図 16 に示す．このアプリケーションは，ウィンドウ内の描画
領域にタッチデバイスやマウスでドラッグした軌跡を描画する．またウィンドウ上部の「Clear」ボタンをタッチ（クリック）すると描画領域を消去し，「Quit」ボタンをタッチ（クリック）するとアプリケーションが終了する．

(a) 起動時(b) タッチデバイスやマウスで描画した例

図 16: kivy03.py の実行結果
この事例では，BoxLayout を使用してウィンドウ内のレイアウトを実現している．具体的には，水平方向の BoxLayout
を用いて「Clear」と「Quit」の 2 つのボタンを配置し，そのレイアウトと描画領域を垂直方向の BoxLayout で配置している．BoxLayout を使用するには次のようにして必要なモジュールを読み込んでおく．

BoxLayout を使用するためのモジュールの読込みfrom kivy.uix.boxlayout import BoxLayout
BoxLayout の配置方向（水平，垂直）の指定は，インスタンス生成時にコンストラクタの引数としてキーワード引数「orientation=」を与える．この引数の値として’horizontal’ を与えると水平方向，’vertical’ を与えると垂直方向の配置となる．
ボタンウィジェット（Button）を使用するには次のようにして必要なモジュールを読み込んでおく．

Button を使用するためのモジュールの読込みfrom kivy.uix.button import Button
ボタンウィジェットのトップに表示する文字列は，インスタンス生成時にコンストラクタの引数としてキーワード引
数「text=」を与える．この引数の値として文字列を与えると，それがボタントップに表示される．

175

グラフィックスを描画するには，Wedget クラスを使用するのが一般的である．このクラスは多くのウィジェットの上位クラスであり，描画をするための canvas という要素を持つ．グラフィックスの描画はこの canvas に対して行う．

Widget を使用するには次のようにして必要なモジュールを読み込んでおく．
Widget を使用するためのモジュールの読込みfrom kivy.uix.widget import Widget【実装例】
今回の事例のプログラムを kivy03.py に挙げる．これを示しながら GUI アプリケーションプログラム構築の流れを説明する．
プログラム：kivy03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----import sys
from kivy . app import App
from kivy . uix . boxlayout import BoxLayout
from kivy . uix . button import Button
from kivy . uix . widget import Widget
from kivy . graphics import Color , Line
from kivy . core . window import Window# - - - - - 拡 張 ク ラ ス の 定 義 ----# アプリケーションのクラス
class kivy03 ( App ):def build ( self ):return root
# Clearボタンのクラス
class BtnClear ( Button ):def on_release ( self ):drawArea . canvas . clear ()# Quitボタンのクラス
class BtnQuit ( Button ):def on_release ( self ):sys . exit ()# 描画領域のクラス
class DrawArea ( Widget ):def on_touch_down ( self , t ):self . canvas . add ( Color (0.4 ,0.4 ,0.4 ,1) ) # 描 画 色 の 設 定
self . lineObject = Line ( points =( t .x , t . y ) , width =10 )self . canvas . add ( self . lineObject )def on_touch_move ( self , t ):self . lineObject . points += ( t .x , t . y )def on_touch_up ( self , t ):pass
# - - - - - G U I の 構 築 ----# ウィンドウの色とサイズ
Window . size = (600 ,400)
Window . clearcolor = (1 ,1 ,1 ,1)# 最上位レイアウトの生成
root = BoxLayout ( orientation = ’ vertical ’)# ボタンパネルの生成
btnpanel = BoxLayout ( orientation = ’ horizontal ’)btnClear = BtnClear ( text = ’ Clear ’)# Clearボタンの生成
btnQuit = BtnQuit ( text = ’ Quit ’)# Quitボタンの生成
btnpanel . add_widget ( btnClear )# Clearボタンの取り付け
btnpanel . add_widget ( btnQuit )# Quitボタンの取り付け
btnpanel . size_hint = ( 1.0 , 0.1 ) # ボ タ ン パ ネ ル の サ イ ズ 調 整
root . add_widget ( btnpanel )# ボタンパネルをメインウィジェットに取り付け# 描画領域の生成
drawArea = DrawArea ()root . add_widget ( drawArea )

176

57
58
59
60

# - - - - - ア プ リ ケ ー シ ョ ン の 実 行 ----ap = kivy03 ()ap . run ()全体の概要：
このプログラムの 3〜9 行目で必要なモジュール群を読み込んでいる．必要となる各種のクラスの定義は 13〜35 行
目に記述している．GUI を構成するための各種のインスタンスの生成は 43〜56 行目に記述しており，59〜60 行目にアプリケーションの実行を記述している．

BoxLayout へのウィジェットの登録「Clear」「Quit」の 2 つのボタンは 47〜48 行目で生成しており，これらを add widget メソッドを用いて水平配置の

BoxLayout である btnpanel に登録（49〜50 行目）している．同様の方法で，最上位の BoxLayout （垂直配置）である root に btnpanel と描画領域のウィジェット drawArea を登録（52，56 行目）している．
※ 親ウィジェットに子ウィジェットを登録，削除する方については「3.2.4 ウィジェットの登録と削除」（p.179）を参照のこと．

BoxLayout 配下に登録されたオブジェクトは均等な大きさで配置されるが，今回の事例では，ボタンの領域の高さを小さく，描画領域の高さを大きく取っている．このように，配置領域の大きさの配分を変えるには，BoxLayout の子の要素に対して size hint プロパティを指定する．51 行目で実際にこれをしているが，親ウィジェットのサイズに対する比率を (水平比率, 垂直比率) の形で与える．

canvas に対する描画
Widget の canvas に対して描画するには Graphics クラスのオブジェクトを使用する．具体的には Graphics クラスのオブジェクトを canvas に対して add メソッドを用いて登録する．

canvas に対して登録できる Graphics オブジェクトには Line（折れ線），Rectangle（長方形），Ellipse（楕円）をはじめとする多くのものがある．また描画の色も Color オブジェクトを canvas に登録することで指定する．今回のプログラムでは 29 行目で Color オブジェクトを登録して描画色を指定している．また，30 行目で作成した Line オブジェ
クトを 31 行目で登録し，33 行目でこれを更新することで描画している．
イベント処理と描画の流れ
今回のプログラムでは，描画領域のオブジェクト drawArea に対するイベント処理によって描画を実現している．
具体的には DrawArea クラスの定義の中で，タッチが開始（マウスボタンのクリックが開始）したことを受けるイベ
ントハンドラである on touch down メソッド，ドラッグしたことを受けるイベントハンドラである on touch move メ
ソッド，タッチが終了（マウスボタンが解放）したことを受けるイベントハンドラである on touch up メソッドを記述することで描画処理を実現している．これらメソッドは 2 つの仮引数を取る．
まず，on touch down で描画の開始をするが，Color オブジェクトの登録による色の指定（29 行目）をして，Line
オブジェクトを生成（30 行目）して登録（31 行目）している．このときはまだ Line オブジェクトは描画の開始点の座標のみを保持している．
次に，ドラッグが起こった際に on touch move で Line オブジェクトの座標を追加（33 行目）することで，実際の描画を行う．タッチやマウスの座標はメソッドの第 2 引数である t に与えられるオブジェクトに保持されている．このオブジェクトの x プロパティに x 座標の値が，y プロパティに y 座標の値がある．

canvas の消去
canvas オブジェクトに対して clear メソッドを実行することでそこに登録された Graphics オブジェクトを全て消去する．今回のプログラムでは，消去ボタンである btnClear オブジェクトのタッチ（クリック）を受けるイベント処理でこのメソッドを実行（20 行目）して描画を消去している．Button オブジェクトのタッチ（クリック）の開始と終了のイベントは，on press，on release メソッドで受ける．これらメソッドは 1 つの引数を取る．
アプリケーションの終了
今回のプログラムでは，終了ボタンである btnQuit オブジェクトに対するイベント処理でアプリケーションの終了を実現している．sys モジュールを読み込み，exit を呼び出すことでプログラムが終了する．

177

3.2.3

イベント処理（コールバックの登録による方法）

ウィジェットの拡張クラスを定義してイベントハンドリングのメソッドをオーバーライドする方法とは別に，bind
メソッドを用いてイベントハンドリングする方法もある．

GUI のオブジェクトの生成後，そのオブジェクトに対して，
オブジェクト.bind(イベント=コールバック関数)とすることで，bind メソッドの引数に指定したイベントが発生した際に，指定したコールバック関数を呼び出すことができる．この方法を採用することにより，イベント処理を目的とする拡張クラスの定義を省くことができる．

bind を用いてイベント処理を登録する形で先のプログラム kivy03.py を書き換えたプログラム kivy03-2.py を示す．
プログラム：kivy03-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# coding : utf -8
import sys
from kivy . app import App
from kivy . uix . boxlayout import BoxLayout
from kivy . uix . button import Button
from kivy . uix . widget import Widget
from kivy . graphics import Color , Line
from kivy . core . window import Window# - - - - - 拡 張 ク ラ ス の 定 義 ----# アプリケーションのクラス
class kivy03 ( App ):def build ( self ):return root
# - - - - - G U I の 構 築 ----# ウィンドウの色とサイズ
Window . size = (600 ,400)
Window . clearcolor = (1 ,1 ,1 ,1)# 最上位レイアウトの生成
root = BoxLayout ( orientation = ’ vertical ’)# ボタンパネルの生成
btnpanel = BoxLayout ( orientation = ’ horizontal ’)btnClear = Button ( text = ’ Clear ’) # C l e a r ボ タ ン の 生 成
btnQuit = Button ( text = ’ Quit ’)# Quitボタンの生成
btnpanel . add_widget ( btnClear )# Clearボタンの取り付け
btnpanel . add_widget ( btnQuit )# Quitボタンの取り付け
btnpanel . size_hint = ( 1.0 , 0.1 ) # ボ タ ン パ ネ ル の サ イ ズ 調 整
root . add_widget ( btnpanel )# ボタンパネルをメインウィジェットに取り付け# 描画領域の生成
drawArea = Widget ()root . add_widget ( drawArea )# - - - - - コ ー ル バ ッ ク の 定 義 と 登 録 ----# 描画領域を消去する関数
def callback_Clear ( self ):drawArea . canvas . clear ()drawArea . canvas . add ( Color (0.4 ,0.4 ,0.4 ,1) )drawArea . lineObject = Line ( points =[] , width =10)
drawArea . canvas . add ( drawArea . lineObject )btnClear . bind ( on_release = callback_Clear )# ボタンへの登録# アプリケーションを終了する関数
def callback_Quit ( self ):sys . exit ()btnQuit . bind ( on_release = callback_Quit )# ボタンへの登録# 描画のための関数
def callback_drawStart ( self , t ):self . canvas . add ( Color (0.4 ,0.4 ,0.4 ,1) )self . lineObject = Line ( points =( t .x , t . y ) , width =10 )self . canvas . add ( self . lineObject )

178

56
57
58
59
60
61
62
63
64
65
66

def callback_drawMove ( self , t ):self . lineObject . points += ( t .x , t . y )def callback_drawEnd ( self , t ):pass
drawArea . bind ( on_touch_down = ca ll back_drawStart )drawArea . bind ( on_touch_move = callback_drawMove )drawArea . bind ( on_touch_up = callback_drawEnd )# - - - - - ア プ リ ケ ー シ ョ ン の 実 行 ----ap = kivy03 ()ap . run ()全体の概要：GUI 構築の部分は概ね kivy03.py と同じであるが，イベント処理のためのコールバック関数の定義と各ウィジェッ
トへの登録が，39〜62 行目に記述されている．
イベントハンドリングには，拡張クラスを定義してイベントハンドラをオーバーライドする方法と，bind メソッド
によるコールバック関数の登録の 2 種類の方法があるが，プログラムの可読性などを考慮してどちらの方法を採用するかを検討するのが良い．

3.2.4

ウィジェットの登録と削除

ウィジェットの階層的関係は，親の要素に子の要素を登録する方法で構築する．親のウィジェット wp に子のウィジェット wc を登録するには add widget メソッドを用いて，

wp.add widget(wc)と実行する．また逆に wp から wc を削除するには remove widget を用いて，

wp.remove widget(wc)と実行する．
次のプログラム kivy07.py は，一旦登録したウィジェトを取り除く処理を示すものである．
プログラム：kivy07.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# coding : utf -8
from kivy . app import App
from kivy . uix . anchorlayout import AnchorLayout
from kivy . uix . button import Button
from kivy . core . window import Window# - - - - - 最 上 位 の ウ ィ ジ ェ ッ ト ----root = AnchorLayout ()# - - - - - ボ タ ン の 生 成 ----btn1 = Button ( text = ’ Delete This Button ! ’)
# 最上位のウィジェットからボタンを取り除く処理（コールバック関数）
def delbtn ( self ):root . remove_widget ( btn1 )# ボタンへのコールバックの登録
btn1 . bind ( on_release = delbtn )# - - - - - 最 上 位 の ウ ィ ジ ェ ッ ト に ボ タ ン を 登 録 ----root . add_widget ( btn1 )# - - - - - ア プ リ ケ ー シ ョ ン の 実 装 ----class kivy07 ( App ):def build ( self ):return root
Window . size =(250 ,50)
kivy07 (). run ()

179

解説
このプログラムは最上位の AnchorLayout にボタン を 1 つ登録するものであり，そのボタンをクリック（タッチ）
すると，そのボタン自身を取り除く．プログラムの実行例を図 17 に示す．

→
(a) ボタンをクリックすると(b) そのボタンが除去される

図 17: ウィジェット（ボタン）を取り除く処理

3.2.5

アプリケーションの開始と終了のハンドリング

Kivy アプリケーションの実行が開始する時と終了する時のハンドリングは，アプリケーションクラスの on start メ
ソッドと on stop メソッドでそれぞれ行う．この様子を次のサンプルプログラム kivy08.py で確認できる．
プログラム：kivy08.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----from kivy . app import App
from kivy . uix . label import Labelfrom kivy . core . window import Window# - - - - - 最 上 位 の ウ ィ ジ ェ ッ ト ----root = Label ( text = ’ This is a sample . ’)
# - - - - - ア プ リ ケ ー シ ョ ン の 実 装 ----class kivy08 ( App ):# アプリケーションのインスタンス生成
def build ( self ):print ( ’0) ア プ リ ケ ー シ ョ ン の イ ン ス タ ン ス が 生 成 さ れ ま し た ． ’ )return root
# アプリケーション実行開始時
def on_start ( self ):print ( ’1) ア プ リ ケ ー シ ョ ン の 実 行 が 開 始 さ れ ま し た ． ’ )# アプリケーション終了時
def on_stop ( self ):print ( ’2) ア プ リ ケ ー シ ョ ン を 終 了 し ま す ． ’ )Window . size =(250 ,50)
kivy08 (). run ()このプログラムを実行すると図 18 のようなウィンドウが表示される．

図 18: Kivy08.py のアプリケーションウィンドウ
アプリケーションの生成時，開始時，終了時にそれぞれメッセージを標準出力に出力する．
（次の例参照）

0) アプリケーションのインスタンスが生成されました．
1) アプリケーションの実行が開始されました．
2) アプリケーションを終了します．

3.3

←生成時
←開始時
←終了時

各種ウィジェットの使い方

ここでは使用頻度の高い代表的なウィジェットの基本的な使い方について説明する．より詳細な使用方法について
は Kivy の公式サイトを参照のこと．またここで紹介するウィジェット以外にも有用なものが多くあり，それらについ180

ても公式サイトを参照のこと．

3.3.1

ラベル：Label

GUI に文字を表示する場合に標準的に用いられるのがラベル（Label）オブジェクトである．Label のインスタンスを生成する際，コンストラクタの引数に text=’ 文字列’ とすると，与えた文字列を表示するラベルが生成される．図19 はLabel(text=’This is a test for Label object.’) として生成したラベルを表示した例である．

図 19: Label オブジェクトの表示
ラベルに表示する文字のフォントを指定することができる．特に本書を執筆中の版の Kivy は，フォントを指定せずに日本語の文字列を表示することができないので，日本語文字列を表示する場合にはフォント指定が必須である．図

20 は Windows 環境でLabel( text=’ 日本語を MS ゴシックで表示するテスト’,
font name=r’C:￥Windows￥Fonts￥msgothic.ttc’,font size=’24pt’)
として，MS ゴシックフォントを使用して表示した例である．この書き方の中にある font name はフォントのパス145
を，font size はフォントのサイズを指定するものである．

図 20: Label オブジェクトの表示（MS ゴシックによる日本語表示）使用するフォントによっては，Kivy 独自のマークアップを使用して，強調，斜体などのスタイルを施すことができる．マークアップは与える文字列の中に直接記述できる．図 21 は，Label( text=’[u] 日本語を IPA 明朝で表示するテスト（下線付き）[/u]’,
markup=True, color=(0.6,1,1,1), font name=r’C:￥Windows￥Fonts￥ipam.ttf’,
font size=’20pt’)
として，IPA 明朝フォントを使用して下線（アンダーライン）を施した例である．
マークアップを使用する場合は markup=True を指定する．またこの例のようにフォントの色を指定する際はcolor=(R,G,B, α)と指定する．
マークアップは ’[...]〜[/...]’ で括るタグを使用する．代表的なマークアップには［b］文字列［/b］ 強調文字［u］文字列［/u］ 下線（アンダーライン）［i］文字列［/i］

斜体（イタリック）

といったものがある．

図 21: Label オブジェクトの表示（IPA 明朝による日本語表示：下線付き）

Label のコンストラクタに与える代表的なキーワード引数：
text=’ 文字列’font name=r’ フォントのパス’
font size=’ フォントサイズ’color=［赤，緑，青，α（不透明度）］

全て 0〜1 の値

markup=True

マークアップを使用する場合

145 フォントのパスは OS 毎に異なるので注意すること．

181

ここで示した Label を表示するサンプルプログラムを kivy02Label.py に示す．
プログラム：kivy02Label.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# coding : utf -8# - - - - - モ ジ ュ ー ル の 読 込 み ----from kivy . app import App
from kivy . uix . boxlayout import BoxLayout
from kivy . uix . label import Labelfrom kivy . core . window import Window# - - - - - ク ラ ス の 定 義 ----# アプリケーションのクラス
class kivy02 ( App ):def build ( self ):return root
# - - - - - G U I の 構 築 ----# 最上位のレイアウト
root = BoxLayout ( orientation = ’ vertical ’)# ラベル
lb1 = Label (text = ’ This is a test for Label object . ’ ,font_size = ’24 pt ’)
lb2 = Label (text = ’ 日 本 語 を M S ゴ シ ッ ク で 表 示 す る テ ス ト ’ ,font_name =r ’ C :\ Windows \ Fonts \ msgothic . ttc ’ ,font_size = ’24 pt ’)
lb3 = Label (text = ’ 日 本 語 を M S 明 朝 で 表 示 す る テ ス ト ’ ,font_name =r ’ C :\ Windows \ Fonts \ msmincho . ttc ’ ,font_size = ’24 pt ’)
lb4 = Label (text = ’ 日 本 語 を I P A ゴ シ ッ ク で 表 示 す る テ ス ト ’ ,color =(1 ,1 ,0 ,1) ,font_name =r ’.\ ipag . ttf ’ ,font_size = ’24 pt ’)
lb5 = Label (text = ’[ u ] 日 本 語 を I P A 明 朝 で 表 示 す る テ ス ト （ 下 線 付 き ） [/ u ] ’ ,markup = True ,color =(0.6 ,1 ,1 ,1) ,font_name =r ’.\ ipam . ttf ’ ,font_size = ’20 pt ’)root . add_widget ( lb1 )root . add_widget ( lb2 )root . add_widget ( lb3 )root . add_widget ( lb4 )root . add_widget ( lb5 )# ウィンドウの色とサイズ
Window . size = (640 ,300)# - - - - - ア プ リ ケ ー シ ョ ン の 起 動 ----ap = kivy02 ()ap . run ()注意）このプログラムを実行する場合は，フォントのパスなどを適切に編集すること．

3.3.1.1

リソースへのフォントの登録

フォントファイルが収められているディレクトリのパスを Kivy のリソース（resource）に登録しておくと font nameの指定において，フォントのファイル名のみの記述で済む．フォントファイルのディレクトリをリソースに登録するには，resource add path メソッドを使用する．このメソッドを使用するためには次のようにして必要なモジュールを読み込んでおく．

from kivy.resources import resource add path
この後 resource add path メソッドを実行する．

182

《 フォントパスのリソースへの登録 》

resource add path(フォントディレクトリのパス)
例えば Windows 環境では，

resource add path(r’C:￥Windows￥Fonts’)などとする．
■ フォントファイルと格納場所に関すること
本書では Windows 環境を前提とした解説を基本としており，Label オブジェクトのためのフォントファイルもC:￥Windows￥Fonts 配下にあることを前提としている．しかし，クロスプラットフォームに対応したアプリケーショ
ンプログラムを開発する場合は，各 OS 固有のフォントディレクトリを前提とするのは好ましくない．また，各 OSに強く関連づけられたフォント（Windows における MS ゴシックや MS 明朝など）を使用するのもあまり好ましくない．従って，クロスプラットフォームで動作するアプリケーションを開発する場合は，IPA 146 や Google などが公開する制約条件の緩いライセンスのフォントなどをアプリケーション独自のディレクトリに配置して使用する方が良い．
■ デフォルトフォントの設定

DEFAULT FONT の設定をしておくと，font name の設定を省略した際のデフォルトフォントを指定できる．デフォ
ルトフォントの設定には LabelBase クラスの register メソッドを使用する．これを行うには次のようにして必要なモジュールを読み込んでおく．

from kivy.core.text import LabelBase, DEFAULT FONT
この後デフォルトフォントを設定する．
《 デフォルトフォントの設定 》

LabelBase.register(DEFAULT FONT, フォントファイル名)
例えば Windows 環境で IPA ゴシックフォントをデフォルトフォントにするには，

LabelBase.register(DEFAULT FONT,’ipag.ttf’)などとする．

3.3.2

ボタン：Button

Button はボタンを実現するクラスである．ボタントップに表示する文字列の扱いについては Label の場合とほぼ同じであるが，下記のようにボタンのタッチ（クリック）によるイベント処理ができる点が特徴である．
タッチ（クリック）のイベント：
on press
タッチ（クリック）の開始
on release タッチ（クリック）の終了
これらのイベントハンドリングには引数が 1 つ（自オブジェクト：self）与えられる．

bind メソッドでコールバック関数を登録する場合は，ボタンオブジェクト.bind(on press=コールバック関数)
ボタンオブジェクト.bind(on release=コールバック関数)とする．コールバック関数の定義を記述する際も仮引数は 1 つである．
「ボタンがクリックされた」ことをハンドリングするには「ボタンが放された」と解釈して on release でハンドリングするとよい．

3.3.3

テキスト入力：TextInput

TextInput は文字列の入力，編集をする場合に使用する．フォントやフォントサイズの設定は Label の場合と同じである．
146 情報処理推進機構（https://www.ipa.go.jp/）183

テキストの入力や変更の際に起こるイベント

TextInput オブジェクト内でテキストの新規入力や変更があった場合，それがイベントとして発生する．TextInputの拡張クラスを定義する際はそれを on text メソッドとしてハンドリングする．また TextInput オブジェクトに対して bind メソッドでコールバック関数を登録する際はオブジェクト.bind(text=コールバック関数)とする．on text メソッドでイベントハンドリングする際は仮引数を 3 つ取り，コールバック関数でハンドリングする
際は仮引数を 2 つ取る．両方の場合において，第 1 引数には，そのオブジェクト自身（self）が与えられる．
入力されているテキストの文字列は，プロパティ text に保持されている．
複数行にまたがるテキストを扱うかどうかに関しては，コンストラクタにキーワード引数 ‘multiline=True/False’ を与えることで設定する．True を与えると複数行の取り扱い，False を与えると 1 行のみの取り扱いとなる．

3.3.4

チェックボックス：CheckBox

チェックボックス（CheckBox オブジェクト）のイベントハンドリングは基本的にボタンと同様（on press,on release）
である．チェックされているか否かはチェックボックスオブジェクトのプロパティ active から真理値（True/False）として得られる．

3.3.5

進捗バー：ProgressBar

進捗バー（ProgressBar オブジェクト）は値の大きさを水平方向に可視化するものである．値のプロパティは valueである．可視化範囲の最大値はプロパティ max に設定する．

3.3.6

スライダ：Slider

スライダ（Slider オブジェクト）は縦あるいは横方向にスライドするウィジェットであり，視覚的に値を調整，入力する際に用いる．値のプロパティは value である．このクラスのインスタンスを生成する際，キーワード引数 orientation=
を与えることで，縦横のスタイルを選択できる．この引数の値に ’horizontal’ を与えると横方向，’vertical’ を与えると
縦方向になる．
（デフォルトは水平）
スライダの値の変更に伴って起こるイベント

Slider オブジェクトを操作（値を変更）した場合，それがイベントとして発生する．Slider の拡張クラスを定義する際はそれを on value メソッドとしてハンドリングする．また Slider オブジェクトに対して bind メソッドでコールバック関数を登録する際はオブジェクト.bind(value=コールバック関数)とする．on value メソッドでイベントハンドリングする際は仮引数を 3 つ取り，コールバック関数でハンドリングする際は仮引数を 2 つ取る．両方の場合において，第 1 引数には，そのオブジェクト自身（self）が与えられる．

3.3.7

スイッチ：Switch

スイッチ（Switch オブジェクト）は水平方向の「切り替えスイッチ」で ON/OFF の 2 つの状態を取る．それぞれの状態はプロパティ active から真理値（True/False）として得られる．
（デフォルトは OFF）
スイッチの切り替えに伴って起こるイベント

Switch オブジェクトを操作（値を変更）した場合，それがイベントとして発生する．Switch の拡張クラスを定義する際はそれを on active メソッドとしてハンドリングする．また Switch オブジェクトに対して bind メソッドでコー
ルバック関数を登録する際はオブジェクト.bind(active=コールバック関数)とする．on active メソッドでイベントハンドリングする際は仮引数を 3 つ取り，コールバック関数でハンドリングする際は仮引数を 2 つ取る．両方の場合において，第 1 引数には，そのオブジェクト自身（self）が与えられる．

184

トグルボタン：ToggleButton

3.3.8

トグルボタン（ToggleButton オブジェクト）はいわゆる「ラジオボタン」と同様のものである．すなわち，複数のボタンを 1 つの「グループ」としてまとめ，同一のグループ内のボタンの内，1 つだけが ON（チェック済みもしくはダウン）になるウィジェットである．イベントハンドリングは基本的に Button クラスと同様であるが，プロパティ

state に押されていない状態を意味する ’normal’ か，押されている状態を意味する ’down’ が保持されている．
トグルボタンの例
次のように 3 つのトグルボタン tb1，tb2，tb3 を生成した例について考える．

tb1 = ToggleButton(group=’person’,text=’nakamura’,state=’down’)
tb2 = ToggleButton(group=’person’,text=’tanaka’)
tb3 = ToggleButton(group=’person’,text=’itoh’)
これらを BoxLayout で水平に配置した例が図 22 である．

図 22: トグルボタンの例
トグルボタン生成時のコンストラクタに，キーワード引数 group= を与えることで複数のトグルボタンをグループ化することができる．またグループ内の 1 つのトグルボタンに state=’down’ を指定することで，初期状態で押されているトグルボタンを決めることができる．
画像：Image

3.3.9

Image は画像を扱うためのウィジェットクラスである．そのインスタンスに画像ファイルを割当てることで画像を配置することができる．インスタンス生成時のコンストラクタにキーワード引数 source= を指定することで画像ファイルを割り当てる．
《 Image オブジェクト 》

Image(source=r’ 画像ファイルのパス’)指定したファイルから画像を読み込む．

Image オブジェクトの texture size プロパティに読み込んだ画像のピクセルサイズが保持されている．
画像の表示サイズに関しては，それを配置するレイアウトオブジェクトに制御を委ねるのが一般的である．次に示
すサンプルプログラムは，スライダに連動して画像の表示サイズが変化するものである．

3.3.9.1

サンプルプログラム

スライダの値によって画像の表示サイズが変わるプログラム kivy02Earth.py を示す．拡大，縮小する画像を常に中央に表示するため，Image オブジェクトを AnchorLayout で配置している．
プログラム：kivy02Earth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8# - - - - - モ ジ ュ ー ル の 読 込 み ----from kivy . app import App
from kivy . uix . boxlayout import BoxLayout
from kivy . uix . anchorlayout import AnchorLayout
from kivy . uix . image import Image
from kivy . uix . slider import Slider
from kivy . core . window import Window# - - - - - G U I と ア プ リ ケ ー シ ョ ン の 定 義 ----# イベントのコールバック
def onValueChange ( self , v ):im . size_hint = ( sl . value , sl . value )# GUIの構築

185

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

root = BoxLayout ( orientation = ’ vertical ’)# 画像とそのレイアウト
anchor = AnchorLayout ()im = Image ( source = ’ Earth . jpg ’)anchor . add_widget ( im )# スライダsl = Slider ( min =0.0 , max =1.0 , step =0.01)
sl . size_hint = ( 1.0 , 0.1 )sl . value = 1.0
sl . bind ( value = onValueChange )root . add_widget ( anchor )root . add_widget ( sl )# アプリケーションのクラス
class kivy02 ( App ):def build ( self ):return root
# ウィンドウの色とサイズ
Window . size = (500 ,550)# アプリ起動
print ( im . texture_size )ap = kivy02 ()ap . run ()# 画像サイズの調査

全体の概要：
最上位のレイアウト（垂直の BoxLayout）である root は，画像表示部とスライダを収めるものである．Image オ
ブジェクト im は AnchorLayout オブジェクト anchor に収められており，その内部で im の size hint を調整することで表示サイズを調節している．
このプログラムを実行した様子を図 23 に示す．

スライダに連動して画像の表示サイズが変わる

図 23: kivy02Earth.py の実行例

3.4

Canvas グラフィックス

ウィジェット（Widget）には canvas 要素があり，これに対してグラフィックスの描画ができる．先の「3.2.2 アプリ
ケーション構築の例」（p.175）でも少し説明した通り，canvas に対して色や図形などを追加することで描画ができる．

Widget を使用するには，必要なモジュールを，from kivy.uix.widget import Widgetとして読込み，これの canvas に対して Graphics を描画する．基本的な Graphics オブジェクトには Color，Line，Rectangle，Ellipse があり，それらを使用する際は kivy.graphics からインポートする．
Graphics モジュールを読み込む例
from kivy.graphics import Color, Line, Rectangle, Ellipse
186こうすることで，複数の Graphics のモジュールを読み込むことができる．

3.4.1

Graphics クラス

以下に紹介する Graphics オブジェクトを canvas に対して add メソッドで登録して描画する．

Kivy の座標系は他の多くの GUI ライブラリと異なり，上下の方向が逆である．
（図 24）

図 24: Kivy の座標系
また Kivy 以外の多くの GUI ライブラリはオブジェクトの配置を決める際，オブジェクトの左上の位置を指定する
が，Kivy では Graphics オブジェクトの左下の位置を配置座標（pos の値）とする．

3.4.1.1

Color

描画色を指定するためのオブジェクトのクラスである．
コンストラクタ：

Color( Red, Green, Blue, Alpha )引数は全て 0〜1.0 の範囲の値である．Alpha は不透明度を指定するもので，1.0 を指定すると，完全に不透明になる．

3.4.1.2

Line

折れ線を描画するためのオブジェクトのクラスである．
コンストラクタ：Line( points=座標リスト, width=線幅 )canvas 上の座標，(x1 , y1 ), (x2 , y2 ), · · · , (xn , yn ) を結ぶ折れ線を，線の幅 width で描画する．描画座標リスト
は [x1 , y1 , x2 , y2 , · · · , xn , yn ] とする．

3.4.1.3

Rectangle

長方形領域を描画するためのオブジェクトのクラスである．canvas 上に画像を表示する場合にも Rectangle を使用
する．
コンストラクタ 1：

Rectangle( pos=(描画位置の座標), size=(横幅, 高さ) )canvas 上の pos で指定した座標に，size で指定したサイズの長方形を描く．
コンストラクタ 1：

Rectangle( pos=(描画位置の座標), size=(横幅, 高さ),
texture=テクスチャオブジェクト )canvas 上の pos で指定した座標に，size で指定したサイズでテクスチャオブジェクトを描く．
テクスチャは canvas に画像を表示する際の標準的なオブジェクトであり，これの使用に際しては，下記のようにして必要なモジュールを読み込んでおく．

from kivy.graphics.texture import Texture
先に，「3.3.9 画像：Image」（p.185）で画像を読み込んで保持するウィジェットである Image について説明したが，テクスチャオブジェクトはこの Image オブジェクトから texture プロパティとして取り出すことができる．

187

3.4.1.4

Ellipse

楕円を描画するためのオブジェクトのクラスである．
コンストラクタ：

Ellipse( pos=(描画位置の座標), size=(横幅, 高さ) )canvas 上の pos で指定した座標に，size で指定したサイズの楕円を描く．

この他にも Bezier オブジェクトもあり，多角形や曲線を描くことができる，
サンプルプログラム

3.4.2
3.4.2.1

正弦関数のプロット

canvas グラフィックスを使うと，簡単に数学関数の軌跡がプロットできる．
プログラム：kivy04-1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----import mathfrom kivy . app import App
from kivy . uix . widget import Widget
from kivy . graphics import Color , Rectangle
from kivy . core . window import Window# - - - - - ア プ リ ケ ー シ ョ ン の 構 築 ----class kivy04 ( App ):def build ( self ):return root
root = Widget ()root . canvas . add (Color (1 ,0 ,0 ,1) )x = 0.0
while x < 6.28:
y = 100.0* math . sin ( x )root . canvas . add ( Rectangle ( pos =(32.0* x +5.0 , y +105.0) , size =(3 ,3) ) )x += 0.005# アプリの実行
Window . size = (210 ,210)
kivy04 (). run ()このプログラムの実行結果を図 25 に示す．

図 25: kivi04-1.py の実行結果

3.4.2.2

各種図形，画像の表示

長方形，楕円，折れ線，テクスチャ画像を表示するプログラム kivy04-2.py を示す．

188

プログラム：kivy04-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----from kivy . app import App
from kivy . uix . widget import Widget
from kivy . uix . image import Image
from kivy . graphics import Color , Line , Rectangle , Ellipse
from kivy . core . window import Window# - - - - - ア プ リ ケ ー シ ョ ン の 構 築 ----class kivy04 ( App ):def build ( self ):return root
# 画像の読込みとテクスチャの取り出し
im = Image ( source = ’ Earth . jpg ’);
tx = im . texture
root = Widget ()# 長方形の描画
root . canvas . add (root . canvas . add (# 画像の描画
root . canvas . add (root . canvas . add (# 楕円の描画
root . canvas . add (root . canvas . add (# 折れ線の描画
root . canvas . add (root . canvas . add (Color (1 ,0 ,0 ,1) )Rectangle ( pos =(10 ,210) , size =(350 ,100)) )Color (1 ,1 ,1 ,1) )Rectangle ( pos =(0 ,0) , texture = tx , size =(210 ,200)) )Color (0 ,1 ,0 ,1) )Ellipse ( pos =(200 ,10) , size =(170 ,170)) )Color (1 ,1 ,1 ,1) )Line ( width =10 , points =[580 ,25 ,400 ,25 ,580 ,160 ,400 ,290 ,580 ,290]) )# スクリーンショット
def save_shot ( self , t ):# 方 法 -1
Window . screenshot ( name = ’ kivy04 -2 -1. png ’)# 方 法 -2
self . export_to_png ( ’ kivy04 -2 -2. png ’)root . bind ( on_touch_up = save_shot )# アプリの実行
Window . size = (600 ,330)
kivy04 (). run ()このプログラムの実行結果を図 26 に示す．

図 26: kivi04-2.py の実行結果
プログラムの 32〜36 行目で Window のスクリーンショットの画像を保存する機能を実装している．

Window.screenshot(name=’kivy04-2-1.png’)としている部分がスクリーンショットのメソッドの 1 つ（screenshot メソッド）であり，その時点のウィンドウの様子を引数 ’name=’ に与えたファイル名の png 形式画像として保存する．
（保存時のファイル名には自動的に連番が付189

けられる）また，

self.export to png(’kivy04-2-2.png’)としている部分も同じ処理を実現するもので，これは Widget の表示内容を PNG 形式の画像として保存するものである．
（Widget に対する export to png メソッド）

3.4.3

フレームバッファへの描画

Canvas への描画とは別に，フレームバッファ（FBO）147 と呼ばれる固定サイズの領域への描画が可能である．フ
レームバッファからはピクセル値の取り出しが可能である．

FBO を使用するには次のようにして必要なモジュールを読み込んでおく．
from kivy.graphics import Fbo
FBO の生成時には，描画サイズを指定する．
例．FBO の生成

f = Fbo( size=(400,300) )これで画素サイズ 400 × 300 の FBO が f として生成される．FBO は描画対象の Widget の Canvas に登録しておく必要がある．
例．Widget オブジェクト root への FBO オブジェクト f の登録

root.canvas.add( f )更にこの後，FBO の texture プロパティを与えた Rectangle を Canvas に描画することで実際に FBO の内容が表示される．

FBO への描画は Canvas への描画とほぼ同じ方法（add メソッド）が使用できる．
FBO を用いて，タッチした場所の画素の値（ピクセル値）を取得するプログラム kivy04-3.py を次に示す．
プログラム：kivy04-3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み と モ ジ ュ ー ル の 初 期 設 定 ----from kivy . config import Config
Config . set ( ’ graphics ’ , ’ resizable ’ , False )# ウィンドウリサイズの禁止
from kivy . app import App
from kivy . uix . widget import Widget
from kivy . graphics import Color , Rectangle , Fbofrom kivy . core . window import Window# - - - - - ア プ リ ケ ー シ ョ ン の 構 築 ----class kivy04 ( App ):def build ( self ):return root
# 最上位ウィジェットの生成
root = Widget ()# フ レ ー ム バ ッ フ ァ の 生 成 と Canvasへの登録
fb = Fbo ( size =(300 , 150))
root . canvas . add ( fb )# フレームバッファへの描画
fb . add ( Color (1 , 0 , 0 , 1) )fb . add ( Rectangle ( pos =(0 ,0) , size =(100 , 150)) )fb . add ( Color (0 , 1 , 0 , 1) )fb . add ( Rectangle ( pos =(100 ,0) , size =(100 , 150)) )fb . add ( Color (0 , 0 , 1 , 1) )fb . add ( Rectangle ( pos =(200 ,0) , size =(200 , 150)) )fb . add ( Color (1 ,1 ,1 ,1) )fb . add ( Rectangle ( pos =(0 ,75) , size =(300 ,75)) )# フ レ ー ム バ ッ フ ァ の 内 容 を Canvasに描画
root . canvas . add ( Rectangle ( size =(300 , 150) , texture = fb . texture ) )147 OpenGL の描画フレーム

190

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# タッチ位置の色の取得（コールバック関数）
def pickColor ( self , t ):# ウィンドウサイズの取得(w , h ) = Window . size
# タッチ座標の取得(x , y ) = t . spos
# フレームバッファ上での座標
fbx = int ( w * x );fby = int ( h * y )# フレームバッファ上のピクセル値の取得
c = fb . get_pixel_color ( fbx , fby )print ( ’ 位 置 : \ t ’ ,( fbx , fby ) , ’\ t ピ ク セ ル : ’ , c )# コールバックの登録
root . bind ( on_touch_up = pickColor )# アプリの実行
Window . size = (300 ,150)
kivy04 (). run ()解説．

19〜20 行目で FBO を生成して Widget の Canvas に登録している．23〜30 行目で FBO に対して描画し，それを32 行目で Rectangle として Canvas に描画している．
アプリケーションのウィンドウ内をタッチ（クリック）するとコールバック関数 pickColor が呼び出され，その位置のピクセルを 43 行目で取得している．

3.4.3.1

ピクセル値の取り出し

FBO のピクセル値を取り出すには get pixel color メソッドを使用する．
書き方：

FBO オブジェクト.get pixel color(横位置, 縦位置)

ピクセル値を取り出す横位置と縦位置は，画像左下を基準とするピクセル位置である．得られたピクセル値は[赤, 緑, 青, α]のリストであり，各要素は 0〜255 の整数値である．
プログラム kivy04-3.py を実行すると図 27 のようなウィンドウが表示される．

図 27: kivy04-3.py の実行結果
このウィンドウ内をタッチ（クリック）すると，次の例のように，その位置のピクセル値を表示する．
位置:
位置:
位置:
位置:

3.4.3.2(143, 117)
(52, 39)(134, 34)
(256, 24)

ピクセル: [255, 255, 255, 255]
ピクセル: [255, 0, 0, 255]
ピクセル: [0, 255, 0, 255]
ピクセル: [0, 0, 255, 255]

イベントから得られる座標位置

Kivy のウィジェット上のイベントから取得される座標位置は，ウィジェットサイズの縦横を共に 1.0 に正規化した
位置であり，基準は左下である．このため，先のプログラム kivy04-3.py では，37〜41 行目にあるように FBO 上の座標位置を得るための変換処理をしている．

191

3.5

スクロールビュー（ScrollView）

大きなサイズのウィジェットやレイアウトを，それよりも小さなウィジェットやウィンドウの内部でスクロール表示
する場合はスクロールビュー（ScrollView）を使用する．これはスクロールバーを装備した矩形領域であり，内部のオブジェクト（子要素）を縦横に並行移動して表示するものである．
スクロールビューの使用に際して，次のようにして必要なモジュールを読み込む．

from kivy.uix.scrollview import ScrollView
スクロールビューは次のようにしてインスタンスを生成し，基本的にはウィジェットの 1 つとして扱う．
コンストラクタ：ScrollView()

コンストラクタにキーワード引数「bar width=幅」を与えることで，スクロールバーの幅を設定することができる．
ここではサンプルプログラムを示しながらスクロールビューの使用方法について説明する．
【サンプルプログラム】
図 28 のような，縦横にたくさんのボタンが配置されたウィジェットをスクロール表示するアプリケーションプログ
ラム kivy06.py を考える．

→(a) 多量のボタンが並んでいる(b) マウスやタッチデバイスでスクロール

図 28: 縦横に並んだボタンパネルのスクロール
基本的な考え方：
スクロールビューよりも大きなサイズのウィジェットを，スクロールビューに子要素として登録する．次に示すプ
ログラム kivy06.py では，多量のボタンを配置した巨大な BoxLayout を生成して，それをスクロールビューに登録している．
プログラム：kivy06.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8###### 必 要 な パ ッ ケ ー ジ の 読 込 み # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #from kivy . app import App
from kivy . uix . boxlayout import BoxLayout
from kivy . uix . button import Button
from kivy . uix . scrollview import ScrollView
from kivy . core . window import Window###### G U I の 構 築 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## ウィンドウのサイズ
Window . size = (320 ,240)# 最上位ウィジェット（スクロールビュー）の生成
root = ScrollView ( bar_width =10 )# 大きいボックスレイアウトの作成
bx = BoxLayout ( orientation = ’ vertical ’ ,size_hint =( None , None ) ,# サイズに関して親の制御を受けない設定
size =(1040 ,1500) )# 1040 × 1 5 0 0 の 固 定 サ イ ズ# A0〜Z49 の ボ タ ン を 生 成 （1300 個 ）
al = [ chr ( i ) for i in range (65 , 65+26)]# 0 〜49 行 の ボ タ ン 配 列 を 生 成192# アルファベットのリスト

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

for m in range (50):bx2 = BoxLayout ( orientation = ’ horizontal ’ )# An〜Znの横方向のボタン生成（26個）
for n in al :# 40 × 3 0 の サ イ ズ の ボ タ ン を 生 成
bx2 . add_widget ( Button ( text = n + str ( m ) , font_size =12 ,size_hint =( None , None ) , size =(40 ,30) ) )bx . add_widget ( bx2 )root . add_widget ( bx )###### ア プ リ ケ ー シ ョ ン の 構 築 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## アプリケーションのクラス
class kivy06 ( App ):def build ( self ):return root
# アプリケーションの実行
kivy06 (). run ()解説

16〜18 行目で生成した大きなサイズの BoxLayout である bx に多量のボタンを配置して，それを，13 行目で生成したスクロールビュー root に 31 行目で登録している．

23〜30 行目は多量のボタンを生成している部分である．An〜Zn（n は整数値）の 26 個のボタンを生成して，それらを水平方向（行）の BoxLayout である bx2 に登録して，それを垂直方向の BoxLayout である bx に次々と登録し
ている．

3.5.1

ウィジェットのサイズ設定

通常の場合は，階層的に構築されたウィジェット群のサイズは自動的に調整される．これは，親ウィジェットに収まるように子ウィジェットのサイズを調整するという Kivy の機能によるものであるが，先のプログラム kivy06.py では，ウィジェットサイズの自動調整の機能に任せることなく，大きなサイズのウィジェット（1,040 × 1,500 のサイズの BoxLayout）を生成している．これは，ウィジェット生成時のコンストラクタにキーワード引数

size hint=(None, None)
を与えることで可能となる．これと同時に，コンストラクタにキーワード引数

size=(横幅, 高さ)を与えて，具体的なサイズを設定する．

3.5.2

マウスのドラッグによるスクロール

ScrollView のスクロールバーをマウスのドラッグで操作するには ScrollView のコンストラクタにキーワード引数
scroll type=[’bars’]
を与える．

3.6

ウィンドウサイズを固定（リサイズを禁止）する設定

ウィンドウのリサイズを禁止（ウィンドウサイズを固定）するには，Kivy モジュールを読み込む先頭の位置で，次のように設定する．

from kivy.config import Config
Config.set(’graphics’,’resizable’,False)
これは Kivy の他のモジュールの読み込みに先立って記述すること．

3.7

Kivy 言語による UI の構築

実用的な GUI アプリケーションを構築する場合，GUI の構築と編集の作業に多くの時間と労力を要する．この部分の作業を容易にするために，インターフェースを構築するための特別な機能を使用することが，アプリケーション開193

発において一般的になって148 きている．Python と Kivy によるアプリケーション開発においても，インターフェース構築に特化した言語「Kivy 言語」（以下 Kv と略す）を使用することができ，開発効率を高めることができる．

Kv は Python とは異なる独自の言語であり，ここでは Kv 自体の基礎的な解説からはじめ，Kv で記述した GUI とPython で記述したプログラムとの相互関係について説明する．ただし本書は Kv の全般的なリファレンスではなく，
あくまで導入的な内容に留める．

Kivy 言語の基礎

3.7.1

Kv はレイアウトやウィジェットの階層構造であるウィジェットツリーを宣言的に記述する言語である．Kv で記述されたウィジェットツリーは可読性が高く，GUI の構造全体の把握が容易になる．

3.7.1.1

サンプルプログラムを用いた説明

まずは Kv を使用せずに GUI を構築したアプリケーションを示す．そして，同じ機能を持つアプリケーションのGUI を Kv で記述する例を示す．
サンプルとして示すアプリケーションは図 29 に示すようなものである．これは，1 段目にボタン，2 段目と 3 段目にテキスト入力を備えたもので，それらを BoxLayout で配置している．

1 段目がボタン，2 段目と 3 段目がテキスト入力

図 29: サンプルプログラムの実行例（起動時）
このアプリケーションの動作は次のようなものである．

(a) ボタンをタッチ（クリック）すると，3 段目にその旨のメッセージが表示される．
(b) 2 段目にテキスト入力すると，3 段目にその旨のメッセージが表示される．
これら動作の様子を図 30 に示す．

(a) ボタンをクリックしたときの反応(b) 2 段目にテキストを入力したときの反応

図 30: サンプルプログラムの実行例（動作）このアプリケーションを Kv を使用せずに構築したものがプログラム kivyKV01-1.py である．
プログラム：kivyKV01-1.py
1
2
3
4
5
6
7
8
9
10
11
12
13

# coding : utf -8# - - - - - 関 連 モ ジ ュ ー ル の 読 込 み ----from kivy . app import App
from kivy . uix . boxlayout import BoxLayout
from kivy . uix . button import Button
from kivy . uix . textinput import TextInput
from kivy . core . window import Window# - - - - - G U I の 構 築 ----# コールバック関数
def funcButton ( self ):tx2 . text = ’ result : Button1 was touched ’def funcTextInput ( self , v ):148 JavaFX における FXML や，それらを基本とする統合開発環境はまさにその例である．

194

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

tx2 . text = ’ result : ’ + self . text
# GUI
root = BoxLayout ( orientation = ’ vertical ’)
bt1 = Button ( text = ’ Button1 ’)
bt1 . bind ( on_release = funcButton )tx1 = TextInput ()tx1 . bind ( text = funcTextInput )tx2 = TextInput ()root . add_widget ( bt1 )root . add_widget ( tx1 )root . add_widget ( tx2 )# - - - - - ア プ リ ケ ー シ ョ ン 本 体 ----class KivyKV01App ( App ):def build ( self ):return root
# アプリの実行
Window . size = (300 ,100)
KivyKV01App (). run ()次に，このプログラムのインターフェース部を Kv で，その他を Python で記述することを考える．このアプリケー
ションの GUI の構成を階層的に示すと図 31 のようになる．

図 31: サンプルプログラムのウィジェットツリー

Kv で GUI を記述するとこの階層構造をそのまま反映した形となる．その Kv ファイル kivyKV01.kv を示す．
Kv ファイル：kivyKV01.kv
1
2
3
4
5
6
7
8
9
10
11
12

< RootW >:BoxLayout :orientation : ’ vertical ’Button :id : bt1
text : ’ Button1 ’
on_release : root . funcButton ( tx2 )TextInput :id : tx1
on_text :root . funcTextInput ( tx2 , tx1 . text )TextInput :id : tx2

このように，インスタンス名，プロパティ，イベントなどを含め，GUI の階層構造が簡潔に記述できる．この Kv ファ
イルを読み込んで GUI を実装するアプリケーション（Python プログラム）を kivyKV01.py に示す．
プログラム：kivyKV01.py
1
2
3
4
5
6
7
8
9
10
11
12

# coding : utf -8# - - - - - 関 連 モ ジ ュ ー ル の 読 込 み ----from kivy . app import App
from kivy . uix . boxlayout import BoxLayout
from kivy . core . window import Window# - - - - - G U I の 構 築 ----class RootW ( BoxLayout ):# コールバック関数
def funcButton ( self , tx2 ):tx2 . text = ’ result : Button1 was touched ’def funcTextInput ( self , tx2 , t ):

195

13
14
15
16
17
18
19
20
21
22

tx2 . text = ’ result : ’ + t# - - - - - ア プ リ ケ ー シ ョ ン 本 体 ----class KivyKV01App ( App ):def build ( self ):return RootW ()# アプリの実行
Window . size = (300 ,100)
KivyKV01App (). run ()解説：

Kv ファイルの 1,2 行目が，Python プログラムの 8 行目のクラス定義に対応している．Python プログラムでは，
GUI の最上位オブジェクトのクラス宣言と，コールバック関数の定義のみを記述しており，GUI の階層構造は全て Kv
ファイル内に記述している．
■ Kv ファイルにおけるクラスの定義’ ＜... ＞’ の記述は Kv における規則の記述である．この記述を応用することで，Python プログラム側のクラス定義に対応させることができる．
■ Kv ファイルにおける id

Kv ファイル内では，ウィジェットなどに識別名を与えるために ’id:’ を記述する．
（id により与えられた識別名は，
厳密にはインスタンス名ではない）■ Kv ファイルにおけるイベントハンドリング’ イベント名:’ に続いて呼び出すコールバック関数を記述する．このとき，Python プログラムの中のどこに記述された関数（メソッド）かを明示するために root という指定をしている．この root は Kv において記述対象のツリーの最上位を意味するものであり，Python 側プログラムでは，これを用いたクラス RootW （Python 側の 9 行目）が対応する．すなわち，root.funcButton(tx2,bt1.text) は，RootW クラスのメソッド funcButton を呼び出すことになる．

Kv 側からの関数（メソッド）呼び出しにおいては自由に引数を与えることができ，それを受ける Python 側の関数
（メソッド）の仮引数も対応する形に記述する．ただし Python 側の仮引数には，第 1 引数として，それを呼び出した
オブジェクト自身（self）を受け取る仮引数を記述する必要があり，結果として，引数の数が 1 つ多い記述となる．

3.7.1.2

Python プログラムと Kv ファイルの対応

先の例では，アプリケーションのクラス名が KivyKV01App なので，それに対応する Kv ファイルの名前は KivyKV01.kvとする．すなわち，アプリケーションのクラスの名前は，’ 任意の名前 App’と末尾に’App’ を付ける．そして対応する Kv ファイルの名前には，App の前の部分に拡張子 ’.kv’ を付けたものとす
る．こうすることで，アプリケーションの起動時に自動的に対応が取られて Kv ファイルが読み込まれる．

Builder クラスを用いた Kv ファイルの読込み
Builder クラスの load ﬁle メソッドを使用することで，先に説明した名前の制限にとらわれることなく，Python 側，
Kv 側共に自由にファイル名を付けることができる．Builder クラスを使用するためには次のようにして必要なモジュー
ルを読み込んでおく．

from kivy.lang.builder import Builder
この後，Python 側プログラムの冒頭で，Builder.load file( ’Kv ファイル名’ )とすることで，指定したファイルから Kv の記述を読み込むことができる．

196

時間によるイベント

3.8

Kivy には Clock モジュールがあり，ユーザからの入力以外に時間によるイベントハンドリングが可能である．すな
わち，設定された時間が経過したことをイベントとしてハンドリングすることができ，いわゆるタイマーの動作を実現することができる．Clock モジュールを使用するには次のようにして必要なものを読み込んでおく．

from kivy.clock import Clock
時間イベントのスケジュール

3.8.1

ClockEvent オブジェクトとして時間イベントを生成することで，指定した時間が経過した時点でコールバック関数を起動することができる．
《 コールバック関数のスケジュール 》
一度だけ：

Clock.schedule once ( コールバック関数, 経過時間 )繰り返し：

Clock.schedule interval ( コールバック関数, 経過時間 )この結果，ClockEvent オブジェクトが返される．経過時間の単位は「秒」であり，浮動小数点数で表現する．コー
ルバック関数は仮引数を 1 つ取る形で定義しておく．コールバック関数には起動時に経過時間が引数として渡される．コールバック関数は戻り値として True を返すように定義するが，False を返す形にすると schedule intervalによってスケジュールされた時間イベントがキャンセルされる．

schedule interval によってコールバック関数の繰り返し起動がスケジュールされた場合，得られた ClockEvent オブジェクトに対して cancel メソッドを使用することで，スケジュールを解除（キャンセル）することができる．また，Clock.unschedule(スケジュールされた ClockEvent)とすることでもキャンセルできる．
時間イベントの実装例は「3.9.4 スワイプ」（p.202）のところで紹介する．

GUI 構築の形式

3.9

Kivy は通常の PC だけでなく，スマートフォンやタブレット PC といった携帯情報端末のためのアプリケーション
開発を視野に入れているため，独特の UI デザインを提供する．例えば，複数のウィンドウを同時に表示する形式ではなく，1 つのウィンドウ内で，UI をまとめたスクリーンを切り替える形式などが特徴的である．
ここでは，実用的な UI インターフェースを構築するためのいくつかの形式について説明する．
スクリーンの扱い：

3.9.1

Screen と ScreenManager

Kivy では，UI の 1 つのまとまりを Screen として扱い，それらをスライドのようにして切り替えることが可能である．Screen オブジェクトには各種のレイアウトオブジェクトを登録することができ，各々のレイアウトにはこれまで説明した方法で UI を構築する．複数作成した Screen オブジェクトは 1 つの ScreenManager オブジェクトに登録して管理する，ScreenManager に登録されたスクリーンは transition によって切り替えることができる．

ScreenManager，Screen を使用するには，次のようにして必要なモジュールを読み込んでおく．
from kivy.uix.screenmanager import ScreenManager, Screen
3.9.1.1

ScreenManager

ScreenManager オブジェクトは複数の Screen を登録管理するもので，次のようにして生成する．
sm = ScreenManager()
この例では，生成された ScreenManager オブジェクトが sm に保持されている．

197

3.9.1.2

ScreenScreen オブジェクトは，先の ScreenManager に登録して使用する．このオブジェクトが 1 つの UI スクリーンとなり，更にここにレイアウトオブジェクトなどを登録する．Screen オブジェクトは次のようにして生成する．

sc1 = Screen(name=識別名)「識別名」は Screen を識別するためのもので文字列として与える．生成した Screen オブジェクトは add widget メ
ソッドで ScreenManager オブジェクトに登録する．

ScreenManager オブジェクトのプロパティ current に Screen の識別名を与えることで表示する Screen を選択できる．また，transition プロパティの設定により，Screen が切り替わる様子を制御できる．

Screen の遷移の効果は，いわゆるスライドインであるが，その他の効果も設定できる．
参考）遷移の効果

Kivy の ScreenManager には表 27 のような様々な transition が用意されている．これらは ScreenManager オブジェ
クト生成時に設定するが，詳しくは巻末付録に挙げている Kivy のサイトを参照のこと．

遷移

表 27: 遷移効果の効果
効果SlideTransition

縦／横方向のスライディング（デフォルト）

SwapTransition

iOS のスワップに似た切り替え

FadeTransition

フェードイン／アウトによる切り替え

WipeTransition

ワイプによる切り替え

FallOutTransition

消え行くような切り替え

RiseInTransition

透明から不透明に変化するような切り替え

NoTransition

瞬時の切り替え

CardTransition

上に重ねるような切り替え

次に，図 32 のように，2 つのスクリーンを切り替え表示するプログラム kivy05-1.py を挙げて Screen の扱いについて説明する．

スクリーンをタッチすると，→スライディングが起こり，→次のスクリーンに切り替わる

図 32: スクリーンを切り替えるアプリケーションの実行例
プログラム：kivy05-1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----from kivy . app import App
from kivy . uix . screenmanager import ScreenManager , Screen
from kivy . uix . anchorlayout import AnchorLayout
from kivy . uix . label import Labelfrom kivy . core . window import Window# - - - - - ア プ リ ケ ー シ ョ ン ク ラ ス の 定 義 ----class kivy05 ( App ):def build ( self ):return root
# - - - - - G U I の 構 築 ----# ウィンドウのサイズ
Window . size = (300 ,100)

198

# スクリーンマネジャ
root = ScreenManager ()# スクリーン
sc1 = Screen ( name = ’ screen_1 ’)
sc2 = Screen ( name = ’ screen_2 ’)# レイアウトal1 = AnchorLayout ()al2 = AnchorLayout ()# ラベル
l1 = Label ( text = ’ This is Screen -1\ nSwitch to Screen -2 ’)
l2 = Label ( text = ’ This is Screen -2\ nSwitch to Screen -1 ’)# 組み立て
al1 . add_widget ( l1 )al2 . add_widget ( l2 )sc1 . add_widget ( al1 )sc2 . add_widget ( al2 )root . add_widget ( sc1 )root . add_widget ( sc2 )# 最初に表示されるスクリーン
root . current = ’ screen_1 ’

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# - - - - - ス ク リ ー ン 遷 移 の 処 理 ----# コールバック関数
def callbk1 ( self , t ):# screen -1 か ら screen -2 へroot . transition . direction = ’ left ’root . transition . duration = 3# ゆっくりroot . current = ’ screen_2 ’
def callbk2 ( self , t ):# screen -2 か ら screen -1 へroot . transition . direction = ’ right ’root . transition . duration = 0.4 # デ フ ォ ル ト
root . current = ’ screen_1 ’# ラベルオブジェクトに登録
l1 . bind ( on_touch_up = callbk1 )l2 . bind ( on_touch_up = callbk2 )# - - - - - ア プ リ ケ ー シ ョ ン の 実 行 ----ap = kivy05 ()ap . run ()解説

19〜35 行目でスクリーンと UI を構築している．41〜48 行目でスクリーンを切り替えるためのコールバック関数を定義して，Label オブジェクトに登録している．この例でわかるように，ScreenManager のプロパティ transition.direction
で遷移の方向を，transition.duration で遷移にかかる時間（秒）を設定する．

ScreenManager とは別に，より簡単にスワイプを実現する方法を「3.9.4 スワイプ」（p.202）のところで解説する．
3.9.2

アクションバー：

ActionBar

一般的な GUI アプリケーションで採用されているプルダウンメニューに近い機能を Kivy ではアクションバー（ActionBar）という形で実現する．ActionBar を構築するために必要なクラスは次に挙げる 5 つのものである．

ActionBar，ActionView，ActionPrevious，ActionGroup，ActionButton
これらのクラスを使用するために，必要なモジュールを次のようにして読み込む．

from kivy.uix.actionbar import ActionBar, ActionView, ActionPrevious, ￥ActionGroup, ActionButton
ここでは，よく知られた GUI における「メニューバー」「メニュー」「メニュー項目」の構成に対応させる形でActionBar の構築について説明する．
一般的に「メニューバー」と呼ばれるものは，例えば「ファイル」「編集」…といった「メニュー」を配置しており，
それら各メニューをクリックするとプルダウンメニューが表示されて，その中に「新規」
「開く」
「保存」
「閉じる」…
といった「メニュー項目」が並んでいる．この場合の「メニューバー」は Kivy の ActionBar に相当する．ActionBarにはまず ActionView を登録して，それに対して ActionPrevious, ActionGroup を登録する．この ActionGroup が一般的な「メニュー」に相当する．その後 ActionGroup に対していわゆる「メニュー項目」に相当する ActionButton を

199

必要なだけ登録する．

ActionBar を構築する様子を階層的に示すと次のようになる．
【ActionBar の構築】

ActionBar（「メニューバー」に相当）|+- ActionView|+- ActionPrevious（タイトルの表示など）|+- ActionGroup（「メニュー」に相当）|+- ActionButton （「メニュー項目」に相当）|+- ActionButton （「メニュー項目」に相当）|:
図 33 のような ActionBar を実装するアプリケーションを例に挙げて構築方法について説明する．

ButtonGroup（右下）をクリックすると， →ActionButton が表示される．

→

選択によるコールバック処理

図 33: ActionBar の実装例
これを実装したプログラムを kivy05-2.py に示す．
プログラム：kivy05-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----from kivy . app import App
from kivy . uix . actionbar import ActionBar , ActionView , ActionPrevious , \ActionGroup , ActionButton
from kivy . uix . boxlayout import BoxLayout
from kivy . uix . anchorlayout import AnchorLayout
from kivy . uix . textinput import TextInput
from kivy . core . window import Window# - - - - - ア プ リ ケ ー シ ョ ン ク ラ ス の 定 義 ----class kivy05 ( App ):def build ( self ):return root
# - - - - - G U I の 構 築 ----# ウィンドウのサイズ
Window . size = (400 ,200)# 最上位のレイアウト
root = BoxLayout ( orientation = ’ vertical ’)# テキストフィールド
txt = TextInput ()# アクションバー
acBar = ActionBar ()acView = ActionView ()acPrev = ActionPrevious ( title = ’ The Action Bar ’)acGrp = ActionGroup ( text = ’ Buttons ’ , mode = ’ spinner ’)acBtn1 = ActionButton ( text = ’ Button -1 ’)acBtn2 = ActionButton ( text = ’ Button -2 ’)acBtn3 = ActionButton ( text = ’ Button -3 ’)# 組み立てroot . add_widget ( txt )acGrp . add_widget ( acBtn1 )

200

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

acGrp . add_widget ( acBtn2 )acGrp . add_widget ( acBtn3 )acView . add_widget ( acPrev )acView . add_widget ( acGrp )acBar . add_widget ( acView )root . add_widget ( acBar )# コールバック関数
def clback1 ( self ):txt . text = ’ Button -1 is clicked . ’
def clback2 ( self ):txt . text = ’ Button -2 is clicked . ’
def clback3 ( self ):txt . text = ’ Button -3 is clicked . ’
acBtn1 . bind ( on_release = clback1 )acBtn2 . bind ( on_release = clback2 )acBtn3 . bind ( on_release = clback3 )# - - - - - ア プ リ ケ ー シ ョ ン の 実 行 ----ap = kivy05 ()ap . run ()解説

27〜33 行目で ActionBar 構築に必要なオブジェクトを生成している．ActionGroup（いわゆるメニュー）を生成する際に，キーワード引数 ’text=’ を与えることでグループ名を設定することができ，これが ActionBar 上に表示される．また，キーワード引数 mode=’spinner’ を与えると，ActionGroup クリック時に ActionButton （いわゆるメニュー項目）が「立ち上がるメニュー」として表示される．

3.9.3

タブパネル：

TabbedPanel

TabbedPanel を使用すると，いわゆる切り替えタブが実現できる．TabbedPanel には TabbedPanelItem オブジェ
クトを必要な数だけ登録する．各 TabbedPanelItem オブジェクトが個々のタブパネルであり，これにレイアウトオ
ブジェクトを配置することができる．
タブパネルを構築するには，次のようにして必要なモジュールを読み込んでおく．

from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
ここでは，図 34 のように，2 つのタブを切り替えるプログラムを例に挙げる．

タブの切り替え表示

図 34: TabbedPanel の実装例実装したプログラムを kivy05-3.py に示す．
プログラム：kivy05-3.py
1
2
3
4
5
6
7
8
9

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----from kivy . app import App
from kivy . uix . tabbedpanel import TabbedPanel , TabbedPanelItem
from kivy . uix . anchorlayout import AnchorLayout
from kivy . uix . label import Labelfrom kivy . core . window import Window# - - - - - ア プ リ ケ ー シ ョ ン ク ラ ス の 定 義 -----

201

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

class kivy05 ( App ):def build ( self ):return root
# タブパネルroot = TabbedPanel ()root . do_default_tab = False# タ ブ1ti1 = TabbedPanelItem ( text = ’ Tab1 ’)
lb1 = Label ( text = ’ Tab 1 ’)ti1 . add_widget ( lb1 )root . add_widget ( ti1 )# タ ブ2ti2 = TabbedPanelItem ( text = ’ Tab2 ’)
lb2 = Label ( text = ’ Tab 2 ’)ti2 . add_widget ( lb2 )root . add_widget ( ti2 )root . default_tab = ti1# - - - - - G U I の 構 築 ----# ウィンドウのサイズ
Window . size = (300 ,150)
ap = kivy05 ()ap . run ()解説

18,23 行目のように，TabbedPanelItem のオブジェクト生成時にキーワード引数 ’text=’ を与えることで，タブの見出しを設定できる．

3.9.4

スワイプ：

Carousel

Carousel による UI は ScreenManager による UI と似ているが，スワイプ機能が予め備わっており，ScreenManagerの transition を使用するよりも UI の実装が容易であることが特徴である．

Carousel オブジェクトにはレイアウトをはじめとするウィジェットを登録するが，それらは登録した順に順序付けされる．そして，Carousel オブジェクトに対して，load next，load previous といったメソッドを使用することで，登録されたウィジェット群を順番に（逆順に）「回転」させる149 ことができる．

Carousel を使用したプログラム kivy05-4.py を次に示す．
プログラム：kivy05-4.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# coding : utf -8# - - - - - 必 要 な パ ッ ケ ー ジ の 読 込 み ----from kivy . app import App
from kivy . uix . carousel import Carousel
from kivy . uix . label import Labelfrom kivy . clock import Clockfrom kivy . core . window import Window# - - - - - ア プ リ ケ ー シ ョ ン ク ラ ス の 定 義 ----class kivy05 ( App ):def build ( self ):return root
# Carouselの生成
root = Carousel ( direction = ’ right ’)
lb1 = Label ( text = ’ Slide - 1 ’)
lb2 = Label ( text = ’ Slide - 2 ’)
lb3 = Label ( text = ’ Slide - 3 ’)root . add_widget ( lb1 )root . add_widget ( lb2 )root . add_widget ( lb3 )root . loop = True
# 循環の切り替え指定

149 ”carousel”（英） は「回転木馬」という意味である．

202

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# - - - - - 自 動 ス ワ イ プ ----# コ ー ル バ ッ ク 関 数 （ 引 数 に は durationが与えられる）
def autoSwipe ( dt ):print ( dt )root . load_next ()return True
# Falseを返すとスケジュールがキャンセルされる# スケジュール
tm = Clock . schedule_interval ( autoSwipe , 3)
print ( type ( tm ))# 型の確認# 停止用コールバック関数
def cancelSwipe ( self , t ):print ( ’ 自 動 ス ワ イ プ が キ ャ ン セ ル さ れ ま し た ． ’ )Clock . unschedule ( tm )# キ ャ ン セ ル 方 法1#
tm . cancel ()# キ ャ ン セ ル 方 法2
root . bind ( on_touch_down = cancelSwipe )# - - - - - G U I の 構 築 ----# ウィンドウのサイズ
Window . size = (300 ,150)
ap = kivy05 ()ap . run ()解説

22 行目にあるように，Carousel オブジェクトの loop プロパティに True を設定すると，末尾のウィジェットの次
は先頭のウィジェットに戻るように順序付けされ，ウィジェット群を順番に回転させることができる．

203

4

実用的なアプリケーション開発に必要な事柄

4.1

日付と時間に関する処理

Python では日付や時刻，あるいは経過時間といった情報を扱うことができる．ここではそのためのモジュールである datetime モジュール，time モジュール，timeit モジュールについて解説する．

4.1.1

日付と時刻の取り扱い： datetime モジュール

日付と時刻の情報を扱うために datetime モジュールが標準的に提供されている．このモジュールは様々なクラスや関数を提供しており，

from datetime import *のように実行して当該モジュール内の全てのクラスや関数を読み込むことができるが，他のライブラリと併用する場
合に名前の衝突150 が起こることがあることに注意しなければならない．このモジュールが提供するクラスの内，特に datetime クラス，timedelta クラス，timezone クラスを用いることが多く，次のようにしてこれらクラスを選択的に読み込むと安全である．
例．モジュールの読み込み>>> from datetime import datetime, timedelta, timezone

Enter

以後の解説では，これらモジュールを読み込んだ状態を前提とする，

datetime モジュールで扱える情報は年，月，日，時，分，秒，マイクロ秒の 7 つの要素である．例えば現在時刻を取得するには now メソッドを使用する．
例．現在時刻の取得>>> datetime.now()
Enter←現在時刻の取得
datetime.datetime(2017, 5, 5, 13, 10, 25, 653093) ←処理結果
この例のように時間情報は datetime.datetime(...) という形式で（datetime クラスのオブジェクトとして）扱われる．

4.1.1.1

datetime オブジェクトの分解と合成

datetime オブジェクトを「日付のみ」のオブジェクト（date オブジェクト）と「日付なし時刻」のオブジェクト（time オブジェクト）に分解することができる．
例．時刻情報の分解（先の例の続き）>>> d = datetime.now()>>> dt = d.date()

Enter

Enter

>>> dtEnter
datetime.date(2017, 5, 5)>>> tm = d.time()Enter>>> tmEnter
datetime.time(13, 23, 16, 396945)←現在時刻の取得←日付のみの取り出し
←内容確認
←結果
←日付なし時刻の取り出し
←内容確認
←結果

このように，datetime オブジェクトに対して date メソッドや time メソッドを実行する．その結果，それぞれdatetime.date(...)，

datetime.time(...)という形式（それぞれ date クラス，time クラスのオブジェクト）で結果が得られる．またこれらを combine メソッドで連結して datetime オブジェクトを作成することもできる．
例．date オブジェクトと time オブジェクトの連結（先の例の続き）>>> datetime.combine(dt,tm)
Enter←日付と時刻を連結
datetime.datetime(2017, 5, 5, 13, 23, 16, 396945)←連結結果
now メソッドで現在時刻を取得することとは別に，指定した特定の日付，時間を構成することもできる．

150 詳しくは巻末付録「F.1 ライブラリの読込みに関すること」を参照のこと．

204

例．「1966 年 3 月 14 日」という日付と時刻の生成←日付情報の生成←得られたデータ>>> datetime(1966,3,14)Enter
datetime.datetime(1966, 3, 14, 0, 0)
4.1.1.2

文字列を datetime オブジェクトに変換する方法

strptime メソッドを使用すると，日付と時刻の情報を含んだ文字列から datetime オブジェクトを作成することがで
きる．
書き方：

strptime( 日付時刻を含んだ文字列, 書式文字列 )この関数は，第 1 引数に与えた「日付時刻を含んだ文字列」から第 2 引数「書式文字列」に沿った形で日付時刻を取り出し，結果を datatime オブジェクトとして返す．この関数の実行例を次に示す．
例．strptime 関数>>> datetime.strptime(’2022-03-14 13:15:10’,’%Y-%m-%d %H:%M:%S’)datetime.datetime(2022, 3, 14, 13, 15, 10)←得られたデータEnter

この例のように，書式文字列には「%」で始まる書式文字列を記述し，文字列中の各情報の場所を指定する．書式文字列として重要なものを表 28（p.206）に示す．
■ ISO8601 形式の日付，時刻の表現
日付と時刻の表現に関する国際規格に ISO8601 がある．これは
日付 T 時刻の形式である．例えば「2022 年 3 月 14 日 13 時 15 分 12 秒」は次のように表現される．

2022-03-14T13:15:12
Python 3.7 から datetime クラスに fromisoformat メソッドが導入され，この形式で表現された文字列から datetime
オブジェクトを作成することができる．
例．ISO8601 形式から datetime オブジェクトを作成する>>> datetime.fromisoformat(’2022-03-14T13:15:12’)Enter
datetime.datetime(2022, 3, 14, 13, 15, 12)←変換結果
4.1.1.3

datetime オブジェクトの差：← ISO8601 フォーマットを変換

timedelta

マイナス演算子「-」で 2 つの datetime オブジェクトの差を求めることで，2 つの時刻の間の時間差を取得することができる．
例．1966 年 3 月 14 日 13 時 15 分から 2017 年 5 月 5 日 14 時 00 分までの経過時間>>> d2 = datetime(2017,5,5,14,0)←日付情報 1966/03/14 13:15 の生成Enter>>> d1 = datetime(1966,3,14,13,15)←日付情報 2017/05/05 14:00 の生成Enter>>> td = d2 - d1
Enter
←経過時間の取得>>> tdEnter←値の確認
datetime.timedelta(days=18680, seconds=2700)←経過日数が「18680 日と 2700 秒」である
このように，自然な形の減算で時間差を取得することができ，結果はdatetime.timedelta( days=日数, seconds=秒数 )という形式（timedelta クラスのオブジェクト）で得られ，days，seconds，microseconds といった属性を持つ．
例．timedelta オブジェクトの属性（先の例の続き）>>> td.days
18680

Enter

>>> td.seconds
2700

Enter

>>> td.microseconds
0←日数← 18680 日←秒← 2700 秒

Enter←マイクロ秒←秒の小数点以下は 0注意）timedelta の days，seconds，microseconds 属性は事後で変更はできない．
（readonly attribute である）

205

timedelta を用いると「〜日後の日付」や「〜日前の日付」を算出することもできる．計算方法は，datetime オブ
ジェクトに対する timedelta オブジェクトの加算あるいは減算である．
例．1966 年 3 月 14 日 13 時 15 分から 18680 日と 2700 秒経過した日付と時刻>>> d1 = datetime(1966,3,14,13,15)>>> td = timedelta(18680, 2700)←日付情報 1966/03/14 13:15 の生成Enter←経過した日数と秒数の生成

Enter←日付の取得
←得られた日付>>> d1 + td
Enterdatetime.datetime(2017, 5, 5, 14, 0)

この例のように，timedelta(日数，秒数) の形151 で時間差を作成することもできる．

4.1.1.4

日付，時刻の書式整形

日付，時刻を書式整形して文字列で取得することができる．
例．日付，時刻の書式整形>>> d1 = datetime(1966,3,14,13,15)←日付情報の生成Enter>>> str(d1)Enter←文字列に変換’1966-03-14 13:15:00’←得られた文字列>>> d1.ctime()Enter←文字列（UNIX 形式，C 言語）に変換’Mon Mar 14 13:15:00 1966’←得られた文字列
このように str 関数の引数に datetime オブジェクトを与える．あるいは C 言語（UNIX）の形式で書式整形するには

ctime メソッドを用いる．更に strftime メソッドを使用すると，より自由な書式整形ができる．
例．strftime による書式整形←現在時刻の取得

Enter>>> d2 = datetime.now()>>> d2.strftime(’%Y %m %d %a %H %M %S %f’)
Enter ←書式整形’2018 05 26 Sat 12 57 46 243601’ ←整形結果の文字列
このように ‘%’ で記述した書式指定を strftime の引数に与えることによって書式整形ができる．書式指定の一部を表28 に示す．
（曜日や月名はロケール152 の設定の影響を受ける）
表 28: 日付，時刻の書式指定
書式 意味
書式

書式

意味

意味

%Y

年

%m

月

%d

日

%H

時

%M

分

%S

秒

%a

曜日（短縮）

%A

曜日

%f

マイクロ秒

%b

月名（短縮）%B

月名

Python 3.7 から datetime クラスに isoformat メソッドが導入され，datetime の値を ISO8601 形式の文字列に変換することができる．
例．datetime オブジェクトを ISO8601 形式に変換する>>> d = datetime.now()

Enter←現在時刻を取得>>> d.isoformat()Enter← ISO8601 形式に変換’2022-03-10T22:58:49.280558’←変換結果
4.1.1.5

datetime のプロパティ

datetime オブジェクトから各要素（年，月，日，時，分，秒，マイクロ秒）を取り出すための各種のプロパティがある．

151 timedelta のコンストラクタには第 3 引数としてマイクロ秒の値を与えることもできる．
152 詳しくは p.217「4.2 ロケール（locale）」参照のこと．

206

例．datetime からの要素の取り出しEnter>>> d = datetime.now()←現在の日付，時刻の取得

>>> d
Enter
←確認
datetime.datetime(2017, 5, 5, 14, 54, 23, 305326)←表示結果>>> d.year
2017

Enter

←「年」の取得←表示結果（年）>>> d.minute
54

Enter

←「分」の取得←表示結果（分）>>> d.month
5

Enter

←「月」の取得←表示結果（月）>>> d.second
23

Enter

←「秒」の取得←表示結果（秒）>>> d.microsecond Enter ←「マイクロ秒」の取得>>> d.day
5

Enter←「日」の取得←表示結果（日）>>> d.hour
14

Enter

←「時」の取得←表示結果（時）4.1.1.6←表示結果（マイクロ秒）

305326

タイムゾーンについて

世界各地の日付と時刻は協定世界時（UTC）153 を基準にしている．datetime クラスの now メソッドは使用している計算機のローカルタイムを取得するものであり，日本国内の計算機でこれを実行すると，UTC の時刻から 9 時間
進んだもの（日本時間）が得られる．UTC の現在時刻を取得するには utcnow メソッドを使用する．次に示す例は日本国内の計算機環境で utcnow，now メソッドを実行したものである．
例．UTC とローカルタイムの取得>>> d1 = datetime.utcnow(); d2 = datetime.now()Enter← UTC と日本時間を同時に取得>>> d1Enter← UTC の日付時刻を確認
datetime.datetime(2022, 3, 10, 12, 18, 33, 645845)← UTC の日付時刻>>> d2Enter←日本時間の日付時刻を確認
datetime.datetime(2022, 3, 10, 21, 18, 33, 645845)←日本時間の日付時刻

日本時間の方が UTC よりも 9 時間進んでいることがわかる．
■ datetime オブジェクトのタイムゾーンの属性

datetime オブジェクトにはタイムゾーンを表す tzinfo 属性がある．この属性の値は timezone クラスのオブジェク
トを保持する．timezone クラスのオブジェクトはローカルタイムを表現するもので，生成する際に UTC との時間差を timedelta オブジェクトとして与える．timezone オブジェクトを単体で作成する例を次に示す．
例．timezone オブジェクトの作成>>> from datetime import datetime, timedelta, timezone>>> z = timezone( timedelta(hours=9) )

Enter

Enter

←必要なクラスの読込み← 9 時間の時間差のタイムゾーンを作成

>>> z
Enter
←内容確認
datetime.timezone(datetime.timedelta(seconds=32400))←得られたタイムゾーン情報

この例では UTC からの時間差が 9 時間であるタイムゾーンの情報を変数 z に得ている．次に，timezone オブジェク
トをタイムゾーンの属性として持つ datetime オブジェクトを作成する例を示す．
例．タイムゾーン属性を持つ現在時刻の取得（先の例の続き）>>> d = datetime.now( tz=z )Enter←タイムゾーン情報を与えて現在時刻を取得

>>> d
Enter
←内容確認
datetime.datetime(2022, 3, 11, 12, 37, 13, 250186,←得られた datetime オブジェクト
tzinfo=datetime.timezone(datetime.timedelta(seconds=32400)))
この例のように now メソッドの引数に「tz=タイムゾーン情報」を与えることで，得られる datetime オブジェクトにタイムゾーンの属性（tzinfo）を与えることができる．

tzinfo 属性は datetime オブジェクトを作成する段階で与えるものであり，事後に与えることはできない．
（次の例）

153 グリニッジ標準時（GMT）を置き換えるものとして使用されている．

207

例．tzinfo 属性を事後に与える試み（先の例の続き）>>> d = datetime.now()>>> d.tzinfo = z

Enter

Enter

←タイムゾーン情報を与えずに現在時刻を取得← tzinfo 属性を設定しようとすると…

Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
AttributeError: attribute ’tzinfo’ of ’datetime.datetime’ objects is not writable
このように，既存の datetime オブジェクトの tzinfo 属性は変更できない旨のエラーが発生する．また，タイムゾー
ンを指定せずに作成した datetime オブジェクトの tzinfo 属性は None となる．
（次の例）
例．タイムゾーン属性を持たない datetime オブジェクトの tzinfo 属性（先の例の続き）>>> print( d.tzinfo )
Enter
None
←参照結果

← tzinfo 属性の確認

datetime クラスのコンストラクタに引数「tzinfo=タイムゾーン情報」を与えることで tzinfo 属性を与えることが
できる．
（次の例）
例．コンストラクタにタイムゾーンを与える（先の例の続き）>>> datetime(2022,3,14,13,15,12, tzinfo=z )Enterdatetime.datetime(2022, 3, 14, 13, 15, 12,←得られた datetime オブジェクト
tzinfo=datetime.timezone(datetime.timedelta(seconds=32400)))
ISO8601 形式はタイムゾーンを扱うことができる．
表記：

日付 T 時刻± UTC からのオフセット

この表記による文字列を fromisoformat メソッドで datetime に変換する例を次に示す．
例．タイムゾーン指定のある ISO8601 表記から datetime オブジェクトを生成する>>> datetime.fromisoformat(’2022-03-14T13:15:12+09:00’) Enter ←タイムゾーン付き ISO8601 表記
datetime.datetime(2022, 3, 14, 13, 15, 12,←得られた datetime オブジェクト
tzinfo=datetime.timezone(datetime.timedelta(seconds=32400)))■ タイムゾーンの変換

datetime オブジェクトに対して astimezone メソッドを実行することでタイムゾーンを変換することができる．
例．日本時間の取得>>> djpn = datetime.now( tz=timezone(timedelta(hours=9)) ) Enter ←現在時刻の取得（日本時間）>>> djpn
Enter←確認
datetime.datetime(2022, 3, 11, 14, 58, 2, 874671,←得られた datetime オブジェクト
tzinfo=datetime.timezone(datetime.timedelta(seconds=32400)))
この例では日本時間の datetime オブジェクトが変数 djpn に得られている．これを UTC に変換する例を次に示す．
例．UTC への変換（先の例の続き）>>> dutc = djpn.astimezone( tz=timezone(timedelta(hours=0)) )Enter← UTC に変換>>> dutc
Enter←確認
datetime.datetime(2022, 3, 11, 5, 58, 2, 874671, tzinfo=datetime.timezone.utc) ← UTC 時刻
先に得られた日本時間よりも 9 時間遅い時刻（UTC）が変数 dutc に得られている．また，UTC のタイムゾーンは実行例にあるように「datetime.timezone.utc」と表されている．これはtimezone(timedelta(hours=0))と同じものを意味する．
■ zoneinfo モジュール

Python3.9 からタイムゾーンを扱うための zoneinfo モジュールが標準添付154 されており，タイムゾーン ID 155 が使用できる．具体的には，zoneinfo モジュールの ZoneInfo クラスのオブジェクトとしてタイムゾーン情報を扱う．
（次
154 Windows 環境でこれを使用する場合は tzdata モジュールをインストールしておく必要がある．

PIP コマンドを使用する場合は「pip install tzdata」などとしてインストールする．
155 タイムゾーンを地域，国などの名前で表現した文字列．IANA が規定している．

208

の例）
例．日本時間のタイムゾーンを作成する>>> z = ZoneInfo(’Asia/Tokyo’)← ZoneInfo クラスの読込みEnter>>> from zoneinfo import ZoneInfo←タイムゾーン ID ’Asia/Tokyo’ のタイムゾーンを作成

Enter

>>> z
Enter
←確認
zoneinfo.ZoneInfo(key=’Asia/Tokyo’)←得られたタイムゾーン

この例における ’Asia/Tokyo’ が日本時間のタイムゾーン ID であり，これを元にしてタイムゾーンを変数 z に作成している．次に，これを与えて datetime オブジェクトを作成する例を示す．
例．ZoneInfo オブジェクトを使用して datetime オブジェクトを作成する（先の例の続き）>>> from datetime import datetime, timedelta, timezone>>> djpn = datetime.now( tz=z )Enter←必要なクラスの読込み←タイムゾーンを与えて現在時刻を取得

Enter>>> djpn
Enter←確認
datetime.datetime(2022, 3, 11, 16, 10, 7, 276301,
tzinfo=zoneinfo.ZoneInfo(key=’Asia/Tokyo’))←得られた datetime オブジェクト

これを UTC 時刻に変換して内容を確認する．
例．先の例の時刻を UTC に変換する（先の例の続き）>>> dutc = djpn.astimezone( tz=timezone.utc )Enter← UTC に変換>>> dutc
Enter←確認
datetime.datetime(2022, 3, 11, 7, 10, 7, 276301, tzinfo=datetime.timezone.utc)
先に作成した djpn よりも dutc の方が 9 時間遅れており，djpn が日本時間を正しく表現していることがわかる．

zoneinfo モジュールは，使用可能な全てのタイムゾーン ID をセットの形で取得する available timezones 関数を提供する．
例．使用可能な全てのタイムゾーン ID を出力する>>> from zoneinfo import available timezonesEnter←関数 available timezones の読込み>>> available timezones()
Enter ←実行{’Asia/Yangon’, ’America/Denver’, ’America/Matamoros’, ’Atlantic/Azores’,’Australia/Queensland’, ’America/Indiana/Petersburg’, ’America/Campo Grande’,：（途中省略）：’America/Indiana/Marengo’, ’Africa/Dar es Salaam’, ’Etc/GMT+9’, ’Asia/Baku’,’America/Bahia Banderas’, ’Africa/Bangui’, ’Eire’, ’GB-Eire’, ’Europe/Zagreb’}
課題．関数 available timezones() が返すセットを元にして，タイムゾーン ID 毎に UTC との時差を出力する処理を実装せよ．
■ 処理系のローカルタイムゾーンの取得

Lennart Regebro 氏が開発した tzlocal モジュール156 を使用することで処理系のローカルタイムゾーンを取得することができる．具体的には，このモジュールが提供する関数 get localzone，get localzone name を使用する．
例．日本国内の計算機環境でローカルタイムゾーンを調べる>>> import tzlocal

Enter←モジュールの読み込み>>> tzlocal.get localzone()Enter
zoneinfo.ZoneInfo(key=’Asia/Tokyo’)←ローカルタイムゾーンの取得 (1)←得られたタイムゾーン (1)>>> tzlocal.get localzone name()Enter’Asia/Tokyo’←得られたタイムゾーン (2)←ローカルタイムゾーンの取得 (2)

この例からわかるように，get localzone 関数は前述の ZoneInfo クラスのオブジェクトとして，get localzone name
156 Python の標準ライブラリではないので，OS のコマンド「pipinstall tzlocal」を実行するなどして，当該計算機環境にインストールする必要がある．公式インターネットサイト：https://pypi.org/project/tzlocal/

209

関数は文字列としてローカルタイムゾーンを返す．

4.1.2

time モジュール

先に説明した datetime モジュールと異なり，UNIX 時間に基づいて日付や時刻を取り扱うものとして time モ
ジュールがある．UNIX 時間とは，1970 年 1 月 1 日 0 時 0 分 0 秒（UTC）157 からの秒数でありエポック秒（seconds

since the epoch）と呼ぶこともある．
time モジュールが提供する関数は，UNIX 環境の C 言語の API に由来するものが多い．
このモジュールは使用に先立って，次のようにしてシステムに読み込んでおく必要がある．

import time
4.1.2.1

基本的な機能■ 現在のエポック秒の取得

time 関数で現在のエポック秒を取得することができる．
例．現在のエポック秒の取得>>> import timeEnter>>> t = time.time()←モジュールの読み込み

Enter←現在のエポック秒の取得>>> print(t,’(sec), type:’,type(t))
1690616550.793217 (sec), type:←値とその型を調べる

Enter<class ’float’>←浮動小数点数である■ 日付，時刻の情報の取得
エポック秒を年，月，日，時，分，秒などの情報から成る struct time オブジェクトに変換するには gmtime，localtime
関数を使用する．
（前者は UTC，後者はローカルタイムである）これら関数を引数なしで実行すると，その時点のエポック秒に対する struct time オブジェクトを返す．
先の例で得られた変数 t の値を struct time オブジェクトに変換する例を次に示す．
例．エポック秒を struct time に変換する（先の例の続き）>>> time.gmtime( t )Enter← UTC の解釈で変換
time.struct time(tm year=2023, tm mon=7, tm mday=29, tm hour=7,
tm min=42, tm sec=30, tm wday=5, tm yday=210, tm isdst=0)← struct time オブジェクト>>> time.localtime( t )Enter←ローカルタイムの解釈で変換
time.struct time(tm year=2023, tm mon=7, tm mday=29, tm hour=16,
tm min=42, tm sec=30, tm wday=5, tm yday=210, tm isdst=0)← struct time オブジェクト

struct time オブジェクトの内部の要素はインデックス（スライス）を与えて参照することができる．次の例は，
struct time オブジェクトをイテラブルとして for 文で扱うものである．
例．インデックスを指定して struct time オブジェクトの内部の要素を参照する（先の例の続き）>>> for i,e in enumerate(time.localtime( t )): Enter...
print(’st[’,i,’]=’,e,’ ’,sep=’’,end=’’)... else: print()
...

Enter

←反復の記述（ここから）←反復の記述（ここまで）

st[0]=2023 st[1]=7 st[2]=29 st[3]=16 st[4]=42 st[5]=30 st[6]=5 st[7]=210 st[8]=0
struct time オブジェクトの内部の要素は属性を指定して参照することもできる．
例．struct time オブジェクトの「年」の属性 tm year の参照（先の例の続き）>>> st = time.localtime( t )Enter← struct time オブジェクトを取得し>>> st.tm year
Enter←「年」の属性 tm year を参照する
2023←「年」の値が得られている
struct time オブジェクトの各属性を表 29 に示す．
157 この時刻を UNIX エポック（the epoch）と呼ぶ．

210

←出力

インデックス

属性

0
1
2
3
4
5
6
7
8
N/A
N/A

表 29: struct time オブジェクトの属性
解説

tm yeartm montm mday
tm hourtm mintm sectm wday
tm yday
tm isdst
tm zonetm gmtoff

年
月（[1,12] の間の数）
日（[1,31] の間の数）
時（[0,23] の間の数）
分（[0,59] の間の数）
秒（[0,61] の間の数）
曜日（[0,6] の間の数，月曜が 0）
年内の日（[1,366] の間の数）
夏時間（無効:0，有効:1，不明:-1）
タイムゾーンの短縮名（タイムゾーン ID ではない）

UTC から東方向へのオフセット（秒）注）tm sec は整数値であり，小数点以下は無い

属性 tm zone の値はタイムゾーン ID ではない．
（次の例参照）
例．tm zone 属性の参照（先の例の続き）>>> st.tm zone
’ 東京 (標準時)’Enter←このような表現となっている■ 日付，時刻の値からエポック秒を得る方法
ローカルタイムを表す struct time オブジェクトをエポック秒に変換するには mktime 関数を用いる．
例．struct time オブジェクトをエポック秒に変換する（先の例の続き）>>> time.mktime( st )Enter
←先の st をエポック秒に変換する
1690616550.0←エポック秒（小数点以下が切り捨てられていることに注意）
mktime 関数の引数には 9 個の要素（struct time の各要素に対応する）を持つタプルを与えることもできる．
例．タプルをエポック秒に変換する（先の例の続き）>>> time.mktime( (2023,7,29,16,42,30,5,210,0) )Enter←引数にタプルを与える
1690616550.0←エポック秒（小数点以下が切り捨てられていることに注意）
参考）UTC を表す struct time オブジェクトをエポック秒に変換するには calendar モジュールの timegm 関数を用いる．
例．UTC の struct time オブジェクトをエポック秒に変換する>>> import timeEnter>>> t = time.time()← time モジュールの読込み←現在のエポック秒を取得

Enter

>>> t
Enter
←確認
1690702599.2582412←浮動小数点数>>> g = time.gmtime( t )Enter>>> import calendarEnter←それを UTC の struct time に変換← calendar モジュールの読込み>>> calendar.timegm( g )Enter
1690702599←整数値← UTC の struct time をエポック秒に変換

timegm 関数の戻り値が整数値であることに注意．
4.1.2.2

日付，時刻を表す文字列表現■ エポック秒を可読な文字列に変換する関数 ctime
書き方：

ctime( t )エポック秒 t をローカルタイム解釈で ’ 曜日

月

日

時:分:秒

211

年’ の文字列に変換したものを返す．

例．ctime による可読な文字列への変換>>> import time

←モジュールの読込みEnter>>> t = time.time()Enter>>> time.ctime( t )Enter’Sun Jul 30 12:30:19 2023’←現在のエポック秒を取得←それを文字列に変換←変換結果■ struct time の内容を可読な文字列に変換する関数 asctime
書き方：

asctime( st )struct time オブジェクト st の内容を ’ 曜日 月 日 時:分:秒 年’ の文字列に変換したものを返す．
例．asctime による可読な文字列への変換（先の例の続き）←エポック秒をローカルタイムの struct time オブジェクトに変換>>> st = time.localtime( t ) Enter>>> time.asctime( st )Enter
’Sun Jul 30 12:30:19 2023’←上で得た struct time オブジェクトを文字列にに変換←変換結果参考）ctime，asctime 関数が返す文字列の書式は，C 言語における同名の関数に由来する．
■ struct time の内容を書式に沿った文字列に変換する関数 strftime
書き方：

strftime( fmt, st )書式文字列 fmt に沿った形で struct time オブジェクト の内容を文字列に変換して返す．書式文字列は datetime モ
ジュールの同名のメソッドに与えるもの（p.206 の表 28）と概ね同じである．
例．strftime による書式整形（先の例の続き）>>> s = time.strftime( ’%Y/%m/%d(%a) %H:%M:%S’, st )
>>> s
Enter
←確認
’2023/07/30(Sun) 12:30:19’

Enter←先に得た st を書式整形←変換結果

この関数は第 2 引数を省略すると，ローカルタイムの現在時刻を書式整形する．
■ 文字列表現の日付，時刻を struct time オブジェクトに変換する関数 strptime
書き方：

strptime( 文字列, fmt )日付，時刻を表現した「文字列」を書式文字列 fmt（先の strftime と同様）に沿った形で解釈し，それを struct time
オブジェクトに変換して返す．
例．strptime による文字列の読み取り（先の例の続き）>>> time.strptime( s, ’%Y/%m/%d(%a) %H:%M:%S’ )Enter←上の例で得た文字列を読み取る

time.struct time(tm year=2023, tm mon=7, tm mday=30, tm hour=12,
tm min=30, tm sec=19, tm wday=6, tm yday=211, tm isdst=-1)←得られた
struct time オブジェクト

この関数は第 2 引数（書式文字列）を省略すると，ctime，asctime 関数が返す文字列の書式が適用される．
例．書式文字列を省略した場合の strptime 関数の動作（先の例の続き）>>> s = time.ctime( t )

Enter

>>> s
Enter
←内容確認
’Sun Jul 30 12:30:19 2023’>>> time.strptime( s )Enter← ctime 形式の文字列の作成←これをそのまま← struct time オブジェクトに変換する

time.struct time(tm year=2023, tm mon=7, tm mday=30, tm hour=12,
tm min=30, tm sec=19, tm wday=6, tm yday=211, tm isdst=-1)
4.1.2.3←得られた
struct time オブジェクト

応用例：datetime オブジェクトとの間の変換

time モジュールの strftime 関数と strptime 関数，datetime モジュールの strftime メソッドと strptime メソッドを応用すると，struct time オブジェクトと datetime オブジェクトの間の相互の変換が実現できる．

212

■ datetime オブジェクト → struct time オブジェクトの変換の例
例．datetime オブジェクトの作成>>> from datetime import datetime>>> d = datetime.now()

Enter

Enter

← datetime クラスの読込み←現在時刻の datetime オブジェクトを作成

>>> d
Enter
←確認
datetime.datetime(2023, 7, 30, 17, 8, 19, 372091)
変数 d に現在時刻の datetime オブジェクトが得られている．次にこれを文字列に変換し，更にそれを struct time オ
ブジェクトに変換する．
例．datetime オブジェクト → 文字列の変換（先の例の続き）>>> s = d.strftime(’%Y/%m/%d %H:%M:%S’)
>>> s
Enter
←確認
’2023/07/30 17:08:19’

Enter← datetime を文字列に変換←文字列になっている

例．文字列 → struct time オブジェクトの変換（先の例の続き）>>> import timeEnter

← time モジュールの読込み>>> st = time.strptime( s, ’%Y/%m/%d %H:%M:%S’ ) Enter ←上で作成した文字列を struct time に変換>>> stEnter←確認
time.struct time(tm year=2023, tm mon=7, tm mday=30, tm hour=17,
tm min=8, tm sec=19, tm wday=6, tm yday=211, tm isdst=-1)← struct time オブジェクトになっている■ struct time オブジェクト → datetime オブジェクトの変換の例
例．struct time → 文字列 → datetime オブジェクト（先の例の続き）>>> s = time.strftime( ’%Y/%m/%d %H:%M:%S’, st )Enter

← struct time を文字列に変換

>>> s
Enter
←確認
’2023/07/30 17:08:19’>>> datetime.strptime( s, ’%Y/%m/%d %H:%M:%S’ ) Enter ←上で作成した文字列を datetime に変換
datetime.datetime(2023, 7, 30, 17, 8, 19)←得られた datetime オブジェクト
注）実際の処理ではタイムゾーンに配慮すること．

4.1.2.4

時間の計測

プログラムの実行にかかった時間を計測するには，開始時点での時刻と終了時点での時刻の値の差を取るという方法がある．2 を 500,000 回掛け算することで 2500,000 を求めるプログラム test10-1.py を示す．このプログラムは計算にかかった時間を出力する．
プログラム：test10-1.py
1
2
3
4
5
6
7
8
9
10
11

# coding : utf -8
import time
# 必要なモジュールの読込み
t1 = time . time ()n = 1
for i in range (500000):n *= 2t2 = time . time ()print ( t2 - t1 , ’( sec ) ’)# import sys ; sys . s et _i nt _ma x_ st r_ d i g i t s (40000); print ( n )このプログラムを実行すると，例えば3.1404953002929688 (sec)などと，実行に要した時間158 が表示される．また，最終行のコメント ’#’ を外すと 2500,000 の計算結果が表示159 される．
158 当然であるが，使用する計算機環境によって実行時間は異なる．
159 この部分の処理に関しては「2.3.6.2 巨大な整数値を扱う際の注意」（p.13）を参照のこと．

213

プログラムの実行時間の計測には，後に説明する timeit モジュールを使用する方法もある．
■ 更に正確な時間計測

time.time() の差分計算による経過時間の計測結果は実時間である．実際の計算機システムでは，複数のスレッド
やプロセスが同時に実行されるので，個々のスレッドやプロセスが CPU を実際に使用した時間（CPU 時間）と実
時間は異なる．当該スレッドが起動した時点を 0 として，当該スレッドが使用した CPU 時間を得るには thread time関数を使用する．また，当該プロセスが起動した時点を 0 として，当該プロセスが使用した CPU 時間を得るにはprocess time 関数を用いる．これらの関数を用いることで，スレッドやプロセスが実際に実行に要した時間を算出することができる．
※ スレッドとプロセスに関しては，後の「4.4 マルチスレッドとマルチプロセス」（p.228）で詳しく解説する．

先のサンプルプログラム test10-1.py と同様の処理を行い，スレッドとしての CPU 時間を計測する例を test10-

1 thread.py に，プロセスとしての CPU 時間を計測する例を test10-1 process.py に示す．
プログラム：test10-1 thread.py

プログラム：test10-1 process.py

1
2
3
4
5
6
7
8
9
10

1
2
3
4
5
6
7
8
9
10

# coding : utf -8
import time
t1 = time . thread_time ()n = 1
for i in range (500000):n *= 2t2 = time . thread_time ()print ( t2 - t1 , ’( sec ) ’)

このプログラムを実行すると，例えば# coding : utf -8
import time
t1 = time . process_time ()n = 1
for i in range (500000):n *= 2t2 = time . process_time ()print ( t2 - t1 , ’( sec ) ’)

このプログラムを実行すると，例えば2.984375 (sec)3.09375 (sec)などと，スレッドとしての実行に要した CPU 時間が表などと，プロセスとしての実行に要した CPU 時間が表

示される．

示される．

▲注意▲
マルチスレッドプログラミングにおいては，個々のサブスレッド内で得られる thread time 関数の値が，当該サブスレッドが実際に実行した処理の CPU 時間を反映しないことがあるので注意すること．それについて次のサンプル

test10-2 thread.py で確認する．
プログラム：test10-2 thread.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8
import timefrom threading import Thread# 実行時間がかかる処理
def longTask ( res , i ):ts = time . thread_time () # ス レ ッ ド 開 始 時 間
n = 1
for _ in range (500000):n *= 2te = time . thread_time () # ス レ ッ ド 終 了 時 間
res [ i ] = te - ts # 実 行 時 間 の 格 納
R = [0 , 0]

# 処理結果受領用リスト# スレッド作成
th1 = Thread ( target = longTask , args =( R , 0))th2 = Thread ( target = longTask , args =( R , 1))# スレッド実行
t1 = time . time ()th1 . start ();th2 . start () # ス レ ッ ド の 開 始
th1 . join ();th2 . join () # ス レ ッ ド 終 了 の 待 機
t2 = time . time ()

214

26
27
28
29

# 測定結果の報告
print ( ’ メ イ ン ス レ ッ ド の 経 過 時 間 （ 秒 ） : ’ , t2 - t1 )print ( ’ス レ ッ ド t h 1 の C P U 時 間 （ 秒 ） : ’ , R [0])print ( ’ス レ ッ ド t h 2 の C P U 時 間 （ 秒 ） : ’ , R [1])

これは先の test10-1 thread.py と同様の処理を 2 つのサブスレッドで同時に実行するものである．これを実行すると次のような結果が表示される．
例．test10-2 thread.py 実行後のコンソール出力
メインスレッドの経過時間（秒）: 6.486693382263184
スレッド th1 の CPU 時間（秒）: 0.78125
スレッド th2 の CPU 時間（秒）: 0.984375

メインスレッドの経過時間は先の test10-1 thread.py の 2 倍程度（同じ処理を 2 つ同時に実行しているため）となっているが，個々のサブスレッド th1，th2 の CPU 時間が非常に小さな値となっている．この値は，個々のサブスレッド
が実際に行っている処理の CPU 時間を反映していないことに注意すること．

4.1.2.5

プログラムの実行待ち

time モジュールの sleep 関数を用いると，指定した時間プログラムを待機させる160 ことができる．
書き方：

sleep( 待ち時間 )CPU 時間を消費せずにプログラムの実行を「待ち時間」（単位：秒）だけ待機する．
プログラム：timeSleep01.py
1
2
3
4
5
6

# coding : utf -8
import time
print ( ’ プ ロ グ ラ ム の 開 始 ’ )time . sleep (3.0)
print ( ’ プ ロ グ ラ ム の 終 了 ’ )これを実行すると次のような出力が得られる．
例．timeSleep01.py を実行した際のコンソール出力
プログラムの開始←この出力の 3 秒後にプログラムの終了←これが出力される

160 厳密には当該スレッドを待機させる．スレッドに関しては後の「4.4 マルチスレッドとマルチプロセス」（p.228）を参照のこと．

215

4.1.3timeit モジュール

プログラムの実行時間の計測には timeit モジュールを使用する方法161 がある．このモジュールを使用するには

import timeit などとして Python 処理系に読み込む必要がある．
このモジュールには同名の関数 timeit が提供されており，これを用いて文字列として与えたプログラムの実行時間を計測することができる．
書き方：

timeit( プログラム, number=繰り返し回数, globals=グローバルオブジェクトの辞書 )「プログラム」に文字列で記述した Python のプログラムを与える．
「繰り返し回数」には与えたプログラムを実行する回数を指定する．
（暗黙で 1,000,000 が設定されているので注意すること）「グローバルオブジェクトの辞書」には，実行するプログラムに必要となるグローバルオブジェクトの辞書（変数名に対する値の辞書）を与える．この関数は実行に要した時間（秒単位の浮動小数点数）を返す．
以下にサンプルを示して timeit 関数の使用方法について説明する．
例．サンプル用の関数定義>>> def p2n(n): Enter← 2n を計算する関数
...
r = 1
Enter
...
for i in range(n): r *= 2
Enter
...
return r
Enter
...
Enter
←関数定義の記述の終了>>>← Python のプロンプトに戻った
この関数 p2n の実行時間を計測する例を次に示す．
例．プログラムの実行時間の計測（先の例の続き）>>> import timeitEnter>>> prg = ’p2n(10000)’←モジュールの読み込みEnter←実行するプログラムを文字列として用意>>> timeit.timeit(prg,number=100,globals=globals()) Enter ← 100 回実行してその時間を計測
0.19903010001871735←実行にかかった時間（秒）>>> timeit.timeit(prg,number=1000,globals=globals()) Enter ← 1000 回実行してその時間を計測
1.8931540999910794←実行にかかった時間（秒）timeit 関数の引数 ’globals=’ に与える globals() はグローバルオブジェクトの辞書を取得する関数で，これに関しては後の「4.19 使用されているシンボルの調査」（p.301）で解説する．

161 time モジュールを使用する方法よりも正確な実行時間が得られる．

216

ロケール（locale）

4.2

日付や時刻の書式，通貨の書式、数値の書式などは国や言語圏毎に異なることがあり，アプリケーションプログラムを作成する際は，それらをロケールとして識別することがある．ロケールは言語コード (ISO 639-1) と国コード (ISO3166-1) から成るものであり，例えば日本のロケールは，日本語を意味する言語コード「ja」と日本国を意味する国
コード「JP」を用いて「ja JP」などと表記される．更にロケールにはエンコーディングの情報を持たせることも可能
で，先の例に「utf-8」の情報を加えるとロケールは「ja JP.UTF-8」となる．また，ロケールの記述に用いる言語コー
ド，国コード，エンコーディングの表記は大文字／小文字の違いなど様々なバリエーションがある．

Python 言語処理系においては，ロケールの設定などの機能を locale モジュールが提供している．実際に，datetime モ
ジュールや time モジュールなどのいくつかの API がロケールの設定状態の影響を受ける．例えば次のような datetime
オブジェクトの書式整形について考える．
例．datetime オブジェクトの書式整形>>> from datetime import datetime, timedelta, timezone>>> z = timezone(timedelta(hours=9))Enter>>> d = datetime(2023,7,31,13,15,23,tzinfo=z)Enter←モジュールの読込み←日本のタイムゾーン← datetime オブジェクトの作成

Enter>>> d.strftime(’%Y/%m/%d (%a:%A) (%b:%B) %H:%M:%S’)Enter’2023/07/31 (Mon:Monday) (Jul:July) 13:15:23’
←結果

←書式整形

この例では %a，%A によって曜日，%b，%B によって月名を得ているが英語圏の書式となっていることがわかる．
（実際に多くの計算機環境において，この状態がデフォルトとなっている）
次に，ロケールを他の言語圏に変更して同様の処理を行う例を示す．
例．ロケールの設定変更（先の例の続き）

Enter>>> import locale←モジュールの読込み>>> locale.setlocale( locale.LC TIME, ’ja JP’ )’ja JP’>>> d.strftime(’%Y/%m/%d (%a:%A) (%b:%B) %H:%M:%S’)’2023/07/31 (月:月曜日) (7:7 月) 13:15:23’>>> locale.setlocale( locale.LC TIME, ’fr FR’ )’fr FR’←時間のロケールを日本に設定←変更された

Enter

Enter

←時間のロケールをフランスに設定←変更されたEnter>>> d.strftime(’%Y/%m/%d (%a:%A) (%b:%B) %H:%M:%S’)’2023/07/31 (lun.:lundi) (juil.:juillet) 13:15:23’←書式整形←日本語になっている

Enter

←書式整形
←フランス語になっている

この例で示した setlocale 関数がロケールを設定するものである．
書き方：

setlocale( カテゴリ, ロケール )ロケールを設定する際にはカテゴリ（表 30）を指定する
表 30: ロケールのカテゴリ
カテゴリ

解説

LC ALLLC COLLATE
LC CTYPELC MONETARYLC NUMERICLC TIMELC MESSAGES

全てのロケール設定を総合したもの
文字列の並べ替えに関する設定
文字タイプ関連の設定金額などの値の書式化に関する設定
数値の文字列表現に関する設定
時刻の書式化に関する設定
メッセージ表示に関する設定

影響範囲（備考）

locale モジュールの strcoll, strxfrm 関数
string モジュール
locale モジュールの format, atoi, atof, str 関数
datetime, time モジュール
サポートしていない処理系もある．

実際にはこの表のカテゴリを「locale. カテゴリ」のように記述する．

4.2.1

ロケール設定の確認

getlocale 関数によってロケールの設定を確認することができる．
書き方：

getlocale( カテゴリ )指定した「カテゴリ」の設定状態を (’ 言語コード 国コード’, エンコーディング) のタプルとして返す．

Python 処理系を起動した直後のロケール設定を確認するプログラム locale01.py を示す．

217

プログラム：locale01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# coding : utf -8
import locale# locale . setlocale ( locale . LC_ALL , ’’ )# locale . setlocale ( locale . LC_ALL , ’C ’ )cat = locale . LC_COLLATE
print ( ’ LC_COLLATE ( ’ , cat ,cat = locale . LC_CTYPE
print ( ’ LC_CTYPE( ’ , cat ,cat = locale . LC_MONETARY
print ( ’ LC_MONETARY ( ’ , cat ,cat = locale . LC_NUMERIC
print ( ’ LC_NUMERIC ( ’ , cat ,cat = locale . LC_TIME
print ( ’ LC_TIME( ’ , cat ,# OSのロケール設定に準拠する# ANSI C ( POSIX ) の ロ ケ ー ル 設 定 に 準 拠 す る’): ’, locale . getlocale ( cat ) , sep = ’ ’ )’): ’, locale . getlocale ( cat ) , sep = ’ ’ )’): ’, locale . getlocale ( cat ) , sep = ’ ’ )’): ’, locale . getlocale ( cat ) , sep = ’ ’ )’): ’, locale . getlocale ( cat ) , sep = ’ ’ )このプログラムの実行による出力の例を次に示す．
LC COLLATE (1): (None, None)LC CTYPE(2): (’Japanese Japan’, ’932’)
LC MONETARY (3): (None, None)LC NUMERIC (4): (None, None)LC TIME(5): (None, None)

このプログラムの 4 行目の先頭にあるコメント記号「#」を外すと，Python 処理系のロケールが OS のロケール設
定に準拠したものとなる．また 5 行目の先頭にあるコメント記号「#」を外すと ANSI C(POSIX) に準拠した設定となるので試みられたい．
参考）ロケールを使用するアプリケーションにおいては locale.setlocale( locale.LC ALL, ’’ ) を実行しておくことが望ましい．

4.2.2

使用できるロケールの調査

ロケールの表記を始めとする各種の情報は辞書の形で locale.locale alias に保持されている．この中から 言語コー
ド 国コード の形式になっているものを取り出すことで，Python 言語処理系で使用できるロケールを調べることができる．
（下記プログラム例：locale02.py）
プログラム：locale02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# coding : utf -8
import localeb = set ()for e in locale . locale_alias . keys ():if ’_ ’ in e and ’. ’ not in e and len ( e ) <6:
b . add ( e )# ロケール収集# 整列して出力for i , L in enumerate ( sorted ( list ( b ))):
if ( i +1)%18!=0:
print (f ’{ L :6 s } ’ , end = ’ ’)else :
print ( L )else : print ()このプログラムの実行による出力の例を次に示す．
a3 az aa dj aa er aa et af za ak gh am et an es ar aa ar ae ar bh ar dz ar eg ar in ar iq ar jo ar kw ar lb
ar ly ar ma ar om ar qa ar sa ar sd ar ss ar sy ar tn ar ye as in az az az ir be by bg bg bi vu bn bd bn in
bo cn bo in br fr bs ba c c
ca ad ca es ca fr ca it ce ru cs cs cs cz cv ru cy gb cz cz da dk de at de be
de ch de de de it de lu dv mv dz bt ee ee el cy el gr en ag en au en be en bw en ca en dk en gb en hk en ie
en il en in en ng en nz en ph en sg en uk en us en za en zm en zw eo eo eo xx es ar es bo es cl es co es cr：（以下省略）：

218

4.2.34.2.3.1

その他
現在のエンコーディングの調査

getencoding 関数を使用すると現在のエンコーディングを調べることができる．
例．エンコーディングを調べる>>> import localeEnter←モジュールの読込み>>> locale.setlocale( locale.LC ALL, ’’ )Enter
←ロケールの初期化’Japanese Japan.932’←このようなロケールに設定された>>> locale.getencoding()’cp932’4.2.3.2←エンコーディングを調べる←現在のエンコーディング

Enter

通貨の書式整形currency 関数を使用すると，数値を通貨の値と見做して書式整形ができる．
書き方：

currency( 数値, grouping=桁区切りの有無, international=国際表現にするか否か )「数値」を金額表現の文字列に変換して返す．
「grouping=」,「international=」には真理値を与える．
例．日本円による書式整形>>> import localeEnter←モジュールの読込み>>> locale.setlocale( locale.LC MONETARY, ’ja JP’ )’ja JP’←設定結果>>> locale.currency( 100000 )’￥100000’

Enter

Enter

←通貨を日本円に設定←数値を通貨表現の文字列に変換←変換結果>>> locale.currency( 100000, grouping=True )Enter’￥100,000’←変換結果←コンマ区切りありで変換>>> locale.currency( 100000, grouping=True, international=True )Enter’JPY100,000’←変換結果↑コンマ区切りありの国際表現で変換
例．米ドルによる書式整形（先の例の続き）>>> locale.setlocale( locale.LC MONETARY, ’en US’ )’en US’←設定結果>>> locale.currency( 100000 )’$100000.00’

Enter←通貨を米ドルに設定

Enter
←変換結果

>>> locale.currency( 100000, grouping=True )Enter’$100,000.00’←変換結果>>> locale.currency( 100000, grouping=True, international=True )’USD100,000.00’
←変換結果

Enter

本書で取り上げなかったロケール関連の機能については，Python の公式インターネットサイトなどを参照のこと．

219

文字列検索と正規表現

4.3

re モジュールを用いることで，高度なパターン検索が実現できる．このモジュールは次のようにして読み込む．
例．モジュールの読み込み>>> import re
以後，re モジュールが読み込まれている前提で解説する．

4.3.1

パターンの検索re クラスの search 関数を使用すると，文字列に含まれるパターンを検索することができる．具体的には，長いテキスト（文字列）の中に，探したい検索キー（文字列）がどの位置にあるかを調べる．
《 文字列の検索 (1) 》
書き方 (1)：

re.search(検索キー, テキスト)

検索対象の「テキスト」の中から指定した「検索キー」（パターン）が最初に現れる場所を見つけ出す．
「検索キー」は raw 文字列で与える．
書き方 (2)： コンパイル済み検索キー.search(テキスト)「コンパイル済み検索キー」は re クラスの compile 関数で生成された検索キーであり，これを用いることで検索処理が最適化される．
検索キーのコンパイル：

re.compile(検索キー)

この結果，コンパイル済み検索キーが返される．
検索処理が終わると，検索結果を保持する match オブジェクトが返される．テキストの中に検索キーに一致す
るものが無ければ None が返される．

検索キーには正規表現（後述）を指定することができる．そのため，raw 文字列で与える必要がある．
テキスト ’My name is Taro. I am 19 years old.’ の中から ’Taro’ の位置を探す例（書き方 (1) の例）を示す．
例．検索処理>>> import reEnter←モジュールの読み込み>>> txt = ’My name is Taro.
>>> ptn = r’Taro’

I am 19 years old.’(11, 15)←テキストの生成←検索キーの生成Enter>>> res = re.search(ptn,txt)>>> res.span()

Enter

Enter

←検索の実行←検出位置を調べるEnter← 11〜14 番目に’Taro’ が存在することがわかる

この例では，検索結果が変数 res に match オブジェクトとして得られている．それに対して span メソッドを実行することで，検出位置のタプル (n1 , n2 ) が得られる．これは，対象テキストの n1 〜n2 − 1 のインデックスの位置にパターンが見つかったことを意味する．
検索キーをコンパイルして同様の処理を行ったものが次の例（書き方 (2) の例）である．
例．パターンをコンパイルして検索する例>>> p = re.compile(ptn)

Enter←検索キーのコンパイル>>> res = p.search(txt)Enter←検索の実行>>> res.span()(11, 15)Enter←検出位置を調べる← 11〜14 番目に’Taro’ が存在することがわかる

search 関数は，テキストの中で最初に検索キーが現れる場所を探す．同じ検索キーがテキストの中に複数含まれる
場合は ﬁnditer 関数を使用することで全ての検出位置を取得することができる．

220

《 文字列の検索 (2) 》
書き方 (3)：re.ﬁnditer(検索キー, テキスト)

検索対象のテキスト中から指定した検索キー（パターン）が現れる箇所を全て見つけ出す．
「検索キー」は raw 文字列で与える．
書き方 (4)： コンパイル済み検索キー.ﬁnditer(テキスト)「コンパイル済み検索キー」は re クラスの compile 関数で生成された検索キーであり，これを用いることで検索処理が最適化される．
検索処理が終わると，検索結果を保持する match オブジェクトのイテレータが返される．

次に，ﬁnditer 関数を用いた検索の例を示す．test11.txt のようなテキストからキーワード「Python」を全て見つけ出す処理の例（書き方 (4) の例）である．
検索対象のテキスト：test11.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

（フリー百科事典「ウィキペディア」より）
コードを単純化して可読性を高め、読みやすく、また書きやすくしてプログラマの作業性とコードの信頼性を高めることを重視してデザインされた、汎用の高水準言語である。反面、実行速度は Cなどの低級言語に比べて犠牲にされている。
核となる文法（シンタックス）および意味（セマンティクス）は必要最小限に抑えら れ て い る 。 そ の 反 面 、 豊 富 で 大 規 模 な 文 書 ( document ) や 、 さ ま ざ ま な 領 域 に対応する大規模な標準ライブラリやサードパーティ製のライブラリが提供されている。
ま た P y t h o n は 多 く の ハ ー ド ウ ェ ア と O S ( プ ラ ッ ト フ ォ ー ム) に 対 応 し て お り 、 複 数 のプ ロ グ ラ ミ ン グ パ ラ ダ イ ム に 対 応 し て い る 。 Pythonはオブジェクト指向、命令型、手続き型、関数型などの形式でプログラムを書くことができる。動的型付け言語であり、参照カウントベースの自動メモリ管理（ガベージコレクタ）を持つ。
これらの特性により、 PythonはWebアプリケーションやデスクトップアプリケーション
な ど の 開 発 は も と よ り 、 シ ス テ ム 用 の 記 述 ( script ) や 、 各 種 の 自 動 処 理 、 理 工 学 や
統計・解析など、幅広い領域における支持を得る、有力なプログラム言語となった。
プログラミング作業が容易で能率的であることは、ソフトウェア企業にとっては投入人員の節約、開発時間の短縮、ひいてはコスト削減に有益であることから、産業分野でも広く利用されている。 Googleなど主要言語に採用している企業も多い。

このテキストの中から検索キー ’Python’ を全て探し出すプログラムを test11.py に示す．
プログラム：test11.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8
import re# 必要なモジュールの読込み# ファイルの内容を一度で読み込む
f = open ( ’ test11 . txt ’ , ’r ’ , encoding = ’ utf -8 ’)text = f . read ()f . close ()# 検索処理ptn = r ’ Python ’# 検索キーp = re . compile ( ptn ) # 検 索 キ ー の コ ン パ イ ル
res = p . finditer ( text )# 処理結果の報告
print ( ’ 【 検 索 キ ー " Python " の 検 索 結 果 】 ’ )print ( ’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)n = 0
for i in res :n += 1
print (n , ’ 番 目 の 検 出 位 置 : ’,i . span ())
print ( ’ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ’)print (n , ’ 個 検 出 し ま し た ． ’ )テキスト中には ’Python’ という語は複数あり，得られるイテレータは，検索が該当した回数分の match オブジェク
トを含んでいる．そこで，18〜20 行目のように for 文で 1 要素ずつ取り出している．取り出された要素に対して span221

メソッドを実行することで，テキスト中に見つかった検索キーワードの位置を取得することができる．
このプログラムを実行した結果を次に示す．
【検索キー"Python"の検索結果】------------------------------1 番目の検出位置: (256, 262)
2 番目の検出位置: (319, 325)
3 番目の検出位置: (424, 430)------------------------------3 個検出しました．

4.3.1.1

正規表現を用いた検索

検索キーとして，固定された文字列のみを用いるのではなく，指定した条件に一致する部分をテキストの中から見つけ出す場合に正規表現が非常に有用である．例えばアルファベットのみから成る文字列を見つけ出す場合について考える．
「アルファベット文字列」を意味するパターンを正規表現で表すと ’[a-zA-Z]+’ となる．
（詳しくは後述する）
先のプログラムの 10 行目を

ptn = r’[a-zA-Z]+’
20 行目を
print(n,’ 番目の検出位置:￥t’,i.span(),’￥t’,i.group())と書き換えて（タイトル表示部分も変えて）実行すると，次のような結果となる．
【アルファベット文字列の検索結果】------------------------------1 番目の検出位置:(110, 111)
2 番目の検出位置:(193, 201)
3 番目の検出位置:(256, 262)：
（途中省略）：
8 番目の検出位置:(479, 485)
9 番目の検出位置:(631, 637)------------------------------9 個検出しました．

C
document
PythonscriptGoogle

このように柔軟に検索パターンを構成する場合に正規表現が有用である．検索パターンが具体的にどのような文字列に一致したかを調べるにはメソッド group を使用する．
この例では ’[a-zA-Z]+’ で半角アルファベットを表したが，正規表現では’[〜]’ で文字の範囲（集合）を表す．例
えば ’[a-z]’ とするとこれは「アルファベット小文字」を意味する．また，’[A-Z]’ では「アルファベット大文字」を意味する．更に ’+’ は「それらが 1 文字以上続く列」を意味する．従って，’[a-zA-Z]+’
は，「アルファベット小文字もしくは大文字」かつ「それらが 1 文字以上続く列」を意味し，「アルファベットの文字列」を意味するパターンとなる．同様に「数字のみの列」を意味する正規表現は’[0-9]+’ となる．
特定の文字集合，例えば「’c’,’n’,’x’ のどれか」は ‘[cnx]’ と記述する．
例．’a’ もしくは ’b’ もしくは ’c’ に一致する文字の検索←パターン検索実行>>> print( re.search( r’[abc]’, ’abcd’ ) )Enter<re.Match object; span=(0, 1), match=’a’>←先頭の ’a’ に一致

これはパターン ‘[abc]’ を検索するものであるが，括弧 ‘[ ]’ の中に ‘^’ を記述すると「それら以外のパターン」を
検索する．

222

例．「それ以外」のパターン検索>>> print( re.search( r’[^abc]’, ’abcd’ ) )Enter←パターン検索実行<re.Match object; span=(3, 4), match=’d’>←末尾の ’d’ に一致
これは「 『’a’ もしくは’b’ もしくは’c’』でないもの」の検索であり，「’a’ でなく，かつ，’b’ でなく，かつ，’c’ でないもの」と同義162 である．結果として末尾の ’d’ に一致している．
本書では正規表現の全てについての解説はしないが，特に使用頻度が高いと考えられるパターン表現について説明する．
■ 正規表現で構成する文字列のパターン
基本的には「1 文字分のパターン」と「繰り返し」を連接したものである．先に説明した’[〜]’ が「1 文字分のパターン」，’+’ が「繰り返し」を意味する．
「1 文字分のパターン」の基本的なものを表 31 に挙げる．
表 31: 正規表現のパターン（一部）
パターン

意味

[c1 c2 c3 · · ·]特定の文字の集合 c1 c2 c3 · · ·[c1 -c2 ]（これらの内のどれかに該当）否定の ‘ˆ’ が使える．

c1 〜c2 の間に含まれる文字．文字の範囲をハイフン ’-’ でつなげる．
例: [a-d] → ’a’,’b’,’c’,’d’ のどれか． （否定の ‘ˆ’ が使える）.（ドット） 任意の 1 文字￥d

数字（ [0-9] と同じ）

￥D

数字以外

￥s

空白文字（タブ，改行文字なども含む）￥S

空白文字以外（￥s でないもの）￥w

アンダースコアを含む半角英数字（ [a-zA-Z0-9 ] と同じ）￥W

半角英数字以外（￥w でないもの）「繰り返し」の基本的なものを表 32 に挙げる．

表記

表 32: 繰り返しの表記（一部）
表記
意味

意味

+

1 回以上

?

0 回かもしくは 1 回{m,n}{m,n}?

m 回以上 n 回以下（回数が大きい方を優先）
m 回以上 n 回以下（回数が小さい方を優先）

{n}

n回

{m,}

m 回以上

*

0 回以上

正規表現のパターンには多バイト文字（全角文字）を使用することもできる．
例．全角文字列 ’ かきくけこ’ を検索する>>> print( re.search( ’[かきくけこ]+’, ’ あいうえおかきくけこさしすせそ’ ) )Enter<re.Match object; span=(5, 10), match=’ かきくけこ’>←検出できている■ 文字コードを検索パターンに使用する方法「￥x」に続いて 16 進数の ASCII コードを記述したものを当該文字コードが表す文字の検索パターンとして使用できる．例えばアルファベット小文字を意味する正規表現 ’[a-z]’ は ’[￥x61-￥x7a]’ と記述することができる．
例．アルファベット小文字の検索パターンを文字コードで記述する>>> txt = r’0123abcDEF#$&?’>>> ptn = r’[￥x61-￥x7a]+’>>> res = re.search(ptn,txt)

Enter
Enter
Enter

←テキスト
←パターン
←検索実行

>>> print( res.span(),res.group() )Enter←結果の出力(4, 7) abc←インデックス範囲 4 以上 7 未満の位置に ’abc’ を検出
162 ブール代数や集合論における「ド・モルガン則」でも理解できる．

223

■ Unicode 文字の検索

Unicode 文字を検索する場合「￥u」に続いて 16 進数のコードポイント値を記述して検索パターンとすることができる．
例．Unicode の平仮名を検索する>>> txt = ’0123 あいうえお abc’

Enter

←テキスト

>>> ptn = r’[￥u3041-￥u3096]+’

Enter

←パターン

>>> res = re.search(ptn,txt)

←検索実行

Enter

>>> print( res.span(),res.group() )Enter←結果の出力(4, 9) あいうえお←インデックス範囲 4 以上 9 未満の位置に ’ あいうえお’ を検出
Unicode における平仮名のコード範囲は ￥u3041〜￥u3096 であり，この例はそれを応用したものである．
4.3.1.2

検索パターンの和結合

複数の検索パターンを ‘|’ で和結合することができる．これを応用すると高度なパターン検索が可能になる．これに関して以下に例を挙げて説明する．
■ サンプルケース：HTML タグのパターン検索
次のような 3 つのパターンのタグ全てに一致する検索処理について考える．

1. tx1 = ’<h1>見出し 1</h1>’

：

単純なタグ

2. tx2 = ’<h2 id="hd2">見出し 2</h2>’：

タグ内に属性などの記述があるもの：

タグ内に余計な空白があるもの

3. tx3 = ’<h3

>見出し 3</h3>’

このような文字列が変数 tx1，tx2，tx3 に設定されているとする．
例．上記 1 のパターンでそれぞれ検索>>> ptn = r’<h￥d>’Enter←上記 1 のパターン>>> print( re.search(ptn,tx1) )Enter←上記 1 に対して検索実行<re.Match object; span=(0, 4), match=’<h1>’>←先頭のタグに一致>>> print( re.search(ptn,tx2) )
None

Enter

←上記 2 に対して検索実行←一致せず>>> print( re.search(ptn,tx3) )
None

Enter

←上記 3 に対して検索実行←一致せず

この例からわかるように ‘ptn = r’<h￥d>’’ の検索パターンでは 2 と 3 のパターンに一致させることができない．従って 1，2，3 全てのパターンに一致させるには ‘<h￥d￥s+[^>]*>’ というパターンも必要になる．そこで，このパターンと上の例のパターンの和結合による検索を試みる例を次に示す．
例．パターンの和結合>>> ptn = r’<h￥d>|<h￥d￥s+[^>]*>’←パターン和結合Enter>>> print( re.search(ptn,tx1) )Enter←上記 1 に対して検索実行<re.Match object; span=(0, 4), match=’<h1>’>←先頭のタグに一致>>> print( re.search(ptn,tx2) )Enter←上記 2 に対して検索実行<re.Match object; span=(0, 13), match=’<h2 id="hd2">’>←先頭のタグに一致>>> print( re.search(ptn,tx3) )Enter<re.Match object; span=(0, 6), match=’<h3←上記 3 に対して検索実行>’>←先頭のタグに一致

この例のように，検索パターンの結合を応用すると高度な検索が可能となる．
考察）今回の例の tx1，tx2，tx3 に一致する検索パターンはもっと簡単に記述することができるので考察されたい．

4.3.1.3

正規表現を用いたパターンマッチ

パターンマッチによって，テキストデータから必要な部分を抽出することができる．パターンマッチには match 関数を用いる．

224

例．テキスト ’uyhtgfdres98234yhnbgtrf’ の中から数字の部分のみ取り出す←テキストの生成Enter>>> txt = ’uyhtgfdres98234yhnbgtrf’Enter>>> ptn = r’[a-zA-Z]+([0-9]+)[a-zA-Z]*’←パターンの生成←パターンマッチの実行>>> res = re.match(ptn,txt)

Enter>>> res.group(0)Enter’uyhtgfdres98234yhnbgtrf’←マッチしたか確認←マッチしている（テキスト全体）>>> res.group(1)Enter ←パターン ([0-9]+) が一致した部分の取り出し’98234’←数字のみが得られている
この例では，検索パターンが ’[a-zA-Z]+([0-9]+)[a-zA-Z]*’として与えられている．パターンの中に括弧 ’(〜)’の部分（グループ）があるが，抽出したい部分はこのように括弧で括る．

match 関数は，テキストとパターンを一致させるように動作する．すなわちテキストの先頭からパターンを一致させるように試みるものであり，search や ﬁnditer による検索とは動作が異なる．
パターンの中には抽出したい括弧付きの部分（グループ）を複数記述することができ，match が成功すると，得られた match オブジェクトから group メソッドに順番の引数を与えて取り出すことができる．ここに示した例では括弧付きの部分は 1 つであるので，

res.group(1)で抽出した部分を得ることができる．
パターンにおけるグループの考え方は検索処理の場合にも当てはまり，search の戻り値の match オブジェクトや

ﬁnditer の戻り値の各要素の match オブジェクトに対しても ‘group(n)’ のメソッドを適用することができる．
4.3.1.4

行頭や行末でのパターンマッチ

検索キーの正規表現には行頭や行末の位置指定ができる．すなわち，検索キーの先頭に「^」を記述するとテキストの行の始め（行頭）にあるかどうか，検索キーの末尾に「＄」を記述するとテキストの行の末尾（行末）にあるかどうかを検査できる．
例．行頭でのマッチング検査>>> ptn = r’abc’

Enter←’abc’ を 2 個含むテキストEnter>>> txt = ’abcdabcdefghefgh’←検索キー ’abc’（位置指定なし）←検索の実行>>> res = re.finditer( ptn, txt )Enter>>> for i in res: Enter...
print( i.span() )
...
Enter

←検索結果を全て表示する処理(0, 3)(4, 7)>>> ptn = r’^abc’Enter← 1 つめの一致← 2 つめの一致

Enter←’^’ を含む検索キー（行頭のみの位置指定）←検索の実行>>> res = re.finditer( ptn, txt )Enter>>> for i in res: Enter...
print( i.span() )
...
Enter

←検索結果を全て表示する処理(0, 3)

Enter←行頭の 1 つだけ一致

この例は，テキスト ’abcdabcdefghefgh’ の中のパターン ’abc’ を探す例である．行末や行頭の位置指定をせずに実行
すると 2 箇所に ’abc’ が見つかっているが，位置を指定すると 1 箇所のみパターンが見つかっている．
次に，行末でのマッチングの例を示す．

225

例．行末でのマッチング検査（先の例の続き）>>> ptn = r’fgh’←検索キー ’fgh’（位置指定なし）

Enter←検索の実行>>> res = re.finditer( ptn, txt )Enter>>> for i in res: Enter...
print( i.span() )
...
Enter

←検索結果を全て表示する処理Enter(9, 12)(13, 16)← 1 つめの一致← 2 つめの一致>>> ptn = r’fgh$’Enter←’$’ を含む検索キー（行末のみの位置指定）←検索の実行>>> res = re.finditer( ptn, txt )Enter>>> for i in res: Enter...
print( i.span() )
...
Enter

←検索結果を全て表示する処理←行末の 1 つだけ一致(13, 16)
置換処理：

4.3.2

Enter

re.sub正規表現のパターンにマッチする文字列を別の文字列に置き換える（置換処理）には sub メソッドを使用する．
例．数字列の部分を「数字」に置換する：その 1>>> tx1 = ’abc123def456’←数字を含む文字列Enter>>> re.sub(r’￥d+’,’ 数字’,tx1)’abc 数字 def 数字’←置換結果←数字の部分を「数字」に置換

Enter

このように sub メソッドは置換結果の文字列を返す．

sub メソッドとは別の subn メソッドもある．これは置換処理に加えて，置換処理の対象となった部分の個数も取得
する．
例．数字列の部分を「数字」に置換する：その 2（先の例の続き）>>> re.subn(r’￥d+’,’ 数字’,tx1)
Enter←数字の部分を「数字」に置換(’abc 数字 def 数字’, 2)←置換結果と置換個数のタプル
4.3.2.1

複数行に渡る置換処理

複数行に渡る文字列（テキスト）の各行を置換処理する場合について考える．次のように各行の先頭に空白文字を持つテキストを想定する．
例．行頭に空白文字を持つテキスト>>> tx1 = ’

1 行目￥n>>> print( tx1 )

Enter

1 行目
2 行目
3 行目

2 行目￥n

3 行目’

Enter

← 3 行に渡るテキスト←内容確認←テキストが← 3 行にわたる←文字列になっている

このようなテキスト tx1 の各行の先頭にある空白文字列を除去する試みを次に示す．
例．行頭の ‘￥d+’ にマッチする部分を空白文字に置き換える試み>>> tx2 = re.sub( r’^￥s+’, ’’, tx1 )Enter← ‘ˆ’ を応用した行頭の置換処理←内容確認>>> print( tx2 )

Enter

1 行目
2 行目
3 行目

←最初の行のみ置換処理されている←置換処理されていない←置換処理されていない

この例のように，行頭でのパターンマッチが最初の行にのみ有効になっている．これは，tx1 のテキストの内容が複数の行に渡っているものの，文字列データとしては 1 行であることが原因である．

226

改行コードを含むテキストを複数の行から成るものと見なして，各行を別々に扱って置換処理するには sub メソッドにキーワード引数 ‘ﬂags=re.MULTILINE’ を与える．
例．テキストの各行を別々に扱う形での置換処理>>> tx2 = re.sub( r’^￥s+’, ’’, tx1, flags=re.MULTILINE )>>> print( tx2 )
1 行目
2 行目
3 行目
4.3.2.2

Enter←行頭の置換処理

←内容確認

Enter

←置換処理されている←置換処理されている←置換処理されているパターンマッチのグループを参照した置換処理

sub メソッドに与える正規表現にも括弧 ‘(〜)’ で括ったグループの記述が応用できる．
例．マッチしたグループを参照した置換処理>>> tx1 = ’6638137 兵庫県西宮市池開町’Enter←郵便番号と地域>>> re.sub( r’(￥d{3})(￥d{4})(.*)’, r’￥1-￥2 ￥3’, tx1 )’663-8137 兵庫県西宮市池開町’

Enter←グループを用いた置換処理←置換結果

この例では ’6638137 兵庫県西宮市池開町’ という文字列の中からパターンマッチでいくつかのグループを取り出し，それら（「￥」に番号を付けて参照）を用いて置換処理を行っている．
第 1 のグループとして ‘(￥d{3})’ を記述しており「数字 3 文字」のパターンでマッチさせる．同様に第 2 のグループとして ‘(￥d{4})’ を記述しており「数字 4 文字」のパターンをマッチさせる．残りの部分（第 3 のグループ）は‘(.*)’ と記述して任意の文字列をマッチさせる．これらグループは「￥」に番号を付けて参照することができ，sub メ
ソッドの第 2 引数のパターンの中の記述に使用されている．

4.3.3

文字列の分解への応用：

re.split

re.split を用いると，正規表現のパターンにマッチする部分を区切りにして文字列を分解することができる．
例．数字列を区切りにして文字列を分解>>> tx1 = ’abc123def456ghi’

Enter←数字列で区切られた文字列>>> re.split( r’￥d+’, tx1 )Enter←正規表現を用いた分割処理[’abc’, ’def’, ’ghi’]←分解結果（リストで得られる）

227

4.4

マルチスレッドとマルチプロセス

4.4.1

マルチスレッド

Python ではスレッド（thread）の考え方に基いて複数のプログラムを同時に並行して実行する163 ことができる．
具体的には，threading モジュールを使用して関数やメソッドをメインプログラムから独立したスレッドとして実行する．このモジュールを使用するには次のようにして読み込む．

import threading《 スレッド管理のための基本的なメソッド 》● スレッドの生成（コンストラクタ）
threading.Thread( target=関数（メソッド）の名前,
args=(引数の並びのタプル), kwargs=キーワード引数の辞書 )このメソッドの実行によりスレッドが生成され，それがスレッドオブジェクト（Thread クラス）として返される．
● スレッドの実行
スレッドオブジェクト.start()
start メソッドの実行により，スレッドの実行が開始する．この後，スレッドオブジェクトの ident 属性からスレッド ID （整数値）が得られる．
● スレッドの終了の同期
スレッドオブジェクト.join()
スレッドが終了するまで待つ．

2 つの関数を別々のスレッドとして実行するプログラム test12-1.py を示す．
プログラム：test12-1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8
import threading
import time

例．スクリプト test12-1.py の実行結果
Thread-1

def th_1 ( name ):# 第1 ス レ ッ ド
for i in range (8):print ( name )time . sleep (1)Thread-2
Thread-1
Thread-2
Thread-1
Thread-1

def th_2 ( name ):# 第2 ス レ ッ ド
for i in range (3):print ( ’\t ’ , name )time . sleep (2)Thread-2
Thread-1
Thread-1# スレッドの生成
t1 = threading . Thread (target = th_1 , args =( ’ Thread -1 ’ ,))t2 = threading . Thread (target = th_2 , args =( ’ Thread -2 ’ ,))# スレッドの開始
t1 . start ();t2 . start ()Thread-2 ended
Thread-1
Thread-1
Thread-1 ended

2 つのスレッドが同時に独立して動作していることがわかる．

# スレッドの終了待ち
t2 . join (); print ( ’\ tThread -2 ended ’)t1 . join (); print ( ’ Thread -1 ended ’)

解説
このプログラムでは関数 th 1 と th 2 を別々のスレッドとして実行する．16〜19 行目で引数を付けてスレッドを生成している．今回の例では引数の個数は 1 つなので，これをタプルとして渡すために，スレッドとなる関数に渡す引数の列の最後にコンマ ’,’ を付けている．21 行目でスレッドを開始し，24,25 行目でそれらの終了を待機している．
163 マルチスレッドプログラミングにおいては，実際にはプログラムは「同時に並行」して実行されず，Python インタプリタの実行時間を

各スレッドに分割配分する．後述のマルチプロセスプログラミングでは，CPU やコアの数によって「同時に並行」して実行されること
がある．

228

■ スレッドにキーワード引数を渡す例

Thread オブジェクト生成時に ‘target=’ で指定した関数にキーワード引数を渡す場合はそれらを辞書の形で ‘kwargs=’に渡す．
例．キーワード引数を取る関数の定義>>> def job(x,**kwa): Enter←キーワード引数を取る関数 job...
print(’ 第 1 引数:’,x)
Enter
...
print(’ キーワード引数:’,kwa)
Enter
...
Enter
←関数定義の記述の終了
Enter>>> job(3,a=11,b=12,c=13)
第 1 引数: 3
キーワード引数:←関数 job の実行{’a’:11, ’b’:12, ’c’:13}←出力←キーワード引数の値

この関数をスレッドで実行するには次のようにする．
例．スレッドの関数にキーワード引数を渡す>>> import threading↓スレッド生成Enter>>> th = threading.Thread(target=job,args=(3,),kwargs={’a’:11,’b’:12,’c’:13})
第 1 引数: 3
キーワード引数:

4.4.1.1←スレッドを実行

Enter>>> th.start()

Enter{’a’:11, ’b’:12, ’c’:13}←出力←キーワード引数の値

スレッドの実行状態の確認

スレッドが実行中かどうかを確認するには，当該スレッドオブジェクトに対して is alive メソッドを実行する．このメソッドは，当該スレッドが実行中の場合は True を，そうでなければ False を返す．

is alive メソッドでスレッドの終了を判定するサンプルプログラム test12-2.py を示す．
プログラム：test12-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8
import threading
import time
def th ( n ):for i in range ( n ):time . sleep (1)# スレッドとして実行する関数# スレッドの生成
th_lst = []for i in range (5):t = threading . Thread ( target = th , args =( i +1 ,))th_lst . append ( t )t . start ()time . sleep (0.3)# タイミング調整

while True :# スレッド実行監視ループ
st = []
for t in th_lst :st . append ( t . is_alive () )print ( ’ ス レ ッ ド 実 行 状 態 : ’ , st )time . sleep (1)if not any ( st ):
break

解説．
プログラム中に定義されている関数 th はスレッドとして実行するもので，引数に与えた秒数が経過した後で終了する．11〜14 行目の for 文で，関数 th をスレッドとして 5 つ実行し，それらのスレッドオブジェクトのリストを th lstに保持している．
このプログラムは join メソッドによってスレッドの終了を待機するのではなく．全てのスレッドの終了を定期的に確認することで処理を終了させる方法を取っている．18 行目以降の部分は，全てのスレッドが終了しているかどうか

229

を繰り返し確認（1 秒間隔）するもので，全スレッドが終了していればプログラムを終了する．この際のスレッド状
態の確認に is alive メソッドを用いている．また，繰り返し処理の各回で 5 つのスレッドの実行状態のリストを st に作成（19〜21 行目）し，st の全ての要素が False になった段階（24 行目）で break によって while の繰り返しを終了している．
このプログラムを実行した例を次に示す．
実行例．
スレッド実行状態:
スレッド実行状態:
スレッド実行状態:
スレッド実行状態:
スレッド実行状態:
スレッド実行状態:[True, True, True, True, True][False, True, True, True, True][False, False, True, True, True][False, False, False, True, True][False, False, False, False, True][False, False, False, False, False]

スレッドの実行状態のリスト（変数 st）が 1 秒間隔で出力されることが確認できる．

4.4.1.2

実行中のスレッドのリストを取得する方法

enumerate 関数を使用すると，実行中のスレッドのリストが得られる．
書き方：

threading.enumerate()

Thread オブジェクトのリストが得られる．ただし，この方法で得られるリストには Python のメインプログラムのスレッドも含まれている．

4.4.1.3

スレッド間の排他制御

threading.Thread オブジェクトによるスレッドとして関数を実行する際，その関数からの戻り値を直接的に受け取る方法はなく，スレッドからの情報を受取るにはグーローバル変数を介するなど間接的な方法に頼ることになる．ここでは，複数のスレッドがグローバル変数を共有してアクセスする場合の注意点などについて解説する．
以下に示すサンプルプログラム threadShare01-1.py は，複数のスレッド（そのための関数）が 1 つのグローバル変数を共有してその値を更新する例である．
（あまり良くない例）
プログラム：threadShare01-1.py（あまり良くない例）
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# coding : utf -8
import threading
import time
shr = 0

# スレッドで共有する変数

def th ( n ):# スレッドとして実行する関数
global shr
for m in range (10):shr += 1# 共 有 変 数 の 値 を1 増 加
time . sleep (0.01)# 少し待つ# 10 個 の ス レ ッ ド を 生 成
thList = [ threading . Thread ( target = th , args =( n ,)) for n in range (10) ]for t in thList : t . start () # タ イ ミ ン グ を ず ら し な が ら 全 ス レ ッ ド を 実 行
for t in thList : t . join ()# 全スレッドの終了待ち
print ( ’ 全 ス レ ッ ド 終 了 ． shr = ’ , shr )解説．
このプログラムでは，スレッドとして実行するための関数 th が定義されており，この関数はグローバル変数 shr の値を 1 増加させる処理を約 1 秒間に渡って 10 回実行する．この関数を 10 個のスレッドにして（14 行目）同時に実行（16 行目）し，全てのスレッドの終了を待機（17 行目）する．
このプログラムをスクリプトとして実行すると全スレッド終了．shr = 100と出力される．変数 shr の初期値は 0 であり，それを 1 増加させる処理を 10 回実行するスレッドを 10 個実行しているので当然の結果（10 × 10 → 100）のように思われる．しかし，複数のプログラム（スレッドなど）が平行して実行

230

される状況においては，共有資源へのアクセスの衝突の問題を意識しなければならない．これに関して次のサンプルプログラム threadShare01-2.py を用いて考察する．
プログラム：threadShare01-2.py（アクセス衝突の例）
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# coding : utf -8
import threading
import time
shr = 0

# スレッドで共有する変数

def th ( n ):# スレッドとして実行する関数
global shr
for m in range (10):tmp = shr
# 共有変数の値をローカル変数に読取り
time . sleep (0.007)# 少し待つtmp += 1# ロ ー カ ル 変 数 の 値 を1 増 加
shr = tmp
# ローカル変数の値を共有変数に上書き# 10 個 の ス レ ッ ド を 生 成
thList = [ threading . Thread ( target = th , args =( n ,)) for n in range (10) ]for t in thList :# タイミングをずらしながら全スレッドを実行
t . start ()time . sleep (0.01)
for t in thList : t . join ()# 全スレッドの終了待ち
print ( ’ 全 ス レ ッ ド 終 了 ． shr = ’ , shr )このプログラムは先の threadShare01-1.py に似ているが，関数 th の定義が少し異なり，共有変数 shr の値をローカ
ル変数 tmp に複製（10 行目）して少し待った（11 行目）後，tmp の値を 1 増加させて共有変数 shr に上書き（13 行目）している．このプログラムでは，1 つのスレッドが time.sleep 関数で待っている間に他のスレッドが同様の処理をしており，変数 shr へのアクセスの衝突が起こる．
このプログラムをスクリプトとして実行すると全スレッド終了．shr = 22などと出力される．
（処理環境によって shr の最終値が異なる）■ ロックオブジェクト

Python のマルチスレッド処理では，ロックオブジェクト（lock オブジェクト）を用いることによって，スレッド間の共有資源へのアクセスにおける排他制御が実現できる．lock オブジェクトは Lock 関数で生成することができ，

acquire，release を用いて排他制御の対象のプログラム範囲を指定する．
《ロックオブジェクトによる排他制御》

lock オブジェクト.acquire()：（排他制御するプログラムの記述）：
lock オブジェクト.release()lock オブジェクトは，互いに排他制御を行うスレッド間で同一のものを用いること．
これに関して次のサンプルプログラム threadShare01-3.py を用いて解説する．
プログラム：threadShare01-3.py（排他制御の例）
1
2
3
4
5
6
7
8
9

# coding : utf -8
import threading
import time
L = threading . Lock ()shr = 0
def th ( n ):global shr# lockオブジェクトの生成# スレッドで共有する変数# スレッドとして実行する関数

231

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

for m in range (10):
L . acquire ()# 排他制御範囲（ここから）
tmp = shr
# 共有変数の値をローカル変数に読取り
time . sleep (0.007)# 少し待つtmp += 1# ロ ー カ ル 変 数 の 値 を1 増 加
shr = tmp
# ローカル変数の値を共有変数に上書き
L . release ()# 排他制御範囲（ここまで）# 10 個 の ス レ ッ ド を 生 成
thList = [ threading . Thread ( target = th , args =( n ,)) for n in range (10) ]for t in thList :# タイミングをずらしながら全スレッドを実行
t . start ()time . sleep (0.01)
for t in thList : t . join ()# 全スレッドの終了待ち
print ( ’ 全 ス レ ッ ド 終 了 ． shr = ’ , shr )このプログラムでは 5 行目で lock オブジェクト L を生成している．11 行目に acquire メソッドを，16 行目に release
メソッドを記述しており，この範囲のプログラムが排他制御の対象となる．すなわち，あるスレッドがこの範囲を実行しているときに他のスレッドが同じ部分を実行しようとすると，先に実行しているスレッドが release の部分に到達するまで待たされる．この排他制御により，上のプログラムでは変数 shr へのアクセスの衝突が回避できる．
このプログラムをスクリプトとして実行すると全スレッド終了．shr = 100と出力される．
参考）排他制御は with 構文（後の「4.20 with 構文」（p.302）で解説する）にも対応しており，threadShare01-3.pyの関数 th の定義を次のように簡略化することもできる．
記述例：
1
2
3
4
5
6
7
8

def th ( n ):# スレッドとして実行する関数
global shr
for m in range (10):with L :# 排他制御の対象部分
tmp = shr
# 共有変数の値をローカル変数に読取り
time . sleep (0.007)# 少し待つtmp += 1# ロ ー カ ル 変 数 の 値 を1 増 加
shr = tmp
# ローカル変数の値を共有変数に上書き注意）
最初のサンプルプログラム threadShare01-1.py においては，共有変数 shr へのアクセスの記述は，その変数の値を1 増加させる文1 行のみであるため，CPython 実装においては GIL（Global Interpreter Lock）164 によって結果的にアクセスの衝突が起こらないことになる．しかし，複数のスレッドで計算機資源を共有する場合は常にアクセスの衝突を意識しなければならない．
参考）
先のサンプルプログラムでは，グローバル変数 shr をスレッド間で共有しているが，これは実際のプログラミング
ではあまり好ましくない．実際のプログラミングでは情報の共有をする場合はそれらを何らかのオブジェクトの形にして，それをスレッド用関数の引数に渡すといった工夫をするべきである．
本書に示したサンプルプログラムでは，解説を簡素にするため，例外処理を施していない．実際のプログラミングでは十全な例外処理を施すこと．

164 CPython 実装では複数のスレッドが同時に実行されていても，ある瞬間に実行されているプログラムのステップは 1 つのみであるという制約．これに関する詳細は本書では割愛する．

232

4.4.2

マルチプロセス

マルチプロセスプログラミングでは，プログラムの実行単位（関数の実行など）を，独立したプロセスとして実行する．
このため，複数の CPU やコアを搭載した計算機環境においては，OS の働きによって各プロセスの実行が複数の CPU
やコアに適切に割り当てられる．Python には，マルチプロセスプログラミングのためのモジュール multiprocessingが標準的に提供されている．このモジュールを使用するには次のようにして Python 言語処理系に読み込む．

import multiprocessing
multiprocessing ライブラリが提供する API は threading ライブラリのものと使用方法がよく似ており，それらと対比しながら理解すると良い．

《 プロセス管理のための基本的なメソッド 》● プロセスの生成（コンストラクタ）
multiprocessing.Process( target=関数（メソッド）の名前,
args=(引数の並びのタプル), kwargs=キーワード引数の辞書 )このメソッドの実行によりプロセスが生成され，それがプロセスオブジェクト（Process クラス）として返される．
● プロセスの実行
プロセスオブジェクト.start()
start メソッドの実行により，プロセスの実行が開始する．この後，当該プロセスオブジェクトの pid 属性からプロセス ID （PID：整数値）が得られる．
● プロセス終了の同期
プロセスオブジェクト.join()
プロセスが終了するまで待つ．

2 つの関数を別々のプロセスとして実行するプログラム test12-1mp.py を示す．
プログラム：test12-1mp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8
import multiprocessing
import time

例．スクリプト test12-1.py の実行結果

def pr_1 ( name ):# 第1 プ ロ セ ス 用 関 数
for i in range (8):print ( name )time . sleep (1)def pr_2 ( name ):# 第2 プ ロ セ ス 用 関 数
for i in range (3):print ( ’\t ’ , name )time . sleep (2)if __name__ == ’ __main__ ’:# プロセスの生成
p1 = multiprocessing . Process (target = pr_1 , args =( ’ Process -1 ’ ,))p2 = multiprocessing . Process (target = pr_2 , args =( ’ Process -2 ’ ,))# プロセスの開始
p1 . start ();p2 . start ()# スレッドの終了待ち
p2 . join (); print ( ’\ tProcess -2 ended ’)
p1 . join (); print ( ’ Process -1 ended ’)Process-1
Process-2
Process-1
Process-1
Process-2
Process-1
Process-1
Process-2
Process-1
Process-1
Process-2 ended
Process-1
Process-1 ended

2 つのプロセスが同時に独立して動作していることがわかる．

解説
このプログラムでは関数 pr 1 と pr 2 を別々のプロセスとして実行する．17〜20 行目で引数を付けてプロセスを生成している．今回の例では引数の個数は 1 つなので，これをタプルとして渡すために，プロセスとなる関数に渡す引数の列の最後にコンマ ’,’ を付けている．22 行目でプロセスを開始し，24,25 行目でそれらの終了を待機している．

233

4.4.2.1

プロセスごとに実行されるモジュール

各プロセスはそれぞれ独自の CPU リソースと仮想記憶空間を持つので，プロセスオブジェクトが start メソッドで実行を開始する際，そのプロセスのリソースとしてスクリプト全体を（モジュールとして）再度読み込む．このことは，複数のプロセスを生成して起動する際に問題を起こすことがある．例えば，起動された各々のプロセス内では当該スクリプトが再度読み込まれて実行されるので，各種オブジェクトを生成する処理の記述があると，それらの処理が各々のプロセス内で再度（不必要に）実行されてしまう．特に，スクリプト内にプロセスオブジェクトの生成と実行の処理が記述されていると，それらが，プロセス起動時に再帰的に（無限に）実行されることになる．
先のプログラム test12-1mp.py では，プロセスの生成と実行の処理を行う部分を

if

name

== ’ main ’:

以下に記述している．これにより，プロセスオブジェクトの生成と実行が再帰的に（無限に）実行されることを防いでいる．すなわち，スクリプト test12-1mp.py が最初に Python 言語処理系によって実行されたときは，そのスクリプトのモジュール名は’ main ’ であるのでこの if 文内のスイートが実行されるが，各プロセスの起動時に test12-1mp.py
が再度読み込まれた際はモジュール名が別の名前165 になるので，if 文のスイートは実行されず，プロセス生成と実行が再帰的に起こることはない．
モジュールの概念と，実行されるスクリプトのモジュール名については後の「4.8 モジュール，パッケージの作成による分割プログラミング」（p.272）で詳しく解説する．

4.4.2.2

プロセスの実行状態の確認プロセスの実行状態の確認も threading の場合と同様に is alive メソッドで行う．
プログラム：test12-2mp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8
import multiprocessing
import time
def pr ( n ):for i in range ( n ):time . sleep (1)# プロセスとして実行する関数

if __name__ == ’ __main__ ’:# プロセスの生成と開始
pr_lst = []for i in range (5):p = multiprocessing . Process ( target = pr , args =( i +1 ,))pr_lst . append ( p )p . start ()time . sleep (0.3)# タイミング調整
while True :# プロセス実行監視ループ
st = []
for p in pr_lst :st . append ( p . is_alive () )print ( ’ プ ロ セ ス 実 行 状 態 : ’ , st )time . sleep (1)if not any ( st ):
break

解説．
プログラム中に定義されている関数 pr はプロセスとして実行するもので，引数に与えた秒数が経過した後で終了する．12〜15 行目の for 文で，関数 pr をプロセスとして 5 つ実行し，それらのプロセスオブジェクトのリストを pr lstに保持している．
このプログラムは join メソッドによってプロセスの終了を待機するのではなく．全てのプロセスの終了を定期的に確認することで処理を終了させる方法を取っている．18 行目以降の部分は，全てのプロセスが終了しているかどうかを繰り返し確認（1 秒間隔）するもので，全プロセスが終了していればプログラムを終了する．この際のプロセス状態の確認に is alive メソッドを用いている．また，繰り返し処理の各回で 5 つのプロセスの実行状態のリストを st に
165 CPython では

mp mainとなる．

234

作成（19〜21 行目）し，st の全ての要素が False になった段階（24 行目）で break によって while の繰り返しを終了している．
このプログラムを実行した際の出力例を次に示す．
例．test12-2mp.py 実行の際のコンソール出力
プロセス実行状態:
プロセス実行状態:
プロセス実行状態:
プロセス実行状態:
プロセス実行状態:
プロセス実行状態:

4.4.2.3[True, True, True, True, True][False, True, True, True, True][False, False, True, True, True][False, False, False, True, True][False, False, False, False, True][False, False, False, False, False]

実行中プロセスのリストを取得する方法

active children 関数を使用すると，実行中のプロセスのリストが得られる．
書き方：

multiprocessing.active children()

Process オブジェクトのリストが得られる．ただし，この方法で得られるリストにはメインプログラムのプロセスは含まれない．

4.4.2.4

プロセスの強制終了

Process オブジェクトに terminate メソッドを実行することで，そのプロセスの実行を強制終了することができる．
書き方：

Process オブジェクト.terminate()「Process オブジェクト」のプロセスが実行中の場合はそれを強制終了する．実行中でない場合は何もしない．terminate
メソッドは値を返さない（None）．

terminate メソッドでプロセスを強制終了する例を ProcTerminate01.py に示す．
プログラム：ProcTerminate01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# coding : utf -8
import multiprocessing
import time
def pr ( ):# プロセスとして実行する関数
while True :# 際限なく実行される処理
time . sleep (1)if __name__ == ’ __main__ ’:# プロセスの生成と開始
pr_lst = []for i in range (5):p = multiprocessing . Process ( target = pr , args =())
pr_lst . append ( p )p . start ()time . sleep (0.3)# タイミング調整
st = [ p . is_alive () for p in pr_lst ]print ( ’ プ ロ セ ス 実 行 状 態 : ’ , st )while True :# プロセス実行監視ループ
try :# 終了対象プロセスのインデックスを入力
n = int ( input ( ’ number to kill > ’) )except ValueError : # 入 力 が 数 値 で な け れ ば
n = 5# 5と す る
if 0 <= n <= 4:
pr_lst [ n ]. terminate ()# プロセスを終了
pr_lst [ n ]. join ()# 終了の待機st = [ p . is_alive () for p in pr_lst ]print ( ’ プ ロ セ ス 実 行 状 態 : ’ , st )if not any ( st ):# 全 て Falseならbreak# このプログラムを終了

このプログラムでは，プロセスとして実行する関数 pr を定義しており，この関数は自発的には終了しない（無限ループ）．この関数を 5 つのプロセスとして同時に実行し，それらをリスト pr lst にして管理する．また，プロセス235

の実行状態をリスト st にして表示する．キーボードから入力したインデックスのプロセスを terminate メソッドで終了して，全てのプロセスが終了した時点で当該プログラムは終了する．
このプログラムを実行した際のコンソールの出力例を次に示す．
例．ProcTerminate01.py 実行の様子
プロセス実行状態:[True, True, True, True, True]← 5 つのプロセスが実行中

number to kill> 4
プロセス実行状態: [True, True, True, True, False]←インデックス 4 のプロセスを終了← 4 つのプロセスが実行中

number to kill> 0
プロセス実行状態: [False, True, True, True, False]←インデックス 0 のプロセスを終了← 3 つのプロセスが実行中

number to kill> 3
プロセス実行状態: [False, True, True, False, False]←インデックス 3 のプロセスを終了← 2 つのプロセスが実行中

number to kill> 1
プロセス実行状態: [False, False, True, False, False]←インデックス 1 のプロセスを終了← 1 つのプロセスが実行中

number to kill> 2
プロセス実行状態: [False, False, False, False, False]←インデックス 2 のプロセスを終了←全てのプロセスが終了

4.4.2.5

共有メモリと排他制御

各プロセスはそれぞれ独自の CPU リソースと仮想記憶空間を持つので，プロセス間での情報共有には特別な方法が必要となる．ここでは multiprocessing ライブラリが提供する共有メモリのための機能について解説する．
■ Value オブジェクトによる共有メモリ

Value オブジェクトは，1 つの値をプロセス間で共有するためのものであり，作成には次のよう記述する．
書き方：

Value( 型コード, 初期値 )「型コード」で指定された型のデータを持つ Value オブジェクトを作成して返す．その値には value 属性としてアクセスする．Value オブジェクトは作成時に「初期値」を設定することができる．
「型コード」は表 33 に挙げる文字列である．
表 33: 型コード
整数
コード

解

説

C 言語での型’b’

符号付き 8 ビット整数

char

’B’

符号なし 8 ビット整数

unsigned char’h’

符号付き 16 ビット整数

short

’H’

符号なし 16 ビット整数

unsigned short’i’

符号付き 32 ビット整数

int

’I’

符号なし 32 ビット整数

unsigned int’l’

符号付き 32 ビット長整数

long

’L’

符号なし 32 ビット長整数

unsigned long’q’

符号付き 64 ビット長長整数

long long’Q’

符号なし 64 ビット長長整数

unsigned long long

浮動小数点数コード

解説

C 言語での型’f’

単精度浮動小数点数（32 ビット） ﬂoat’d’

倍精度浮動小数点数（64 ビット） double
その他

コード

’c’

解

説

C 言語での型

ASCII の 1 文字（例．b’a’）

char

Value オブジェクトはプロセス用関数の引数として渡して共有するのが一般的である．

236

■ ロックオブジェクト

threading ライブラリの場合と同様（p.231）に，ロックオブジェクト（lock オブジェクト）によってプロセス間での共有メモリの排他制御ができる．ロックオブジェクトは，互いに排他制御を行うプロセスの間で同一のものを用いること．
先に示したマルチスレッドの排他制御のサンプルプログラム threadShare01-3.py （p.231）に倣い，マルチプロセス
で同様の処理を実現した procShare01.py 示す．
プログラム：procShare01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# coding : utf -8
import multiprocessing
import time
def pr (n , shr , L ):# プロセスとして実行する関数
for m in range (10):
L . acquire ()# 排他制御範囲（ここから）
tmp = shr . value# 共有変数の値をローカル変数に読取り
time . sleep (0.007)# 少し待つtmp += 1# ロ ー カ ル 変 数 の 値 を1 増 加
shr . value = tmp# ローカル変数の値を共有変数に上書き
L . release ()# 排他制御範囲（ここまで）
if __name__ == ’ __main__ ’:
L = multiprocessing . Lock ()# Lockオブジェクトの生成
shr = multiprocessing . Value ( ’i ’ , 0)
# プロセス間で共有するオブジェクト# 10 個 の プ ロ セ ス を 生 成
prList = [ multiprocessing . Process ( target = pr , args =( n , shr , L ))for n in range (10)]# タイミングをずらしながら全プロセスを実行
for p in prList :p . start ()time . sleep (0.01)# 全プロセスの終了待ち
for p in prList : p . join ()print ( ’ 全 プ ロ セ ス 終 了 ． shr . value = ’ , shr . value )このプログラムでは，Value オブジェクト shr を全プロセスで共有しており，ロックオブジェクト L によってそのアクセスを排他制御している．これにより shr.value の値が正常に増加し，コンソールで実行すると全プロセス終了．shr.value = 100と出力される．
参考）排他制御は with 構文（後の「4.20 with 構文」（p.302）で解説する）にも対応しており，procShare01.pyの関数 pr の定義を次のように簡略化することもできる．
記述例：
1
2
3
4
5
6
7

def pr (n , shr , L ):# プロセスとして実行する関数
for m in range (10):with L :# 排他制御範囲
tmp = shr . value# 共有変数の値をローカル変数に読取り
time . sleep (0.007)# 少し待つtmp += 1# ロ ー カ ル 変 数 の 値 を1 増 加
shr . value = tmp# ローカル変数の値を共有変数に上書き参考）ここで解説したもの以外にも multiprocessing ライブラリは多くのロック機能を提供している．詳しくはPython の公式インターネットサイトなどを参照のこと．
■ Array オブジェクト
データの配列をプロセス間で共有するには Array オブジェクトを用いる．作成には次のように記述する．
書き方：

Array( 型コード, 初期値 )「型コード」は Value オブジェクトの場合に準ずる．
「初期値」はリストなどの形で与える．Array オブジェクトの要
素へのアクセスには，リストの場合と同様の添字（スライス）が使える．

237

1 つの配列（Array オブジェクト）を複数のプロセスで共有してアクセスする例を procShare02.py に示す．
プログラム：procShare02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8
import multiprocessing
import time
def pr (n , shr , L ):time . sleep (1)L . acquire ()shr [ n ] = n
L . release ()# プロセスとして実行する関数# 1秒 待 機# 排他制御範囲（ここから）# 共有メモリ（配列）に値を設定# 排他制御範囲（ここまで）

if __name__ == ’ __main__ ’:
L = multiprocessing . Lock ()# Lockオブジェクトの生成
shr = multiprocessing . Array ( ’i ’ , [ -1]*5)# プロセス間で共有する配列
print ( ’ 初 期 状 態 : ’ , list ( shr ))# 5個 の プ ロ セ ス を 生 成
prList = [ multiprocessing . Process ( target = pr , args =( n , shr , L ))for n in range (5)]# 全プロセスを実行
for p in prList : p . start ()# 全プロセスの終了待ち
for p in prList : p . join ()print ( ’ 最 終 状 態 : ’ , list ( shr ))このプログラムでは，Array オブジェクト shr を複数のプロセスで共有し，各プロセスがその要素の値を書き換える．初期状態では shr の全要素は -1 であり，全てのプロセスが終了すると，各プロセスの起動順番 n に対応するイ
ンデックスの要素の値が n となる．
例．コンソールで procShare02.py を実行した際の出力
初期状態:
最終状態:

[-1, -1, -1, -1, -1][0, 1, 2, 3, 4]■ Manager

Manager を用いると，リストや辞書などを共有メモリとして使用することができる．具体的には，マルチプロセシ
ングマネジャオブジェクト（SyncManager クラスのオブジェクトで，単にマネジャと呼ぶことも多い）を作成し，それの下で共有リストや共有辞書を作成する．
書き方：

Manager()

この記述がマネジャを作成して返す．このようにして得られたマネジャで共有リスト，共有辞書を作成する．
共有リスト：
共有辞書：

マネジャ.list()
マネジャ.dict()

これらの記述で生成されたリストや辞書を，プロセス用の関数に引数として渡す．
共有リストを 2 つのプロセスで共有して更新する例を procShare03list.py に示す．
プログラム：procShare03list.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# coding : utf -8
from multiprocessing import Process , Lock , Manager
import time
def pr ( lst , e , L ):time . sleep (1)L . acquire ()lst . append ( e )L . release ()

#
#
#
#
#

# 必要機能を個別に読み込む

プロセス用関数少し待つ
排他制御（ここから）共有メモリのリストの処理
排他制御（ここまで）

if __name__ == ’ __main__ ’:
L = Lock ()# 排他制御のためのロックオブジェクト
M = Manager ()# 共 有 メ モ リ を 作 成 す る Manager
lst = M . list ()# 共有メモリとしてのリスト
p1 = Process ( target = pr , args =( lst , ’a ’ , L ))# 1番 目 の プ ロ セ ス
p2 = Process ( target = pr , args =( lst , ’b ’ , L ))# 2番 目 の プ ロ セ ス
p1 . start ();p2 . start ()# 2つ の プ ロ セ ス を 起 動
p1 . join ();p2 . join ()# 2つ の プ ロ セ ス の 終 了 を 待 機

238

19

print ( ’ 処 理 結 果 : ’ , lst )このプログラムでは，共有リスト lst を 2 つのプロセス p1，p2 で共有して要素を追加する．このプログラムを実行すると「処理結果: [’a’, ’b’]」と出力される．p1，p2 の実行のタイミングによっては「処理結果: [’b’, ’a’]」と出力されることもある．
共有辞書を 2 つのプロセスで共有して更新する例を procShare03dict.py に示す．
プログラム：procShare03dict.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# coding : utf -8
from multiprocessing import Process , Lock , Manager
import time
def pr ( d , k , v , L ):time . sleep (1)L . acquire ()d[k] = v
L . release ()

#
#
#
#
#

# 必要機能を個別に読み込む

プロセス用関数少し待つ
排他制御（ここから）共有メモリの辞書の処理
排他制御（ここまで）

if __name__ == ’ __main__ ’:
L = Lock ()# 排他制御のためのロックオブジェクト
M = Manager ()# 共 有 メ モ リ を 作 成 す る Manager
d = M . dict ()# 共有メモリとしての辞書
p1 = Process ( target = pr , args =( d , ’ apple ’ , ’ り ん ご ’ , L ))# 1番 目 の プ ロ セ ス
p2 = Process ( target = pr , args =( d , ’ orange ’ , ’ み か ん ’ , L ))# 2番 目 の プ ロ セ ス
p1 . start ();p2 . start ()# 2つ の プ ロ セ ス を 起 動
p1 . join ();p2 . join ()# 2つ の プ ロ セ ス の 終 了 を 待 機
print ( ’ 処 理 結 果 : ’ , d )このプログラムでは，共有辞書 d を 2 つのプロセス p1，p2 で共有してエントリを追加する．このプログラムを実行すると「処理結果: {’apple’: ’ りんご’, ’orange’: ’ みかん’}」と出力される．p1，p2 の実行のタイミングによっては「処理結果: {’orange’: ’ みかん’, ’apple’: ’ りんご’}」と出力されることもある．
【Manager の名前空間】

Manager が提供する名前空間（Namespace ）を使用すると，リストや辞書に限らず様々な型のデータをプロセス間で共有することができる．
書き方：

マネジャ.Namespace()「マネジャ」の下で名前を管理する名前空間プロキシオブジェクト（NamespaceProxy クラス）を生成して返す．
名前空間プロキシではドット表記の属性管理ができる．
書き方：

名前空間プロキシ. 属性名

この形式で値の代入や参照ができる．
名前空間プロキシを 2 つのプロセスで共有する例を procShare03ns.py に示す．
プログラム：procShare03ns.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# coding : utf -8
from multiprocessing import Process , Lock , Manager
import time
def pr1 ( ns , L ):time . sleep (1)L . acquire ()ns . i = 123;
L . release ()# 必要機能を個別に読み込む# プ ロ セ ス 用 関 数1
# 少し待つ# 排他制御（ここから）
ns . f = 3.14159;
ns . s = ’ 文 字 列 ’ ;# 排他制御（ここまで）

def pr2 ( ns , L ):# プ ロ セ ス 用 関 数2
time . sleep (1)# 少し待つL . acquire ()# 排他制御（ここから）
ns . lst = [ ’a ’ , ’b ’];ns . tpl = ( ’c ’ , ’d ’);ns . d = { ’ apple ’: ’ り ん ご ’ } ;ns . st = {7 ,11 ,13}
L . release ()# 排他制御（ここまで）
if __name__ == ’ __main__ ’:
L = Lock ()# 排他制御のためのロックオブジェクト

239

ns . b = True

M = Manager ()# 共 有 メ モ リ を 作 成 す る Manager
N = M . Namespace ()# 共有メモリ用の名前空間
p1 = Process ( target = pr1 , args =( N , L ))# 1番 目 の プ ロ セ ス
p2 = Process ( target = pr2 , args =( N , L ))# 2番 目 の プ ロ セ ス
p1 . start ();p2 . start ()# 2つ の プ ロ セ ス を 起 動
p1 . join ();p2 . join ()# 2つ の プ ロ セ ス の 終 了 を 待 機
print ( ’ 処 理 結 果 : ’ )print (f ’ N . i : { N . i } ,\ tN . f : { N . f } ,\ tN . s : { N . s } ,\ tN . b : { N . b } ’)print (f ’ N . lst : { N . lst } ,\ t \ tN . tpl : { N . tpl } , ’)print (f ’ N . d : { N . d } ,\ tN . st : { N . st } ’)

20
21
22
23
24
25
26
27
28
29

このプログラムでは，名前空間プロキシ N を 2 つのプロセス p1，p2 で共有し，各プロセスはそれの属性に対して値を設定する．このプログラムを実行した際の出力例を示す．
例．コンソールで procShare03ns.py を実行した際の出力
処理結果:
N.i: 123,
N.f: 3.14159,
N.lst: [’a’, ’b’],
N.d: {’apple’: ’ りんご’},

N.s: 文字列,
N.b:
N.tpl: (’c’, ’d’),
N.st: {11, 13, 7}

True

様々な型のデータが共有できていることがわかる．
参考）ここで解説したもの以外にも Manager は多くの機能を提供している．詳しくは Python の公式インターネット
サイトなどを参照のこと．
■ shared memory

Python 3.8 の版から，multiprocessing ライブラリに shared memory が提供されている．この中に定義されている
SharedMemory クラスは，プロセス間で共有する汎用の記憶域に関するものであり，次のようにしてコンストラクタを呼び出すことで共有メモリのインスタンスが生成される．
書き方：

SharedMemory( create=True, size=メモリサイズ )指定した「メモリサイズ」（バイト単位の整数値）の共有メモリを生成して返す．
共有メモリ（SharedMemory のインスタンス）の name プロパティにはその名前が文字列の形で保持されており，
子プロセス側ではこれを指定して既存の共有メモリを取得する．
書き方：

SharedMemory( name=名前 )「名前」を持つ既存の共有メモリのインスタンスを返す．
共有メモリが持つ記憶域（バッファ領域）は buf 属性としてアクセスできる．これは編集可能なバイト列であり，後の「4.13 編集可能なバイト列：bytearray」（p.285）で解説する bytearray 型のオブジェクトと同様の扱いが可能である．
共有メモリを使用している各プロセスにおいて，その使用を終了するには，close メソッドを実行する．
書き方：

共有メモリ.close()

また，共有メモリを廃棄（解放）するには unlink メソッドを実行する．
書き方：

共有メモリ.unlink()

次に示すサンプル procShare04.py は，2 つのプロセスが 1 つの共有メモリに値を書き込む処理の例である．
プログラム：procShare04.py
1
2
3
4
5
6
7
8
9
10
11
12
13

# coding : utf -8
from multiprocessing import Process , Lockfrom multiprocessing . shared_memory import SharedMemory# 必要なクラス# 共有メモリのクラス# プ ロ セ ス 用 関 数1
def pr1 ( n , L ):shr = SharedMemory ( name = n )# 名前を指定して共有メモリ名を取得
B = shr . buf# そのバッファ領域を取得
L . acquire ()B [0] = 0 xe5 ;B [1] = 0 x85 ;B [2] = 0 xb1# 「共」L . release ()shr . close ()# 共有メモリへのアクセスを終了

240

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# プ ロ セ ス 用 関 数2
def pr2 ( n , L ):shr = SharedMemory ( name = n )# 名前を指定して共有メモリ名を取得
B = shr . buf# そのバッファ領域を取得
L . acquire ()B [3] = 0 xe6 ;B [4] = 0 x9c ;B [5] = 0 x89# 「有」
L . release ()# 共有メモリへのアクセスを終了
shr . close ()if __name__ == ’ __main__ ’:
shr = SharedMemory ( create = True , size =6)# 共有メモリの作成
L = Lock ()# 排他制御のためのロックオブジェクト
p1 = Process ( target = pr1 , args =( shr . name , L )) # プ ロ セ ス 1
p2 = Process ( target = pr2 , args =( shr . name , L )) # プ ロ セ ス 2
p1 . start ();p2 . start ()# 2つ の プ ロ セ ス を 起 動
p1 . join ();p2 . join ()# 2つ の プ ロ セ ス の 終 了 を 待 機
s = bytes ( shr . buf ). decode ( ’ utf -8 ’)# 共有メモリの内容を文字列に変換して，print ( s )# 表示する．
shr . close ()# 共有メモリへのアクセスを終了
shr . unlink ()# 共有メモリの領域の解放

このプログラムでは pr1，pr2 が子プロセスとして起動され，共有メモリ shr のバッファ領域に値を書き込む．子プロセスが終了すると，メインプログラム側で shr のバッファ領域の内容を文字列に変換して出力する．

pr1 内では共有メモリのバッファの前半に「共」という文字の文字コード（utf-8）を書き込み，pr2 内では共有メ
モリのバッファの後半に「有」という文字の文字コードを書き込む．その後，メインプログラムは共有メモリのバッ
ファの内容を utf-8 エンコーディングで文字列に変換して出力する．
このプログラムを実行すると「共有」という文字が出力される．
【shared memory の応用例】

SharedMemory オブジェクトは汎用のバイト領域を持つので，様々な用途に応用できる．ここでは NumPy ライブ
ラリ166 が提供する数値配列をプロセス間で共有する事例を挙げる．以下に示す procShare05.py は，3 行 150 列の 2 次
元配列をプロセス間で共有し，三角関数の値を子プロセスで計算し，メインプログラムで計算結果をグラフにプロットする処理の例である．
プログラム：procShare05.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# coding : utf -8
from multiprocessing import Process , Lockfrom multiprocessing . shared_memory import SharedMemory
import numpy as np
import matplotlib . pyplot as plt

#
#
#
#

必要なクラス
共有メモリのクラス
数値演算ライブラリ
グラフ作成ライブラリ# プ ロ セ ス 用 関 数1
def pSin ( n , shape , type , L ):shr = SharedMemory ( name = n )# 名前を指定して共有メモリ名を取得# 共 有 メ モ リ を 元 に NumPy配列のビューを作る
shrA = np . ndarray ( shape , dtype = type , buffer = shr . buf )L . acquire ()shrA [1 ,:] = np . sin ( shrA [0 ,:] )# 正弦関数を算出
L . release ()shr . close ()# 共有メモリへのアクセスを終了# プ ロ セ ス 用 関 数2
def pCos ( n , shape , type , L ):shr = SharedMemory ( name = n )# 名前を指定して共有メモリ名を取得# 共 有 メ モ リ を 元 に NumPy配列のビューを作る
shrA = np . ndarray ( shape , dtype = type , buffer = shr . buf )L . acquire ()shrA [2 ,:] = np . cos ( shrA [0 ,:] )# 余弦関数を算出
L . release ()shr . close ()# 共有メモリへのアクセスを終了
if __name__ == ’ __main__ ’:dummy = np . zeros ((3 , 150))# メモリサイズを調べるためのダミー配列の作成

166 利用に際しては事前にインストールする必要あり．ライブラリの詳細については公式インターネットサイト https://numpy.org/ を参照のこと．

拙書「Python3 ライブラリブック」でも基本的な使用方法を解説しています．

241

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

shr = SharedMemory ( create = True , size = dummy . nbytes ) # 共 有 メ モ リ の 作 成# 共 有 メ モ リ の た め の NumPy配列のビューを作る
shrA = np . ndarray ( dummy . shape , dtype = dummy . dtype , buffer = shr . buf )del dummy# ダミーの消去# 配 列 の 先 頭 行 に x 軸 の 値 （ -2 π 〜 2 π ） を 設 定
shrA [0 ,:] = np . linspace ( -2* np . pi ,2* np . pi ,150)
L = Lock ()# 排他制御のためのロックオブジェクト
p1 = Process ( target = pSin , args =( shr . name , shrA . shape , shrA . dtype , L ))p2 = Process ( target = pCos , args =( shr . name , shrA . shape , shrA . dtype , L ))p1 . start ();p2 . start ()# 実行
p1 . join ();p2 . join ()# 終了の待機# 作図処理plt . figure ( figsize =(6 ,4) )plt . plot ( shrA [0 ,:] , shrA [1 ,:] , label = ’ sin ( x ) ’)plt . plot ( shrA [0 ,:] , shrA [2 ,:] , label = ’ cos ( x ) ’)plt . xlabel ( ’x ’);plt . ylabel ( ’y ’)
plt . title ( ’ Triangular Function : y = sin ( x ) , y = cos ( x ) ’)plt . grid ();plt . legend ()plt . show ()# 共有記憶の終了と廃棄
shr . close ()# 共有メモリへのアクセスを終了
shr . unlink ()# 共有メモリの領域の解放

このプログラムのメイン部で共有メモリ shr を生成している．この際，3 行 150 列の ndarray （NumPy の数値配列）に相当するサイズのバッファ領域を確保するため，dummy 配列を作成してそのバイトサイズを nbytes 属性で取得している．次に，shr のバッファ領域（shr.buf）を記憶域として持つ ndarray を shrA として作成（ndarray コン
ストラクタの引数 ’buﬀer=’ に記憶域を与える）し，以後，メイン部ではこの shrA を数値配列として使用する．
このプログラムでは，正弦関数の値を pr1（プロセス p1）で，余弦関数の値を pr2 （プロセス p2）で算出して共有メモリに書き込む．各プロセスには，共有メモリの名前が引数を介して与えられ，それを引用することで，メインプロセスが確保した共有メモリを取得している．また各プロセス内では，メインプロセスと同様の方法で，共有メモ
リから ndarray を作成している．
子プロセスの処理が全て終了して計算結果として完成した shrA の内容を，メイン部で matplotlib ライブラリ167 を使用（41〜47 行目）してグラフとしてプロットしている．
このプログラムを実行すると右のようなグラフがTriangular Function: y=sin(x), y=cos(x)表示される．

1.00

0.75

・plt.ﬁgure でグラフサイズを指定している．

0.50

・plt.plot でグラフを描画している．

0.25

y

・plt.xlabel，plt.ylabel で軸ラベルを書いている．

0.00

・plt.title でグラフタイトルを上部に書いている．

−0.25

・plt.grid で格子を描いている．

−0.50

・plt.legend で凡例を作成している．

−0.75

・plt.show で最終的にグラフを表示している．

−1.00

sin(x)
cos(x)

−6

−4

−2

0

2

4

6

x

procShare05.py の実行によって作成されたグラフ

167 利用に際しては事前にインストールする必要あり．ライブラリの詳細については公式インターネットサイト https://matplotlib.org/ を参照のこと．拙書「Python3 ライブラリブック」でも基本的な使用方法を解説しています．

242

4.4.3

concurrent.futures

Python 3.2 の版から並行プログラミングのためのライブラリ concurrent.futures が標準的に提供されている．このライブラリは，threading，multiprocessing ライブラリを基に構築されており，高機能な API を提供する．
このモジュールを使用するには次のようにして必要なモジュールを読み込む．

from concurrent import futures
注意）concurrent.futures モジュールを用いたマルチプロセスの実行は，モジュール名 mainとする．これは multiprocessing ライブラリの場合と同じ理由による．

4.4.3.1の下で行うもの

ProcessPoolExecutor

concurrent.futures には，マルチプロセスの形で関数を実行するための ProcessPoolExecutor というクラスが用意されており，このクラスのインスタンスが複数のプロセスの実行を管理する．具体的には，

futures.ProcessPoolExecutor(max workers=プールの最大数)と記述する．プールとは，一連のスレッドやプロセスを管理する作業の単位である．ProcessPoolExecutor の引数‘max workers=’ には使用するプロセスの最大値を与える168 ．これを省略すると当該環境の CPU の数が採用される．例えば，プールの最大数を 4 （最大 4 個のプロセスを管理）としてインスタンスを生成する場合は次のように記述する．

exe = futures.ProcessPoolExecutor(max workers=4)
この結果，exe というインスタンスが生成され，これに対して submit メソッドを実行することでプロセスを実行する
ことができる．例えば，ProcessPoolExecutor オブジェクト exe によって関数 f(’arg’) を実行するには，次のように記述する．

exe.submit(f,’arg’)
これによって，関数 f(’arg’) が独立したプロセスとして実行される．複数の引数を取る関数を実行するには，submitの引数にコンマで区切ってそのまま引数を書き並べる．

submit メソッドは Future オブジェクトを返し，これによってプロセスの実行を管理する．
submit メソッドによって起動した全てのプロセスが終了して ProcessPoolExecutor オブジェクトが不要になった際は shutdown メソッド実行する．
例．ProcessPoolExecutor オブジェクト exe の終了処理

exe.shutdown()
shutdown メソッドを実行すると，実行中のプロセスが全て終了するまで待ち，プロセス実行に使用した計算機資源が解放される．
重要）concurrent.futures モジュールには，ProcessPoolExecutor とは別に ThreadPoolExecutor クラスも提供されており，ProcessPoolExecutor クラスとほぼ同じ使用方法でマルチスレッドを実現する．
注意）ProcessPoolExecutor では multiprocessing ライブラリの共有メモリの一部機能（Value，Array，
SharedMemory）や Lock は使えるが，Manager は使うことができない．ProcessPoolExecutor はmultiprocessing の完全な上位互換ではないことに注意すること．

4.4.3.2

プロセスの実行状態と戻り値

プロセスの実行状態を調べるには，当該 Future オブジェクトに対して running メソッドを実行する．このメソッド
は，プロセスが「実行中」の場合に True を，そうでない場合に False を返す．ただし，実際にプロセスの関数が実行を開始する直前にプロセス管理の準備の処理が始まり，この段階から「実行中」となる．また，プロセスの関数が実行を終えた直後も短時間ではあるがプロセス管理の後処理があり「実行中」の状態が続く．
終了したプロセスの戻り値は当該 Future オブジェクトに対して result メソッドを実行することで得られる．
マルチプロセス実行に関するサンプルプログラム test12-3.py を示す．

168 これに関しては後の「4.4.3.3 同時に実行されるプロセスの個数について」（p.245）で例を挙げて解説する．

243

プログラム：test12-3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# coding : utf -8
from concurrent import futures
import time
def prc ( n ):# プロセスとして実行する関数
t0 = time . time ()for i in range ( n ):time . sleep (1)return time . time () - t0
# プロセスの実行
if __name__ == ’ __main__ ’:exe = futures . ProcessPoolExecutor ( max_workers =4)
prc_lst = []# Futureオブジェクト管理用のリスト
for i in range (4):f = exe . submit ( prc , i +1 )prc_lst . append ( f )# タイミング調整
time . sleep (0.3)# プロセス実行監視ループ
while True :st = []
for f in prc_lst :st . append ( f . running () )print ( ’ プ ロ セ ス の 実 行 状 態 : ’ , st )time . sleep (1)if not any ( st ):break
exe . shutdown ()# プロセスの戻り値の出力
for f in prc_lst :print ( f , ’ の 戻 り 値 : ’ , f . result () )解説．
プログラム中に定義されている関数 prc はプロセスとして実行するもので，引数に与えた秒数が経過した後，実際に実行に要した時間を返して終了する．15〜17 行目の for 文で，関数 prc をプロセスとして 4 つ実行し，それらのFuture オブジェクトのリストを prc lst に保持している．
21〜28 行目の部分は，全てのプロセスが終了しているかどうかを繰り返し確認（1 秒間隔）するもので，全プロセスが終了していれば各プロセスの戻り値を表示してプログラムを終了する．この際のスレッド状態の確認に running
メソッドを用いている．また，while による繰り返し処理の各回で 4 つのプロセスの実行状態のリストを st に作成（22〜24 行目）し，st の全ての要素が False になった段階（27 行目）で break によって while の繰り返しを終了する．
その後，31〜32 行目で各プロセスの戻り値を表示している．
このプログラムを実行した例を次に示す．
実行例．
プロセスの実行状態: [True, True, True, True]
プロセスの実行状態: [False, True, True, True]
プロセスの実行状態: [False, False, True, True]
プロセスの実行状態: [False, False, False, True]
プロセスの実行状態: [False, False, False, False]<Future at 0x1ec590a2b80 state=finished returned float> の戻り値:<Future at 0x1ec590b9b20 state=finished returned float> の戻り値:<Future at 0x1ec590b9f70 state=finished returned float> の戻り値:<Future at 0x1ec590cb070 state=finished returned float> の戻り値:

1.00010085105896
2.005520820617676
3.0089118480682373
4.012871980667114

注意）ProcessPoolExecutor はプロセスに引数を渡す，あるいは戻り値を受け取る際に pickle モジュール169 の機能を使用しているので，データの受け渡しにはこのことに由来する制約がある．

169 後の「4.10 オブジェクトの保存と読込み： pickle モジュール」（p.279）で解説する．

244

4.4.3.3

同時に実行されるプロセスの個数について

ProcessPoolExecutor のインスタンスを生成する際に与える引数 max workers=n は，同時に実行されるプロセスの個数の上限である．この値を超える個数のプロセスが submit メソッドによって投入された場合は，投入順に n 個のプロセスが実行され，それ以降のプロセスは実行待ちとなる．これについて，次のサンプルプログラム test12-4.py で確認する．
プログラム：test12-4.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# coding : utf -8
from concurrent import futures
import time
def prc ( n ):pname = ’p ’+ str ( n )print ( pname + ’ 開 始 ’ )time . sleep (0.5)
print ( pname + ’ 終 了 ’ )return pname# プロセスとして実行する関数# プロセスの実行
if __name__ == ’ __main__ ’:exe = futures . ProcessPoolExecutor ( max_workers =1)# 引数の値を変更して試す
prc_lst = []# Futureオブジェクト管理用のリスト
for i in range (4):f = exe . submit ( prc , i +1 )prc_lst . append ( f )# 全プロセス終了の同期
r = []
for f in futures . as_completed ( prc_lst ): r . append ( f . result ())# 終了処理print ( ’ 各 プ ロ セ ス の 戻 り 値 : ’ , r )exe . shutdown ()解説．
このプログラムでは関数 prc をプロセスとして実行する．この関数は実行開始のメッセージを出力した後 0.5 秒待ち，終了メッセージを出力して処理を終える．16〜18 行目の for 文で prc 関数をプロセスとして 4 個投入する．
このプログラムの max workers（14 行目）を変えて実行した例を次に示す．
実行例．max workers=1 の場合
p1 開始
p1 終了
p2 開始
p2 終了
p3 開始
p3 終了
p4 開始
p4 終了
各プロセスの戻り値 :同時に実行できるプロセス個数が 1 なので，各プロセスが 1 つずつ順番に開始，終了している様子がわかる．

[’p1’, ’p2’, ’p3’, ’p4’]

実行例．max workers=2 の場合
p1 開始
p2 開始
p1 終了
p2 終了
p3 開始
p4 開始
p3 終了
p4 終了
各プロセスの戻り値 :4.4.3.4

同時に実行できるプロセス個数が 2 なので，プロセスが 2 つずつ同時に開始，終了している様子がわかる．すなわち，p1,p2 が同時に開始し，これらが終了するまで p3,p4は実行されずに待っている．p1,p2 が終了
すると，次の p3,p4 が 2 つ同時に実行されている．

[’p1’, ’p2’, ’p3’, ’p4’]

プロセス終了の同期

as completed 関数を使用することでプロセスの終了を同期することができる．先のプログラム test12-4.py ではこの関数を用いて全てのプロセスの終了を待機している．
書き方：

as completed( イテラブル )245

「イテラブル」は Future オブジェクトを要素とするもので，各要素が示すプロセスが終了する度に，その Future の結果を含んだ形のものを順次返すイテレータを作成する．
先のプログラム test12-4.py の prc lst は，実行されるプロセスを示す Future オブジェクトを要素として持つリス
トであり，21 行目で as completed 関数によって，終了した Future オブジェクトを順次返すイテレータを作成している．またそのイテレータを for 文によって処理しており，結果的に全てのプロセスが終了したときに for 文が終了する．
マルチスレッドとマルチプロセスの実行時間の比較

4.4.4

ここでは，サンプルプログラム mproc01.py を使って，マルチスレッドとマルチプロセスの間の実行時間の差異を調べる方法を例示する．プログラム中には関数 calcf が定義されており，これは円軌道のシミュレーションを実行する（円を表現する差分方程式の数値解を求める）もの170 である．これを各種の異なる方法で実行する．
プログラム：mproc01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# coding : utf -8# 必要なモジュールの読込み
import time
import threadingfrom concurrent import futures# 対象の関数：円軌道の精密シミュレーション
def calcf ( name ):dt = 0.0000001
x = 1.0;
y = 0.0
t1 = time . time ()for i in range (62831853):
x -= y * dt ;y += x * dt
t = time . time () - t1
print ( name , ’ - time : ’ , t )##################################################################
マルチスレッドとマルチプロセスによる実行時間の比較実験##################################################################
if __name__ == ’ __main__ ’:
#
#
#
#
#
#
#
#
#
#
#

threadingモジュールによる実験
print ( ’ - - - By threading - - - ’)
p1 = threading . Thread ( target = calcf , args =( ’ p1 ’ ,))p2 = threading . Thread ( target = calcf , args =( ’ p2 ’ ,))p3 = threading . Thread ( target = calcf , args =( ’ p3 ’ ,))p1 . start ()p2 . start ()p3 . start ()p1 . join ()p2 . join ()p3 . join ()

#
#
#
#
#
#
#
#

concurrent . f u t u r e s モ ジ ュ ー ル に よ る マ ル チ プ ロ セ ス の 実 験print ( ’ - - - By concurrent . futures : [ ProcessPoolExecutor ] - - - ’)exe = futures . P rocessPoolExecutor ( max_workers =4)
f1 = exe . submit ( calcf , ’ p1 ’)
f2 = exe . submit ( calcf , ’ p2 ’)
f3 = exe . submit ( calcf , ’ p3 ’)
f4 = exe . submit ( calcf , ’ p4 ’)
exe . shutdown ()

#
#
#
#
#
#
#
#

concurrent . f u t u r e s モ ジ ュ ー ル に よ る マ ル チ ス レ ッ ド の 実 験print ( ’ - - - By concurrent . futures : [ ThreadPoolExecutor ] - - - ’)exe = futures . ThreadPoolExecu to r ( max_workers =4)
f1 = exe . submit ( calcf , ’ p1 ’)
f2 = exe . submit ( calcf , ’ p2 ’)
f3 = exe . submit ( calcf , ’ p3 ’)
f4 = exe . submit ( calcf , ’ p4 ’)
exe . shutdown ()170 詳しくは「6 外部プログラムとの連携」（p.339 〜）の章にある，円の微分方程式を差分化する方法を参照のこと．

246

52

pass

このプログラムの 23 行目以降のコメントを下記のように外して，3 つの実行形態を比較することができる．

1) threading モジュールによる実行→

23〜32 行目先頭の # を外す

2) concurrent.futures モジュールの ProcessPoolExecutor クラスによる実行 →35〜41 行目先頭の # を外す

3) concurrent.futures モジュールの ThreadPoolExecutor クラスによる実行 →44〜50 行目先頭の # を外す

実行した例を次に示す．
1) の実行例（マルチスレッド）--- By threading --p1 - time: 7.784013509750366
p3 - time: 7.783469200134277
p2 - time: 8.176703214645386
2) の実行例（マルチプロセス）--- By concurrent.futures : [ProcessPoolExecutor] --p1 - time: 3.423860549926758
p3 - time: 3.4440042972564697
p4 - time: 3.567429304122925
p2 - time: 3.648512601852417
3) の実行例（マルチスレッド）--- By concurrent.futures : [ThreadPoolExecutor] --p3 - time: 10.68565034866333
p1 - time: 10.819898128509521
p4 - time: 11.471580266952515
p2 - time: 11.6315176486969※ 実行環境： Python 3.11.2, Intel Corei7-1195G7 2.9GHz (4 コア), 32GB RAM, Windows11 Pro

1) と 3) の形態では，実行する関数 caclf の個数が増えると実行時間が伸び，2) の形態では，CPU やコアの数が多くなると実行時間が小さくなる．このことを，関数 caclf を実行する個数を変えて確認されたい．

247

非同期処理： asyncio

4.5

asyncio ライブラリは効率の良い並行処理を実現するものである．asyncio は多くの機能を提供するが，本書ではその内の高レベル API に関する基本的な事柄について解説する．

asyncio による並行処理の考え方は，先の「4.4 マルチスレッドプログラミング」（p.228）で解説したものとは異なり，コルーチン（async キーワードで宣言された関数）やタスク（Task オブジェクト）といった実行の単位（Awaitable
オブジェクト）を独特のイベントループで管理するものである．具体的には，複数の Awaitable オブジェクトをイベ
ントループに登録し，それらを順番に実行する．そして登録された全ての Awaitable オブジェクトが終了するまでイ
ベントループを実行する．各タスクの切り替えは await の式で制御する．
厳密には asyncio におけるタスクの実行は並行実行ではなく，async 宣言された Awaitable オブジェクトを，1 つのスレッド上で await 式によって実行し，それらの一時停止と切替えを管理するものである．特に，ディスクに対する入出力処理や通信といった待ち時間が多く発生する処理を管理する場合にこの実行形態が有利に働くことがある．

4.5.1

コルーチン

コルーチンとは asyncio の並行処理におけるプログラムの単位であり，async キーワードで宣言された関数として実装することができる．
（asyncio ライブラリを読み込んでいない状態でも async 宣言は可能である）
例．コルーチンの定義の例>>> async def msg(s): Enter←コルーチン定義の開始...
print(s)Enter...
return ’ 戻り値’
Enter
...
Enter
←コルーチン定義の終了
このようにして定義された msg は通常の関数とは異なり，呼び出すとコルーチンオブジェクトを返す．
（次の例参照）
例．コルーチンオブジェクトの生成（先の例の続き）>>> c = msg(’ コルーチン’)←コルーチンを呼び出すEnter>>> print( c )
Enter
←内容確認
<coroutine object msg at 0x000002423163F1D0>←コルーチンオブジェクト

この例の実行においては msg に定義されたプログラムは動作しておらず，得られたコルーチンオブジェクトをイベン
トループ上で実行するには次の例のように asyncio の run 関数を使用する．
例．コルーチンの実行（先の例の続き）>>> import asyncio>>> r = asyncio.run( c )コルーチン>>> print( r )戻り値←ライブラリの読込み

Enter

Enter

←イベントループを起動してコルーチンを実行←コルーチンからの出力←戻り値の確認←戻り値が得られているEnter

ただし，このような方法では通常の関数を実行する場合と結果的に変わらない．これに関しては次のサンプルプログ
ラム asyncio01.py の実行によって確認できる．
プログラム：asyncio01.py
1
2
3
4
5
6
7
8
9
10
11
12
13

# coding : utf -8
import asyncio
async def msg ( s ):for i in range (3):print ( s )return s# ライブラリの読込み# コ ル ー チ ン ： 引 数 に 与 え た 値 を3 回 出 力 す る# 受け取った引数を返す

r1 = asyncio . run ( msg ( ’ コ ル ー チ ン 1 ’ ) )r2 = asyncio . run ( msg ( ’ コ ル ー チ ン 2 ’ ) )r3 = asyncio . run ( msg ( ’ コ ル ー チ ン 3 ’ ) )# この順番でイベントループを# 起動してコルーチンを# 実行する

print ( ’ - - -\n ’ , r1 , r2 , r3 )248

このプログラムを実行すると次のような出力となる．
出力）
コルーチン 1
コルーチン 1
コルーチン 1
← 1 つ目のコルーチンが終了した後でコルーチン 2← 2 つ目のコルーチンが起動する
コルーチン 2
コルーチン 2← 2 つ目のコルーチンが終了した後で，コルーチン 3← 3 つ目のコルーチンが起動する
コルーチン 3コルーチン 3← 3 つ目のコルーチンが終了—
コルーチン 1 コルーチン 2 コルーチン 3←それぞれの戻り値を出力

この実行例からわかるように，3 つのコルーチンが順番に実行されており，並行処理とはなっていないことが確認できる．このような記述では run によって 3 つのイベントループが順番に起動，終了され，それぞれのイベントループ
内でコルーチンが実行されるので並行処理のような形にはならない．
コルーチンとタスクの違い

4.5.2

1 つのイベントループ上で複数の Awaitable オブジェクトの実行を管理するには，それらをタスクの形にしなければならない．すなわち，コルーチン自体にはイベントループ上での実行に関する管理の機能がなく，イベントループ
上でのスケジューリングの対象とするには，そのための機能を持ったタスクにする必要がある．タスクを作成するには create task 関数が使用できる．
書き方：

create task( コルーチン )「コルーチン」からタスクを作成して返す．

4.5.2.1

複数のタスクの並行実行

複数のタスクを 1 つのイベントループで並行実行するには，それら複数のタスクを await 式で起動するためのコルーチンを 1 つ実装して，それを run によって起動するとよい．
次に，await 式によるタスクの実行開始，一時停止，切り替えについて説明する．

await によるタスクの一時停止と切替え

4.5.3

asyncio の sleep 関数を使用すると，実行中の Awaitable オブジェクトの実行を一時停止して，実行制御をイベント
ループ上の実行可能な次の Awaitable オブジェクトに移すことができる．このことをサンプルプログラム asyncio02.pyの実行を通して解説する．
プログラム：asyncio02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# coding : utf -8
import asyncio# ライブラリの読込み

async def msg ( s ):# コ ル ー チ ン ： 引 数 に 与 え た 値 を3 回 出 力 す る
for i in range (3):print ( s )await asyncio . sleep (1) # ← こ の コ ル ー チ ン を 一 時 停 止 し て
return s#
次のタスクに制御を移す
async def exe ():# タスクを投入して実行するコルーチン
t1 = asyncio . create_task ( msg ( ’ コ ル ー チ ン 1 ’ ) ) # 3 つ の コ ル ー チ ン を
t2 = asyncio . create_task ( msg ( ’ コ ル ー チ ン 2 ’ ) ) # そ れ ぞ れ タ ス ク に
t3 = asyncio . create_task ( msg ( ’ コ ル ー チ ン 3 ’ ) ) # し て い る ．
# 順番に登録して実行
await t1 ;await t2 ;await t3
asyncio . run ( exe () )# イベントループの起動

解説）

4〜8 行目でコルーチン msg が定義されている．このコルーチンは受け取った引数を 3 回出力するものであるが，毎回の出力の直後に asyncio.sleep(1) を await 式によって実行している．これにより，当該コルーチンは実行が一時249

停止され，1 秒間に渡って休止状態となる．同時に，イベントループの上にある次の実行可能な Awaitable オブジェ
クトに実行の制御が移る．

10〜14 行目に定義されているコルーチン exe は msg を 3 つのタスクにして（11〜13 行目）イベントループに登録
して（14 行目）実行を開始するものである．この際，create task 関数によってコルーチン msg をタスクオブジェク
ト（asyncio.Task クラス）にしている．タスクオブジェクトは生成直後は実行されず，14 行目にある await 式によってイベントループに登録されて実行される．
このプログラムの実行結果の出力を次に示す．
出力）
コルーチン 1
コルーチン 2
コルーチン 3コルーチン 1
コルーチン 2
コルーチン 3コルーチン 1
コルーチン 2
コルーチン 3

←ここで 1 秒弱停止

←ここで 1 秒弱停止

←ここで 1 秒弱停止した後，プログラムが終了

この実行例からわかるように，3 つのタスクが同時に実行されているように見える．
注意）次の asyncio02-2.py のように実装すると並行実行のようにはならないことに注意すること．
プログラム：asyncio02-2.py（良くない実装）
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8
import asyncio# ライブラリの読込み

async def msg ( s ):# コ ル ー チ ン ： 引 数 に 与 え た 値 を3 回 出 力 す る
for i in range (3):print ( s )await asyncio . sleep (1) # ← こ の コ ル ー チ ン を 一 時 停 止 し て
return s#
次のタスクに制御を移す
async def exe ():# タスクを投入して実行するコルーチン
t1 = asyncio . create_task ( msg ( ’ コ ル ー チ ン 1 ’ ) ); await t1
t2 = asyncio . create_task ( msg ( ’ コ ル ー チ ン 2 ’ ) ); await t2
t3 = asyncio . create_task ( msg ( ’ コ ル ー チ ン 3 ’ ) ); await t3
asyncio . run ( exe () )# タスクの生成と# それらの実行を# この方法で試みる# イベントループの起動

このプログラムの実行結果の出力を次に示す．
出力）
コルーチン 1
コルーチン 1
コルーチン 1
コルーチン 2
コルーチン 2
コルーチン 2
コルーチン 3コルーチン 3コルーチン 3

←ここで約 1 秒停止←ここで約 1 秒停止←ここで約 1 秒停止して 1 つ目のコルーチンが終了←ここで約 1 秒停止←ここで約 1 秒停止←ここで約 1 秒停止して 2 つ目のコルーチンが終了←ここで約 1 秒停止←ここで約 1 秒停止←ここで約 1 秒停止した後，プログラムが終了

各タスクが並行実行のようにはならず，順番に実行されていることがわかる．複数の非同期処理を並行処理のように実行するには，exe の末尾にまとめて await 式で実行する必要がある．

4.5.4

タスク登録の簡便な方法

asyncio の gather 関数を使用すると，タスクの生成と登録を更に簡単な形で実現できる．
書き方：

gather( Awaitable オブジェクト 1, Awaitable オブジェクト 2, … )引数に与えた Awaitable オブジェクト（コルーチン，タスクなど）をその順序でタスクとしてイベントループに登録して実行する．

gather 関数を用いて先のプログラム asyncio02.py と同様の処理を実現するプログラム asyncio03.py を示す．
250

プログラム：asyncio03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# coding : utf -8
import asyncio# ライブラリの読込み

async def msg ( s ):# コ ル ー チ ン ： 引 数 に 与 え た 値 を3 回 出 力 す る
for i in range (3):print ( s )await asyncio . sleep (1) # ← こ の コ ル ー チ ン を 一 時 停 止 し て
return s#
次のタスクに制御を移す
async def exe ():# タスクを投入して実行するコルーチン
g = await asyncio . gather (# 実際にタスクを実行する
msg ( ’ コ ル ー チ ン 1 ’) ,msg ( ’ コ ル ー チ ン 2 ’) ,msg ( ’ コ ル ー チ ン 3 ’ ))print ( g )# 戻り値の確認
asyncio . run ( exe () )# イベントループの起動

gather 関数の戻り値がリストとして変数 g に得られ（11〜15 行目）各コルーチンからの戻り値が要素となる．
イベントループと run 関数

4.5.5

イベントループは 1 つのスレッド内に 1 つだけ実行できるものである．従って，一度 run 関数で非同期処理が開始された後は，そのイベントループが終了するまで次の run 関数は実行できない．先に示したサンプルプログラム

asyncio02.py〜asyncio03.py において，exe を最上位のコルーチンとして run 関数で実行し，exe の内部で複数のタスクを登録して実行するという形式をとっているのはそのような事情による．

4.5.5.1

スレッド毎に実行されるイベントループ

イベントループは通常，run 関数の実行によって自動的に作成されるが，asyncio の new event loop 関数によって明示的に作成（ProactorEventLoop オブジェクトを作成）することもできる．また，イベントループは異なるスレッド毎に作成することもできるので，スレッド毎に異なるイベントループを同時に実行することもできる．このことを次のサンプルプログラム asyncio04.py で示す．
プログラム：asyncio04.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8
import asyncio
import threading
async def msg ( s ):# コ ル ー チ ン ： 引 数 に 与 え た 値 を3 回 出 力 す る
for i in range (2):print ( s )await asyncio . sleep (1) # ← こ の コ ル ー チ ン を 一 時 停 止 し て
return s#
次のタスクに制御を移す
def startLoop ( eloop , rn ):# スレッド内でイベントループを開始する
eloop . r un_until_complete ( msg ( rn ) )eloopA = asyncio . new_event_loop ()eloopB = asyncio . new_event_loop ()# イ ベ ン ト ル ー プ(1)# イ ベ ン ト ル ー プ(2)# ス レ ッ ド を2 つ 生 成 し て 各 々 で イ ベ ン ト 管 理 す る
tA = threading . Thread ( target = startLoop , args =( eloopA , ’ コ ル ー チ ン ： ス レ ッ ド A ’) )tB = threading . Thread ( target = startLoop , args =( eloopB , ’ コ ル ー チ ン ： ス レ ッ ド B ’) )# スレッドの開始と終了待ち
tA . start ();tB . start ()tA . join ();tB . join ()このプログラムの 14,15 行目で new event loop 関数によって別々のイベントループを作成している．またそれらを

18,19 行目でスレッド tA，tB に与えている．スレッドとして起動する関数 startLoop はイベントループと文字列を受け取り，run until complete メソッドによってイベントループを起動する．
書き方：

イベントループ.run until complete( コルーチン )251

「コルーチン」に非同期処理の最上位のコルーチンを与える．このメソッドは非同期処理が終了した際にコルーチンの戻り値を返す．run until complete は，asyncio.run と同様の処理を，指定したイベントループに対して実行する際に用いる．
このプログラムをスクリプトとして実行した様子を次に示す．
例．asyncio04.py の実行
コルーチン：スレッド A
コルーチン：スレッド B
コルーチン：スレッド A
コルーチン：スレッド B

2 つのイベントループが平行して動作していることがわかる．
勿論であるが，各々のスレッド内で run 関数によってイベントループを自動的に作成することもできる．次のasyncio04-2.py は更に簡潔な記述で先のプログラムと同等の処理を行うものである．
プログラム：asyncio04-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# coding : utf -8
import asyncio
import threading
async def msg ( s ):# コ ル ー チ ン ： 引 数 に 与 え た 値 を3 回 出 力 す る
for i in range (2):print ( s )await asyncio . sleep (1) # ← こ の コ ル ー チ ン を 一 時 停 止 し て
return s#
次のタスクに制御を移す
def startLoop ( rn ): # ス レ ッ ド 内 で イ ベ ン ト ル ー プ を 生 成 し て 開 始 す る
asyncio . run ( msg ( rn ) )# ス レ ッ ド を2 つ 生 成 し て 各 々 で イ ベ ン ト 管 理 す る
tA = threading . Thread ( target = startLoop , args =( ’ コ ル ー チ ン ： ス レ ッ ド A ’ ,) )tB = threading . Thread ( target = startLoop , args =( ’ コ ル ー チ ン ： ス レ ッ ド B ’ ,) )# スレッドの開始と終了待ち
tA . start ();tB . start ()tA . join ();tB . join ()4.5.5.2

実行中のイベントループを調べる方法

get running loop 関数を用いると，現行のスレッドで実行中のイベントループを調べることができる．
書き方：

asyncio.get running loop( )この関数は，イベントループオブジェクト（ProactorEventLoop オブジェクト）を返す．実行中のイベントループが存在しない場合は例外（RuntimeError）が発生する．
参考）

get running loop 関数と類似のものとして get event loop も存在するが，これは将来の Python の版において廃止
されることが予定されている．

4.5.6

理解を深めるためのサンプル時間かかる処理を非同期処理（async，await）で管理する方法について考える．
例．時間のかかる処理>>> import random>>> while True:

Enter
Enter

...

r = random.random()...

if r < 2**(-26):

...
...

break
Enter

Enter

Enter

Enter

←乱数を生成し
それが 2−26 未満であれば終了するループ←反復処理の記述の終了

このプログラムは非常に小さな乱数（発生確率の非常に低い乱数）が得られるまで乱数生成を繰り返すもので，終了まで時間がかかる例である．
（実際に試されたい）このような処理を複数起動して並行実行するサンプルを次の asyncio07.py

252

に示す．
プログラム：asyncio07.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# coding : utf -8
import asyncio
import random
import time
# v未満の乱数が出るまで試行を続けるコルーチン
async def long_task ( n , v ):while True :# 非常に時間のかかる処理
r = random . random ()#｜#if r < v :
｜
break
#
↓
await asyncio . sleep (0) # イ ベ ン ト ル ー プ に 制 御 を 移 す た め に 必 要print ( n , r )# 上記処理を繰り返すコルーチン
async def asyncIteration ( n , v , i ):for x in range ( i ):await long_task ( n , v ) # 各 回 の 処 理 の 完 了 を 待 つ# イベントループに渡す最上位のコルーチン
async def exe ():await asyncio . gather (asyncIteration ( ’ task1 ’ ,2**( -21) ,2) , # 2 つ の 処 理 がasyncIteration ( ’ task2 ’ ,2**( -20) ,4) # 並 行 実 行 さ れ る 形)# 非同期処理の実行
print ( ’ 開 始 ’ )t1 = time . time ()asyncio . run ( exe () )t2 = time . time ()print ( ’ 終 了 : ’ , t2 - t1 , ’ 秒 ’ )このプログラムは先の例と同じ処理を並行実行するものである．関数 long task(n,v) は非同期処理のためのコルーチンとして定義されており，タスクの識別名 n と乱数の終了条件の値 v を引数に取る．このコルーチンでは，多数回反復される while の処理の中のawait asyncio.sleep(0)において実行の管理をイベントループに移している．待ち時間を 0 にしているが，これは実行待ちをさせるのが目的
ではなく，while による反復で毎回イベントループに制御を渡すのが目的である．すなわち，この行の記述がないと

while ループが終了するまで当該スレッドが他のタスクの実行をブロックしてしまう．
コルーチン asyncIteration は時間のかかる long task を指定した回数（引数 i）繰り返すものである．また，コルー
チン exe はイベントループで実行する 2 つのタスクを起動するものである．
このプログラムを実行した際の出力の例を次に示す．
開始
task2 2.723247869429457e-07
task2 6.862664404527763e-07
task2 9.22241627954179e-07
task1 3.4535740955909944e-07
task2 5.80478085154823e-07
task1 2.7896666210391885e-07
終了: 7.798398494720459 秒

2 つのタスクが互いにブロックせずに実行されている様子がわかる．
4.5.6.1

非同期処理とイベントループの概観

複数のタスクの実行がイベントループ上で管理される様子を図 35 に示す．

253

実行可能なタスクを検知するイベントループ

タスク 1

タスク 2

await で待機状態に入る

await で待機状態
に入る

Yes

Yes

実行可能？ No

実行可能？ NoNo 実行可能？

No 実行可能？

Yes

Yes
await で待機状態に入る

await で待機状態に入る

タスク 3

タスク 4
同時に実行できるタスクは 1 つだけであり，
イベントループに登録された順に実行される．

図 35: イベントループで監視されるタスクの概観

4.5.7

スレッドを非同期処理で管理する方法

イベントループに対する run in executor メソッドを使用すると，Awaitable でない通常の関数をメインのスレッドとは別のスレッドとして起動して非同期処理の枠組みで管理することができる．
書き方：

イベントループ.run in executor( 実行器, 関数, 引数並び… )「関数」に「引数並び…」を与えて実行するための asyncio.Future オブジェクトを返す．この関数を実行する際に使用される「実行器」（concurrent.futures.ThreadPoolExecutor など）を与える．
「実行器」として None を与えるとシス
テムが用意したものが採用される．
このメソッドで得られた Future オブジェクトをコルーチンにしたものをタスクに変換すると，イベントループ上の非同期処理として実行することができる．このことを次のサンプルプログラム asyncio05.py で解説する．
プログラム：asyncio05.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# coding : utf -8
import asyncio , timefrom concurrent import futures
def normalf ( s ):for i in range (3):print ( s )time . sleep (1)return s# 通常の関数# Futureオブジェクトを実行するコルーチンの作成
async def fut2cor ( f ):c = await f
return c# スレッド実行器
e = futures . T hr ea dP oo lE xe cu to r ( max_workers =2)
async def exe ():# タスクを投入して実行するコルーチン
eLoop = asyncio . get_running_loop () # イ ベ ン ト ル ー プ を 取 得# 通 常 の 関 数 の Futureオブジェクトを作成
f1 = eLoop . run_in_executor (e , normalf , ’ 通 常 の 関 数 1 ’ )f2 = eLoop . run_in_executor (e , normalf , ’ 通 常 の 関 数 2 ’ )# Futureオブジェクトをタスクに変換
t1 = asyncio . create_task ( fut2cor ( f1 ))t2 = asyncio . create_task ( fut2cor ( f2 ))# 両方のタスクを同時に実行
r = await asyncio . gather ( t1 , t2 )# 戻り値の確認
print ( r )

254

31
32
33
34

# 実行器の終了
e . shutdown ()asyncio . run ( exe ())# イベントループの起動

解説）
このプログラムの関数 normalf は，引数に与えられた値を出力して 1 秒間待つ処理を 3 回繰り返すもので，これをイベントループ上で実行する．

run in executor はイベントループに対して実行するものなので，システムが用意したイベントループを 20 行目で取得している．22,23 行目で関数 normalf を実行するための Future オブジェクト f1，f2 を作成している．そして，それを関数 fut2cor でコルーチンに変換し，create task 関数でタスク t1，t2 にしている．
（25,26 行目）
このプログラムの実行結果を次に示す．
例．asyncio05.py をスクリプトとして実行
通常の関数 1
通常の関数 2
通常の関数 1
通常の関数 2
通常の関数 1
通常の関数 2[’ 通常の関数 1’, ’ 通常の関数 2’]

スレッド上で実行される関数自体は非同期処理を意識せずに実装できるので，それを非同期処理の枠組みの上で管理したい場合にこの方法が有効である．
勿論のことではあるが，コルーチンをタスクにしたものと，スレッドをタスクにしたものを同時にイベントループ
上で実行することができる．そのことを次の asyncio06.py で示す．
プログラム：asyncio06.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# coding : utf -8
import asyncio , timefrom concurrent import futures
def normalf ( s ):for i in range (3):print ( s )time . sleep (1)return s# 通常の関数

async def coroutine ( s ):# コルーチンfor i in range (3):print ( s )await asyncio . sleep (1)return s# Futureオブジェクトを実行するコルーチンの作成
async def fut2cor ( f ):c = await f
return c# スレッド実行器
e = futures . T hr ea dP oo lE xe cu to r ( max_workers =1)
async def exe ():# タスクを投入して実行するコルーチン
eLoop = asyncio . get_running_loop () # イ ベ ン ト ル ー プ を 取 得# 通 常 の 関 数 の Futureオブジェクトを作成
f = eLoop . run_in_executor (e , normalf , ’ 通 常 の 関 数 ’ )# タスクを作成
t1 = asyncio . create_task ( fut2cor ( f ))# スレッドのタスク
t2 = asyncio . create_task ( coroutine ( ’ コ ル ー チ ン ’ ) )# コルーチンのタスク# 両方のタスクを同時に実行
r = await asyncio . gather ( t1 , t2 )# 戻り値の確認
print ( r )# 実行器の終了
e . shutdown ()

255

39

asyncio . run ( exe ())# イベントループの起動

このプログラムの実行結果を次に示す．
例．asyncio06.py をスクリプトとして実行
通常の関数
コルーチン
通常の関数
コルーチン
通常の関数
コルーチン
[’ 通常の関数’, ’ コルーチン’]normalf と coroutine がタスクとして同時に実行されている様子がわかる．
4.5.8

非同期のコンソール入力を実現するためのライブラリ：aioconsole

有志のエンジニア Vincent Michel 氏が開発して公開しているライブラリ aioconsole 171 を用いると，input 関数と同様のコンソール入力を非同期に実行することができる．このライブラリは Python 言語処理系の標準ライブラリではなく，pip コマンドなどでシステムに導入する必要がある．
非同期のコンソール入力には ainput 関数を用いる．
書き方：

ainput( プロンプト )「プロンプト」に与えた文字列をコンソールに表示して入力を促し，コンソールから入力された文字列を返す．

ainput 関数を使用したサンプル asyncio08.py を次に示す．
プログラム：asyncio08.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# coding : utf -8
import asyncio
import aioconsole# 非 同 期 の タ ス ク1
async def msg ( s ):for i in range (3):print ( s )await asyncio . sleep (4)return s# 非 同 期 の タ ス ク2
async def asyncInput ():while True :r = await aioconsole . ainput ( ’ e n d で 終 了 > ’)print ( ’ 入 力 値 : ’ , r )await asyncio . sleep (4)if r == ’end ’: break# タスク投入用コルーチン
async def exe ():g = await asyncio . gather (msg ( ’ 文 字 列 表 示 ’) ,asyncInput ())
asyncio . run ( exe () )# タ ス ク1
# タ ス ク2

# イベントループで実行

このサンプルでは 2 つのコルーチン msg と asyncInput が定義され，それらが非同期のタスクとして実行される．

msg は引数に与えられた文字列を 3 回出力する．
（毎回の出力の後で 4 秒待機する）asyncInput は非同期に実行され，他のタスクをブロックすることなくコンソールからの入力を受け付ける．このサンプルの実行例を次に示す．

171 https://github.com/vxgmichel/aioconsole

256例．asyncio08.py の実行
文字列表示← msg による出力

end で終了> abcd
入力値: abcd

Enter

文字列表示

←キーボードからの入力← msg による出力

end で終了> end
入力値: end

Enter

文字列表示

←キーボードからの入力← msg による出力

msg と asyncInput が互いに相手をブロックせずに動作している様子がわかる．
永続するイベントループ上でのタスク管理

4.5.9

ここまでの解説では，イベントループ上のタスクが終了した時点で当該イベントループも終了する形の実装を示してきた．この形とは別に，永続するイベントループに対して動的にタスクを投入するという形式のプログラミング172
も実際に多く行われている．ここでは，永続するイベントループとその上でのタスクの管理の方法について解説する．

4.5.9.1

永続するイベントループ

イベントループに対して run forever メソッドを実行するとそのイベントループの動作が永続的になる．
書き方：

イベントループ.run forever( )また，永続するイベントループを停止するには stop メソッドを使用する．
書き方：

イベントループ.stop( )動作を終了して停止したイベントループは close メソッドで閉じておくこと．
書き方：

イベントループ.close( )永続するイベントループに対して動的にタスクを投入する例を asyncio09.py で示す．
プログラム：asyncio09.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# coding : utf -8
import asyncio
import aioconsole#--- タ ス ク の 定 義 -----------------------------------------------------# 非 同 期 の タ ス ク ： メ ッ セ ー ジ を3 回 出 力
async def msg ( n , s ):for i in range (3):print ( ’\t ’* n + s )await asyncio . sleep (1)return s# 非同期のタスク：コンソール入力
async def asyncInput ():while True :r = await aioconsole . ainput ( ’ e n d で 終 了 > ’)if r == ’end ’:asyncio . get_running_loop (). stop ()# イベントループの終了
print ( ’ 終 了 し ま す ． ’ )breakelse :
print ( ’ 入 力 値 : ’ , r )# 最初に起動される非同期タスク
async def theFirst ():asyncio . create_task ( msg (0 , ’ タ ス ク 1 ’ ) )await asyncio . sleep ( 0.5 )asyncio . create_task ( msg (1 , ’ タ ス ク 2 ’ ) )await asyncio . sleep ( 3 )asyncio . create_task ( asyncInput () )# 動 的 に タ ス ク を 投 入(1)# 動 的 に タ ス ク を 投 入(2)# 動 的 に タ ス ク を 投 入(3)#--- イ ベ ン ト ル ー プ の 作 成 ， 最 初 の タ ス ク の 登 録 ， 永 続 実 行 ----------------

172 JavaScript 言語処理系（Web ブラウザのエンジンや Node.js など）におけるプログラミングもこのスタイルである．

257

33
34
35
36
37
38
39

eloop = asyncio . new_event_loop ()asyncio . set_event_loop ( eloop )# イベントループを作成して# それを現行のスレッドにアタッチする．

eloop . create_task ( theFirst () )eloop . run_forever ()# 最初のタスクをイベントループに登録して# そのイベントループを永続実行する．

eloop . close ()# 終了後はイベントループを閉じる．

このサンプルでは，メッセージの出力と 1 秒間の待機を 3 回繰り返すコルーチン msg と，コンソールからの非同期入力を受け付けるコルーチン asyncInput が定義されている．これらが，別のコルーチン theFirst から順次起動される形になっている．asyncInput の入力において ’end’ と入力されるとイベントループが stop メソッドにより停止され，プログラム全体が終了する．

asyncio09.py を実行した際のコンソールの表示を次に示す．
例．ターミナルウィンドウで asyncio09.py を実行した様子
タスク 1
タスク 2

← 2 つのタスク msg が互いに

タスク 1
タスク 2

ブロックせずに実行されている

タスク 1
タスク 2
end で終了> end

Enter←ここで 2 つのタスク msg が終了した←終了を指示終了します．

参考）
このサンプルでは，イベントループ eloop を作成した後で，asyncio.set event loop( eloop )として現行のスレッドにそれをアタッチしているが，当サンプルではこの行を省略することができる．

4.5.9.2

タスクの一覧取得とタスクのキャンセル

all tasks 関数を用いると，イベントループの上で実行されているタスクの一覧（Set オブジェクト）を取得すること
ができる．
書き方：

asyncio.all tasks( イベントループ )「イベントループ」（ProactorEventLoop オブジェクト）の上で実行されているタスク（Task オブジェクト）を要素とする Set オブジェクトを返す．
実行中のタスクを終了する（キャンセルする）には cancel メソッドを使用する．
書き方：

タスク.cancel()「タスク」（Task オブジェクト）を強制終了する．この際に警告が発生することがあるのでそれを適切にハンドリン
グすること．
次に示すサンプル asyncio010.py は，コンソールからの非同期の入力を受けて新規のタスクをイベントループに随時投入するものである．
プログラム：asyncio10.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8
import asyncio
import aioconsole#--- タ ス ク の 定 義 -----------------------------------------------------# 非同期のタスク：無制限の繰り返し
async def tsk ():while True : await asyncio . sleep (1)# 非同期のタスク：コンソール入力
async def asyncInput ():el = asyncio . get_running_loop ()while True :r = await aioconsole . ainput ( ’ e n d で 終 了 > ’)if r == ’end ’:

258

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

for t in asyncio . all_tasks ( el ):t . cancel ()# タスクを強制的にキャンセル
try :# その際の例外処理
await texcept asyncio . CancelledError :pass# 必要に応じてここで例外処理を実行する
asyncio . get_running_loop (). stop ()# イベントループの終了
print ( ’ 終 了 し ま す ． ’ )breakelif r == ’ show ’:
print ( ’ 実 行 中 > \ t ’ , end = ’ ’ )for t in asyncio . all_tasks ( el ):# 実行中タスクのprint ( t . get_name () , sep = ’ ’ , end = ’\t ’ ) # 一 覧 出 呂 っ く
print ()
elif r == ’new ’:asyncio . create_task ( tsk () )# 動的にタスクを投入
else :
print ( ’ 入 力 値 : ’ , r )# 最初に起動される非同期タスク
async def theFirst ():asyncio . create_task ( asyncInput () )#--- イ ベ ン ト ル ー プ の 作 成 ， 最 初 の タ ス ク の 登 録 ， 永 続 実 行 ---------------eloop = asyncio . new_event_loop ()# イベントループを作成してeloop . create_task ( theFirst () )eloop . run_forever ()# 最初のタスクをイベントループに登録して# そのイベントループを永続実行する．

eloop . close ()# 終了後はイベントループを閉じる．

このサンプルでは，コンソールから ’show’ と入力すると実行中のタスクの一覧（タスク名の一覧）を表示する．この際に all tasks メソッドが使用される．また，タスク名の取得には当該タスクに対して get name を実行する．
コンソールから ’new’ と入力するとコルーチン tsk をタスクとしてイベントループに追加し，’end’ と入力すると実行中のタスクを全て強制終了してプログラム全体を終了する．
実行中のタスクを cancel メソッドで強制的に終了するとしばしば警告（asyncio.CancelledError）が発生するので，これを適切にハンドリングすること．

asyncio10.py を実行した際のコンソールの表示を次に示す．
例．ターミナルウィンドウで asyncio10.py を実行した様子
end で終了> show

Enter

←状態確認
←この段階では asyncInput だけが実行されている実行中> Task-2

end で終了> newEnter←新規タスク投入

end で終了> show

Enter

←状態確認

実行中> Task-5 Task-2←タスクが 1 つ増えているend で終了> newEnter←新規タスク投入

end で終了> show

Enter

←状態確認

実行中> Task-5 Task-8 Task-2←タスクが 1 つ増えているend で終了> end←終了を指示Enter

終了します．

■ タスクの名前について
イベントループに投入されたタスクには自動的に名前が付与される．先の実行例で得られた

Task-5 Task-8 Task-2のような出力には各タスクに自動的に命名されたものが見られる．タスク投入時に意図して名前を与える場合は，キー
ワード引数 ’name=’ にそれを指定して，

asyncio.create task( コルーチン, name=タスク名 )のように記述する．

259

4.5.10

非同期のイテレーション

for 文による反復処理に async キーワードを付けることで非同期のイテレーションを実現することができる．
書き方：

async for 変数 in 非同期のイテラブル:（反復対象の処理）「非同期のイテラブル」（後述）から要素を順次「変数」に受け取って「反復対象の処理」を実行する．
「変数」に値を受け取る際に await による待機が起こる場合，イベントループに実行の制御が移される．

4.5.10.1

非同期のイテラブル

要素の取得（あるいは生成）に時間がかかる（await による待機が起こる）イテラブルは非同期のイテラブル173 として扱うことができる．非同期のイテラブルには様々なものがあり，ファイル入出力や通信における入力ストリーム
を非同期の形で扱うイテラブルが代表的な例である．また，次に説明する非同期のジェネレータ，非同期のイテレー
タもこの範疇に入る．
■ 非同期のジェネレータ
非同期のジェネレータは async キーワードで宣言されたジェネレータ174 である．非同期のジェネレータの例を次のサンプル asyncio11.py で示す．
プログラム：asyncio11.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8
import asyncio# コ ル ー チ ン1
async def msg ():for x in range (4):await asyncio . sleep (1)print ( ’ タ ス ク 1 ’ )# コ ル ー チ ン2 ： 非 同 期 の ジ ェ ネ レ ー タ
async def aGen ():for x in [ ’a ’ , ’b ’]:
await asyncio . sleep (2)yield x# タスクを投入するコルーチン
async def exe ():asyncio . create_task ( msg () )# タスク１
async for x in aGen ():# 非同期の反復処理
print ( ’\ t 非 同 期 に 値 を 取 得 : ’ , x )asyncio . run ( exe () )# イベントループで実行

このサンプルでは非同期のジェネレータ aGen がコルーチンの形で定義されている．このジェネレータは 2 つの要
素 ’a’，’b’ を順次返すものであり，値を返す前に 2 秒の待ち時間がある．また，これとは別にコルーチン msg が定義されており，１秒の待ち時間の後でメッセージを出力することを 4 回繰り返す．

aGen は非同期のイテレーション（async for 文）で使用され，要素取得までの待ち時間の間も他のタスク msg をブロックしない．
このサンプルを実行した際の出力の例を次に示す．
例．ターミナルウィンドウで asyncio11.py を実行した様子
タスク 1
非同期に値を取得:

a

非同期に値を取得:

b

タスク 1
タスク 1
タスク 1

← msg による出力← async for 文内の print による出力← msg による出力← msg による出力← async for 文内の print による出力← msg による出力

173 非同期のコンテナと呼ぶこともある．
174 後の「4.7 ジェネレータ」（p.270）で詳しく解説する．

260

msg のタスクと非同期のイテレーションの処理が互いにブロックされずに実行されている様子がわかる．
■ 非同期のイテレータ
非同期のイテレータとは，要素を返す処理を非同期に行うイテレータである．基本的な実装方法は先の「2.8.6 イ
テレータのクラスを実装する方法」（p.148）に似ており，2 つのメソッド

anext

aiter

， anextの実装による．特にメソッドは値を返す処理を非同期に実行するので async キーワードを付けて宣言する．

非同期のイテレータの例を次のサンプル asyncio12.py で示す．これは先の asyncio11.py と同等の処理を実行する（先の実行例と同様の出力を得る）ものである．
プログラム：asyncio12.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# coding : utf -8
import asyncio# コ ル ー チ ン1
async def msg ():for x in range (4):await asyncio . sleep (1)print ( ’ タ ス ク 1 ’ )# 非同期のイテレータのクラス
class AsyncIter :def __init__ ( self ):# コンストラクタ
self . Q = [ ’a ’ , ’b ’]
self . cur = 0
def __aiter__ ( self ):return self
async def __anext__ ( self ):# 次の要素を返すメソッド（非同期処理）
if self . cur > 1:
# イテレーションが終了している場合にraise StopAsyncIteration# この例外を起こす
else :
await asyncio . sleep (2)r = self . Q [ self . cur ]self . cur += 1
return r# タスクを投入するコルーチン
async def exe ():asyncio . create_task ( msg () )# タスク１A = AsyncIter ()# 非同期のイテレータの作成
async for x in A :# 非同期の反復処理
print ( ’\ t 非 同 期 に 値 を 取 得 : ’ , x )asyncio . run ( exe () )# イベントループで実行

このサンプルでは非同期のイテレータのクラス AsyncIter が定義されている．コルーチン exe の中でこのクラスのインスタンス A が作成されて非同期のイテレーションに使用されている．

4.5.11

非同期のファイル入出力：aioﬁles

aioﬁles ライブラリは，asyncio ライブラリと連携して非同期のファイル操作を行う機能を提供する．Python 処理系の通常のファイル操作は同期処理であり，処理が完了するまで当該スレッドをブロックする．aioﬁles はこれを回避するために，ファイル操作を別のスレッドプールに委譲する形で非同期のファイル操作を行う．

aioﬁles ライブラリは Python の標準ライブラリではなく，サードパーティ175 が提供するものであり，これを使用するには pip コマンドなどで Python 言語処理系の環境に予め導入しておく必要がある．

aioﬁles ライブラリが提供する API は，Python の標準的なファイル操作用の API の場合と同様の記述ができるよ
うに配慮されている．また，標準ライブラリである os モジュールが提供するファイル操作関連の API と同じ名称の

API が多数提供されており，os モジュールの場合と同様の記述方法で使用できる点も大きな特徴である．

175 Tin Tvrtkovic 氏によって開発された．
（https://pypi.org/project/aioﬁles/）261

aioﬁles によるファイル入出力は「2.6 入出力」
（p.89）で解説した API と類似の用法で実現できる．すなわち，open
関数でファイルを開いてファイルオブジェクトを作成し，それに対して read，write メソッドを実行して入力，出力を行い，最後に close メソッドを実行してファイルを閉じる．
（それらの関数やメソッドを await 式として実行する）
本書では使用例を挙げて aioﬁles の最も基本的な API について解説する．提供されている各 API とその詳細に関しては aioﬁles の公式インターネットサイトなどを参照のこと．

4.5.11.1

サンプルプログラム

次に示す aioﬁles01.py では，2 つのタスク aFileIOr2()，msg() がイベントループ上で互いにブロックすることなく実行される．aFileIOr2() のタスクは，サイズの大きなファイルを作成して直後にそれを読み込むことを 2 回繰り返すというもので，入出力に伴う待ち時間が発生するものである．また msg() のタスクは一定の時間間隔でメッセージを繰り返しコンソールに出力するもので，1 つ目のタスクが実行を終えた後で終了する．
プログラム：aioﬁles01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# coding : utf -8
import asyncio
import aiofiles
flg = True

# 共 有 変 数 ： aFileIOr2 が 実 行 中 は T r u e ， 終 わ れ ば F a l s e# フ ァ イ ル 出 力 と 読 込 み を2 回 繰 り 返 す 処 理
async def aFileIOr2 ():global flg
for _ in range (2):print ( ’ フ ァ イ ル の 作 成 ’ )# ファイルの作成と出力
f = await aiofiles . open ( ’ aiofiles01 . bin ’ , ’w ’)
for n in range (50000):# 50 ,000 回 出 力 （ 反 復 回 数 は 適 宜 調 整 す る ）c = chr ( n %26 + 97 )# a〜zの文字を作成
await f . write ( c )# 1文 字 ず つ 出 力
if c == ’z ’: await f . write ( ’\n ’)await f . close ()print ( ’ フ ァ イ ル の 読 込 み ’ )# 上で作成したファイルの読込み
f = await aiofiles . open ( ’ aiofiles01 . bin ’ , ’r ’)
while True :c = await f . read (1)if not c : breakawait f . close ()flg = False# 定期的にメッセージを出力する処理
async def msg ():global flg# aFileIOr2 () が 終 了 す る ま で 繰 り 返 すwhile flg :await asyncio . sleep (2.5)# 待ち時間は適宜調整する
print ( ’\ t \ t 別 の タ ス ク ’)# タスク投入用コルーチン
async def exe ():t1 = asyncio . create_task ( aFileIOr2 () )t2 = asyncio . create_task ( msg () )await t1 ;await t2asyncio . run ( exe () )# 実行

このプログラムの実行例を次に示す．

262

例．aioﬁles01.py を OS のターミナルウィンドウで実行した際の出力
ファイルの作成
別のタスク
ファイルの読込み
別のタスク
ファイルの作成
別のタスク
ファイルの読込み
別のタスク
別のタスク

このように，2 つのタスク aFileIOr2()，msg() がイベントループ上で互いにブロックすることなく実行されているのがわかる．
このプログラムの実行によって作成されるファイル aioﬁles01.bin は次のような内容となる．
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz：（以下同様）：

上記プログラム中ではファイルを開く処理に open 関数を使っており，引数の仕様も標準の open 関数に準じている．ただし，aioﬁles の open 関数が返すファイルオブジェクトのクラスは表 34 に示すように，標準の open 関数が返すものとは異なる．
表 34: open 関数が返すファイルオブジェクトのクラス（一部）
テキスト

バイナリ

入力用

AsyncTextIOWrapper

AsyncBuﬀeredReader

出力用

（同上）

AsyncBuﬀeredIOBase

ここで示したサンプル aioﬁles01.py は，ファイルの入出力の待ち時間を強調するために，敢えて 1 バイトずつ入出力を行ったが，実用的な局面では長いデータを適宜まとめて（あるいは全ての内容を一度に）入出力することになる．
ファイル入出力を頻繁に実行しながら他の処理を並行して実行することが求められるアプリケーションを作成する
場合に，この aioﬁles が役立つ．
■ 非同期処理の通信への応用

asyncio による非同期処理の通信への応用に関しては，後の「5 TCP/IP による通信」（p.326）の中の「5.1.6 実用的な通信機能を実現する方法」（p.329）で解説する．
参考）サードパーティが開発して公開している uvloop ライブラリを用いると高速なイベントループが実現できる．これは，JavaScript 処理系の V8 エンジンで採用されているイベントループ機能（libuv）を Python 向けに応用したもの
である．

263

処理のスケジューリング

4.6

指定した時間が経過した後に関数を呼び出す，あるいは指定した時刻に関数を呼び出す方法について説明する．

sched モジュール

4.6.1

Python 処理系に標準的に提供されている sched モジュールを利用すると，指定した時間が経過した後にスケジュー
ル登録しておいた関数を呼び出す（実行する）ことができる．このモジュールによるスケジューリングは，関数呼び出しのスケジュールをスケジューラ（scheduler）オブジェクトに対して登録し，それを実行するという手順となる．
このモジュールは使用に先立って

import schedとして処理系に読み込んでおく必要がある．

4.6.1.1

基本的な使用方法

スケジューラオブジェクトを作成するには下記のように scheduler コンストラクタを使用する．

s = sched.scheduler()
この例では，変数 s にスケジューラオブジェクトが得られている．
イベント（実行したい関数）は，スケジューラオブジェクトに対して enter メソッドを使用して登録する．
書き方：

enter( 経過時間, 優先順位, 関数名, argument=関数に渡す引数のタプル )「経過時間」の単位は秒（浮動小数点数）である．
「優先順位」は登録するイベントの優先順位であり，値の小さい方が優先度が高い．enter メソッドは実行後，イベント（Event）オブジェクト を返す．イベントオブジェクトは登録された個々のスケジュールを意味する．イベントの登録ができたら，その直後にスケジューラオブジェクトに対して run
メソッドを実行する．これによってスケジュールの終了待ちの状態となる．
注）イベント実行までの経過時間は，enter メソッドでイベントを登録した時点が基準となる．
スケジューラオブジェクトには複数のイベントを登録することができる．
次に示すサンプルプログラム sched01.py は 3 つのイベントをスケジューリングする例である．
プログラム：sched01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# coding : utf -8
import sched
import time
# イベントとして実行する関数
def job ( m ):print ( m )# メッセージを表示するだけの関数# イベントのスケジューリング
s = sched . scheduler ()# スケジューラの作成
e1 = s . enter (3 ,1 , job , argument =( ’ 実 行 1 ’ ,))# イ ベ ン ト （3 秒 後 ） を 登 録
e2 = s . enter (4 ,1 , job , argument =( ’ 実 行 2 ’ ,))# イ ベ ン ト （4 秒 後 ） を 登 録
e3 = s . enter (5 ,1 , job , argument =( ’ 実 行 3 ’ ,))# イ ベ ン ト （5 秒 後 ） を 登 録
t1 = time . time ()# イベント登録完了時刻
print ( ’ イ ベ ン ト を 登 録 し ま し た ． ’ )s . run ()# 開始（イベント終了を待つ）
t2 = time . time ()# 全イベントが終了した時刻
print ( t2 - t1 , ’ 秒 後 に 全 て の イ ベ ン ト が 終 了 し ま し た ． ’ )プログラムの 6,7 行目に定義している関数は与えられたものをそのまま表示するもので，これをスケジューリング対象のイベントとしている．11〜13 行目で関数 job を 3 秒後，4 秒後，5 秒後にそれぞれ実行するものとしてスケジューリング（登録）している．
このプログラムを実行すると次のような出力が得られる．

264

実行例．（スクリプトとして実行）
イベントを登録しました．
実行 1
実行 2
実行 3
5.015453100204468 秒後に全てのイベントが終了しました．

関数 job による出力が，設定された時間の後に表示されることを確認されたい．

4.6.1.2

イベントを独立したスレッドで実行する方法

スケジューラオブジェクトに登録された個々のイベントは全て同じスレッド（Thread）で実行される．従って，1つのイベントが実行中である場合は，それが終了するまで次のイベントは実行されない．このことを次のサンプルプ
ログラム sched02.py で示す．
プログラム：sched02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# coding : utf -8
import sched
import time
# イベントとして実行する関数
def job ( m ):for i in range (3): # 3 秒 間 に 渡 っ て メ ッ セ ー ジ を 3 回 出 力 す る
print ( m )time . sleep (1)# イベントのスケジューリング
s = sched . scheduler ()# スケジューラの作成
e1 = s . enter (4.00 ,1 , job , argument =( ’ イ ベ ン ト 1 ’ ,))e2 = s . enter (4.33 ,1 , job , argument =( ’ イ ベ ン ト 2 ’ ,))e3 = s . enter (4.66 ,1 , job , argument =( ’ イ ベ ン ト 3 ’ ,))t1 = time . time ()# イベント登録完了時刻
print ( ’ イ ベ ン ト を 登 録 し ま し た ． ’ )s . run ()# 開始（イベント終了を待つ）
t2 = time . time ()# 全イベントが終了した時刻
print ( t2 - t1 , ’ 秒 後 に 全 て の イ ベ ン ト が 終 了 し ま し た ． ’ )このプログラムで定義されている関数 job は，3 秒間に渡ってメッセージを 3 回出力するものであり，一回の実行に
約 3 秒かかる．従って，13〜15 行目で登録された 3 つのイベントは全て 4 秒を過ぎた後に並行して実行されるのではなく，1 つずつ順番に実行される．このことは次の実行例で確認できる．
実行例．（スクリプトとして実行）
イベントを登録しました．
イベント 1
イベント 1
イベント 1
イベント 2
イベント 2
イベント 2
イベント 3イベント 3イベント 313.054096221923828 秒後に全てのイベントが終了しました．

1 つのイベントの実行が終了した後，次のイベントが実行されていることがわかる．
個々のイベントをそれぞれ独立した時間軸で実行する（それぞれが同時に実行されているように扱う）には，各イベントで実行する関数を別々のスレッド176 にすると良い．このことに関してサンプルプログラム sched03.py で例示する．
プログラム：sched03.py
1
2
3# coding : utf -8
import sched
import time

176 「4.4.1 マルチスレッド」（p.228）参照のこと．

265

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

import threading# メッセージを出力する関数
def job ( m ):for i in range (3): # 3 秒 間 に 渡 っ て メ ッ セ ー ジ を 3 回 出 力 す る
print ( m )time . sleep (1)# イベントとして実行する関数（上記の関数を独立したスレッドで実行する）
def job_th ( m ):th = threading . Thread ( target = job , args =( m ,))th . start ()# イベントのスケジューリング
s = sched . scheduler ()# スケジューラの作成
e1 = s . enter (4.00 ,1 , job_th , argument =( ’ イ ベ ン ト 1 ’ ,))e2 = s . enter (4.33 ,1 , job_th , argument =( ’ イ ベ ン ト 2 ’ ,))e3 = s . enter (4.66 ,1 , job_th , argument =( ’ イ ベ ン ト 3 ’ ,))t1 = time . time ()# イベント登録完了時刻
print ( ’ イ ベ ン ト を 登 録 し ま し た ． ’ )s . run ()t2 = time . time ()# runメソッドが終了した時刻
print ( t2 - t1 , ’’’ 秒 後 に r u n メ ソ ッ ド が 終 了 し ま し た ．
プ ロ グ ラ ム を 終 了 す る に は Enter を 押 し て く だ さ い ． ’ ’ ’ )input ()
# 入 力 待 ち （ Enterでプログラムが終了）

このプログラムで定義している関数 job は先の sched02.py と同じものであるが，その関数を独立したスレッドで実行するための別の関数 job th が定義されており，これをイベントとしてスケジューリングしている．これにより，全てのイベントは 4 秒を過ぎた後に並行して実行されるように見える．このことが次の実行例で確認できる．
実行例．（スクリプトとして実行）
イベントを登録しました．
イベント 1
イベント 2
イベント 34.662025690078735 秒後に run メソッドが終了しました．
プログラムを終了するには Enter を押してください．
イベント 1
イベント 2
イベント 3イベント 1
イベント 2
イベント 3←ここで Enter を押すことでプログラムが終了する．

各スレッドにおける関数 job が独立したスレッドとして同時に実行されている様子がわかる．また，最後に登録したイ
ベント e3 を実行し終えた（スレッド起動が完了した）時点で run メソッド（24 行目）が完了していることもわかる．
■ 工夫
更に，run メソッドを実行する処理を独立したスレッドにすると，run メソッドの終了まで待たされることがなくなる．これをサンプルプログラム sched04.py で例示する．
プログラム：sched04.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8
import sched
import time
import threading# メッセージを出力する関数
def job ( m ):for i in range (3): # 3 秒 間 に 渡 っ て メ ッ セ ー ジ を 3 回 出 力 す る
print ( m )time . sleep (1)# イベントとして実行する関数（上記の関数を独立したスレッドで実行する）
def job_th ( m ):th = threading . Thread ( target = job , args =( m ,))th . start ()

266

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# runメソッドを実行する関数
def mgr ( s ):s . run ()# イベントのスケジューリング
s = sched . scheduler ()# スケジューラの作成
e1 = s . enter (4.00 ,1 , job_th , argument =( ’ イ ベ ン ト 1 ’ ,))e2 = s . enter (4.33 ,1 , job_th , argument =( ’ イ ベ ン ト 2 ’ ,))e3 = s . enter (4.66 ,1 , job_th , argument =( ’ イ ベ ン ト 3 ’ ,))t1 = time . time ()# イベント登録完了時刻
print ( ’ イ ベ ン ト を 登 録 し ま し た ． ’ )sth = threading . Thread ( target = mgr , args =( s ,))sth . start ()# 関数 mgrを独立スレッドにして# それを起動する

t2 = time . time ()# runメソッドが終了した時刻
print ( t2 - t1 , ’’’ 秒 後 に r u n メ ソ ッ ド が 終 了 し ま し た ．
プ ロ グ ラ ム を 終 了 す る に は Enter を 押 し て く だ さ い ． ’ ’ ’ )input ()
# 入 力 待 ち （ Enterでプログラムが終了）

このプログラムは先の sched03.py と似ているが，run メソッドの実行を関数 mgr として定義し，それを独立したス
レッドとして実行（29,30 行目）している．これにより，全てのイベント登録と run メソッドの実行が速やかに終了
し，プログラムの実行位置が 32 行目に移る．このことが次の実行例で確認できる．
実行例．（スクリプトとして実行）
イベントを登録しました．
0.0 秒後に run メソッドが終了しました．
プログラムを終了するには Enter を押してください．
イベント 1
イベント 2
イベント 3イベント 1
イベント 2
イベント 3イベント 1
イベント 2
イベント 3←ここで Enter を押すことでプログラムが終了する．

イベントの実行が終了するのを待たずにプログラムが最終行に至っていることがわかる．

4.6.1.3

イベントの管理イベント管理に関する機能を表 35 に示す．
表 35: イベント管理のための機能（スケジューラオブジェクト S に対するメソッド/プロパティ）

4.6.2

記述

解説

S.cancel( e )S に登録されているイベント e をキャンセルする．

S.empty( )S に登録されているイベントがなければ True を，存在すれば False を返す．

S.queue

S に登録されているイベントのリスト．

schedule モジュール

Python システムに標準添付されているモジュール以外にも，処理のスケジューリングのためのオープンソースのモ
ジュール schedule 177 が公開されている．ここでは schedule モジュールの最も基本的な使用方法について解説する．
次のような関数 job の実行のスケジューリングを例に挙げて説明する．

177 このモジュールは「pipinstall schedule」でインストールできる．詳しくは公式インターネットサイト
https://pypi.org/project/schedule/ を参照のこと．

267

例．日付と時刻を付けてメッセージを出力する関数 job>>> from datetime import datetime← datetime モジュールの読み込みEnter>>> def job(m): Enter←日付・時刻付きでメッセージを表示する関数...
print( str(datetime.now())+’￥t:’+str(m) )
Enter
...
Enter
←関数定義の記述の終了>>> job(’ メッセージ’)Enter
2020-10-14 14:16:28.811510
4.6.2.1←実行:メッセージ←実行結果の出力

一定の時間間隔で処理を起動する方法

先に定義した関数 job を 1 分間隔で実行するには次のようにスケジューリングする．
例．1 分間隔で実行を繰り返すスケジューリング（先の例の続き）>>> import scheduleEnter← schedule モジュールの読み込み>>> e1 = schedule.every(1).minutes.do( job, ’1 分間隔のジョブ’ )Enter←ジョブの登録

この結果，関数 job を 1 分毎に実行するスケジューリングができる．every(1).minutes は「1 分毎」を意味する記述であり，それに続く do(...) で実行する関数をスケジュールする．
書き方：

do( 関数名, 関数に与える引数の並び… )先の例の実行によってジョブ（job）オブジェクト（スケジュールされる処理の単位）e1 が得られている．同様に，20秒間隔でジョブをスケジュールするには次のようにする．
例．20 秒間隔で実行を繰り返すスケジューリング（先の例の続き）>>> e2 = schedule.every(20).seconds.do( job, ’20 秒間隔のジョブ’ )Enter

以上で 1 分毎，20 秒毎のスケジューリングができたことになる．このスケジュールを実行するには次のような繰り返
し処理を実行する．
例．スケジュールを実行するループ（先の例の続き）>>> import timeEnter

← time モジュールの読み込み>>> while True: Enter←ループ記述の開始...
schedule.run pending()Enter←スケジュールを実行する処理...
time.sleep(1)Enter← 1 秒待って次の回に進む
...
Enter
←ループ記述の終了
2020-10-14 15:00:51.309569
2020-10-14 15:01:11.494809
2020-10-14 15:01:31.661763
2020-10-14 15:01:31.661763
2020-10-14 15:01:51.819587
2020-10-14 15:02:11.991623
2020-10-14 15:02:32.180156
2020-10-14 15:02:32.180156:20 秒間隔のジョブ:20 秒間隔のジョブ:1 分間隔のジョブ:20 秒間隔のジョブ:20 秒間隔のジョブ:20 秒間隔のジョブ:1 分間隔のジョブ:20 秒間隔のジョブ←以降，スケジュール実行の過程↓：

これは，1 秒毎にスケジュールを監視して実行するループである．この例にある run pending メソッドがスケジュー
ルを監視して実際にジョブを起動する．このように Python の対話モードでループを実行した場合，スケジュール実
行の繰り返しを停止するには Ctrl + C とキー入力（次の例）する．
例． Ctrl + C による停止時の表示（先の例の続き）

Traceback (most recent call last):
File "<stdin>", line 3, in <module>
KeyboardInterrupt←処理中断のメッセージ

do メソッドで登録したジョブはキャンセルされるまで有効であり，再度スケジュールのループを実行した際，起動の対象となる．ジョブのキャンセルには cancel job メソッドを用いる．

268

例．ジョブのキャンセル（先の例の続き）>>> schedule.cancel job(e1)Enter←ジョブ e1 のキャンセル>>> schedule.cancel job(e2)Enter←ジョブ e2 のキャンセル■ 参考
ジョブとしてスケジューリングする関数は，sched モジュールに関する解説の「4.6.1.2 イベントを独立したスレッドで実行する方法」（p.265）で説明したように，必要に応じて独立したスレッドにしておくと良い．

4.6.2.2

指定した時刻に処理を起動する方法

毎日，指定した時刻にジョブを起動する例を示す．
例．毎日 15:34:00 にジョブを起動する例（先の例の続き）>>> e1 = schedule.every().day.at(’15:34:00’).do( job, ’ 毎日 15:34:00 のジョブ’ )>>> while True: Enter←ループ記述の開始...
schedule.run pending()
Enter
...
time.sleep(1)
Enter
...
Enter
←ループ記述の終了
2020-10-14 15:34:00.782234:毎日 15:34:00 のジョブ

Enter

←ジョブからの出力

この例のように every().day.at(時刻) という形でジョブ起動の時刻を設定する．
（この後 Ctrl + C でループを停止して schedule.cancel job(e1) でジョブをキャンセルしたものとする）
留意事項：
上記の例を実行する際は実行環境の時刻を考え，ジョブ起動の時刻を適宜調整されたい．
例．毎分の 00 秒，20 秒，40 秒にジョブを起動する例（先の例の続き）>>> e1 = schedule.every().minute.at(’:00’).do( job, ’ 毎分 00 秒のジョブ’ )Enter>>> e2 = schedule.every().minute.at(’:20’).do( job, ’ 毎分 20 秒のジョブ’ )Enter>>> e3 = schedule.every().minute.at(’:40’).do( job, ’ 毎分 40 秒のジョブ’ )Enter>>> while True: Enter←ループ記述の開始...
schedule.run pending()
Enter
...
time.sleep(1)
Enter
...
Enter
←ループ記述の終了
2020-10-14 16:09:20.925096
2020-10-14 16:09:40.104823
2020-10-14 16:10:00.223926
2020-10-14 16:10:20.442045:毎分 20 秒のジョブ:毎分 40 秒のジョブ:毎分 00 秒のジョブ:毎分 20 秒のジョブ←ジョブからの出力←ジョブからの出力←ジョブからの出力←ジョブからの出力（この後 Ctrl + C でループを停止して

schedule.cancel job(e1); schedule.cancel job(e2); schedule.cancel job(e3)
でジョブをキャンセルしたものとする）
留意事項：
上記の例を実行する際は実行環境の時刻の秒が 40〜00 の間にあるタイミングで実行されたい．
例．毎時の 18 分，19 分にジョブを起動する例（先の例の続き）>>> e1 = schedule.every().hour.at(’:18’).do( job, ’ 毎時 18 分のジョブ’ )Enter>>> e2 = schedule.every().hour.at(’:19’).do( job, ’ 毎時 19 分のジョブ’ )Enter>>> while True: Enter←ループ記述の開始...
schedule.run pending()
Enter
...
time.sleep(1)
Enter
...
Enter
←ループ記述の終了
2020-10-14 16:18:00.353603
2020-10-14 16:19:00.795833:毎時 18 分のジョブ:毎時 19 分のジョブ

269←ジョブからの出力←ジョブからの出力（この後 Ctrl + C でループを停止して

schedule.cancel job(e1); schedule.cancel job(e2)
でジョブをキャンセルしたものとする）
留意事項：
上記の例を実行する際は実行環境の時刻を考え，ジョブ起動の分を適宜調整されたい．

4.7

ジェネレータ4.7.1

ジェネレータ関数

range 関数が生成する range オブジェクトのように，繰り返しの制御に与えるデータ列は必要に応じて生成されることが望ましい．特にサイズの大きなデータ列に対して繰り返しの制御を行う際には，システムの記憶資源の制限や処理の実行速度の面からデータ列は順次生成されることが望ましい．繰り返し制御のためにデータを順次生成するものとしてジェネレータ関数がある．
例として次のようなジェネレータ関数について考える．
例．整数を際限なく生成するジェネレータ関数 nbr←ジェネレータ関数 nbr の定義の開始>>> def nbr():

Enter

...

n = 0

Enter

...

while True:

Enter

...

yield n

Enter

...

n += 1

Enter

...
>>>

Enter

←ジェネレータ関数 nbr の定義の終了←対話モードのプロンプトに戻った

これはジェネレータ関数の 1 つの例であるが，無限に整数列を生成する形になっていることがわかる．通常の関数定
義の場合は，これはいわゆる無限ループであり，特に忌避されるものである．ただし，定義の中に yield という文があることが重要である．

yield 文は，その関数が生成するデータを意味するものであり，この関数は for などの制御構文から呼び出される毎に，yield 文のところで呼び出し元のプログラムと同期すると解釈することができる．
イテレータに対してするように next 関数を用いてこの関数 nbr を呼び出す例を次に示す．
例．next 関数で値を順に取り出す（先の例の続き）>>> q = nbr()Enter←関数 nbr をジェネレータとして q に与える

>>> q
Enter
←内容確認
<generator object nbr at 0x000001600A41C5C8>←ジェネレータとなっていることがわかる>>> next( q )Enter0←取り出し結果← next 関数による値の取り出し>>> next( q )Enter
1←取り出し結果←更に次の値の取り出し>>> next( q )Enter
2←取り出し結果←更に次の値の取り出し

この例から，無限ループによる制御不能の状態に陥ることなく，関数 nbr から値を際限なく取り出せることがわかる．

yield 文は return 文のように値を返すものであるが，呼び出し元と同期した形で次々と列の要素として値を生成するものと解釈する．
戻り値の指定に yield 文を用いた関数はジェネレータ関数となる．ジェネレータ関数において return 文は使用できない．
（無視される）270

4.7.2

ジェネレータ式「2.5.1.7 for を使ったデータ構造の生成（要素の内包表記）」（p.78）のところでデータ列の内包表記について説明したが，タプルに対する内包表記はジェネレータ式となる．
（次の例参照）
例．ジェネレータ式>>> g = ( 2*x for x in range(4) )←ジェネレータ式を生成

Enter

>>> g
Enter
←内容確認
<generator object <genexpr> at 0x000001600A34E7D8>←ジェネレータとなっていることがわかる>>> for m in g: Enter←個々に値を取り出してみる...
print( m )
Enter
...
Enter
←繰り返しの終了←結果表示（ここから）

0
2
4
6

←結果表示（ここまで）

これは，リスト [0,1,2,3] の各要素を 2 倍して表示したと見ることができるが，g に生成されたジェネレータ式は参照された時点で値を生成する．長大なリストを繰り返し制御に与えるよりも，ジェネレータ式の応用により記憶資源と実行速度の面で効率を高めることができる場合がある．

4.7.3

ジェネレータの入れ子

ジェネレータとして値を返す yield の後に「from イテラブル」を記述することで，与えたイテラブルの要素を順に返すことができる．
例．yield from の記述例>>> def g1(): Enter←ジェネレータ関数 g1 の定義の開始...
yield from [’d’,’e’,’f’]Enter←リストの要素を順に返す記述
...
Enter
←ジェネレータ関数 g1 の定義の終了
この g1 から順に値を取り出す例を次に示す．
例．g1 から値を取り出す（先の例の続き）>>> for x in g1(): print(x,end=’ ’)... else: print()
Enter
...
Enter
d e f

Enter

← g1 から順に値を取り出す処理←実行結果

yield from の後に別のジェネレータ関数を与えることもできる．
例．ジェネレータの入れ子（先の例の続き）>>> def g2(): Enter← g1 を呼び出す g2...
yield from ’abc’
Enter
...
yield from g1()
Enter
...
Enter
← g2 の定義の終了>>> for x in g2(): print(x,end=’ ’)... else: print()
Enter
...
Enter
a b c d e f

Enter

←実行結果

271

← g2 から順に値を取り出す処理モジュール，パッケージの作成による分割プログラミング

4.8

実用的なアプリケーションプログラムの開発においては，多くの関数やクラスを定義する．また，システムの機能を細分化して複数のソースプログラムとしてアプリケーションを作り上げることが一般的である．更に，汎用性の高い関数やクラスは，別のアプリケーションを開発する際にも再利用できることが望ましい．
これまで，様々なモジュールやパッケージの利用方法について説明したが，それらは多くの開発者（サードパーティー）によって開発されたプログラムであり，汎用性の高さゆえに公開され広く利用されている．再利用が望まれる関数やクラスはこのようにモジュールやパッケージという形で用意しておくが，ここでは，独自のモジュールやパッケージを作成する方法について説明する．
モジュール

4.8.1
4.8.1.1

単体のソースファイルとしてのモジュール

最も簡単な方法として，1 つのソースファイルに関数やクラスの定義を記述してモジュールを作成するという方法があるが，これに関してサンプルを示しながら説明する．
次のようなプログラム（モジュールファイル）MyModule.py を用意する．
プログラム：MyModule.py
1
2
3
4
5
6
7
8
9
10

# coding : utf -8# 加算関数def kasan (x , y ):print ( ’ module : ’ , __name__ )return x + y# 乗算関数def jouzan (x , y ):print ( ’ module : ’ , __name__ )return x * y

この場合のモジュールの名前はそのファイル名（拡張子は除く）であり，このモジュールには 2 つの関数 kasan とjouzan が定義されている．このモジュールは他のプログラムや Python インタプリタに読み込んで（import して）使用することができる．
■ モジュールのパスについてPython 言語処理系は import 対象のモジュールを sys.path に登録されているディレクトリの中から探す．sys.path
はリストであり，予めいくつかのディレクトリが登録されているが，Python 利用者が独自に作成したモジュールを

import の対象とするには，そのモジュールの属するディレクトリが sys.path に含まれているかを確認すること．含
まれていなければ，そのモジュールが属するディレクトリのパスを sys.path に追加しなければならない178 ．これに関しては巻末付録の「F.1.3 ライブラリのパス：sys.path」（p.414）で解説する．
上の MyModule.py がモジュールとして import できる状態での使用例を次に示す．
例．Python インタプリタからモジュール MyModule.py を利用する例 (1)>>> import MyModule

Enter

←読み込み

>>> MyModule.kasan( 2, 3 )Enter← kasan の実行
module: MyModule←モジュール名の表示
5←処理結果
この例のように，モジュール名. 関数 として179 モジュールに定義された関数を呼び出すことができる．

Python では大域変数（グローバル変数） name が定義されており，現在実行されているモジュール名がそこに保持されている．先のプログラム MyModule.py では kasan，jouzan 関数が自身が属するモジュールの名前を出力する形になっており，実行結果としてモジュール名である MyModule を出力している．
メインプログラムのモジュール名は ’ main ’ である．
（詳しくは後の「4.8.2.1 モジュールの実行」（p.274 ）を参照のこと）
178 JupyterNotebook など一部の対話環境では，sys.path に変更を加えた後，セッションの再起動が必要となる場合もあるので注意すること．
179 詳しくは巻末付録「F.1 ライブラリの読込みに関すること」（p.413）を参照のこと．

272

例．対話モードでのモジュール名の確認>>> print( name )Enter←モジュール名の表示（メイン）main←モジュール名の表示
モジュールを使用した後は，モジュールファイルと同じディレクトリ内にサブディレクトリ pycache

が作成さ

れる．
関数呼び出し時にモジュール名を省略することもできる．
（次の例参照）
例．Python インタプリタからモジュール MyModule.py を利用する例 (2)>>> from MyModule import kasan, jouzanEnter>>> kasan(2,3)
Enter
module: MyModule5← kasan の実行←モジュール名の表示←処理結果>>> jouzan(3,4)
Enter
module: MyModule
12← jouzan の実行←モジュール名の表示
←処理結果

←読み込み

この例にあるように，

fromモジュール名import使用する関数（クラス）名として180 モジュールを読み込む．
規模の大きなプログラムを開発する際は，複数のサブディレクトリと複数のファイルから構成されるパッケージの形にするのが一般的である．

4.8.2

パッケージ（ディレクトリとして構成するライブラリ）

複数のソースファイルから構成されるモジュール群をパッケージという．1 つのパッケージは 1 つのディレクトリ
として作成する．またそのディレクトリ内に初期化スクリプト

init .py を作成しておく181 ．以下に例を挙げてパッケージ作成の方法について解説する．
注意）パッケージを import 可能にするには，モジュールの場合と同様に sys.path に注意すること．
■ パッケージ作成の例
次のようなディレクトリ構成のパッケージについて考える．

./MyPackage|+init .py|+- kasan.py|+- jouzan.py|+- cdir.py（ディレクトリ）（初期化スクリプト）（テキスト形式のソースプログラム）（テキスト形式のソースプログラム）（テキスト形式のソースプログラム）

この場合のパッケージ名は，パッケージのファイル（フォルダ）を含む最上位のディレクトリ名である．この例ではMyPackage がパッケージ名となる．次に kasan.py と jouzan.py の内容を示す．
プログラム：kasan.py
1
2
3
4
5
6
7
8
9

# coding : utf -8# 加算関数def kasan (x , y ):print ( ’ module : ’ , __name__ )return x + y# テスト実行用メイン部
if __name__ == ’ __main__ ’:print ( ’ テ ス ト 実 行 ： kasan (2 ,3)= ’ , kasan (2 ,3))

180 詳しくは巻末付録「F.1 ライブラリの読込みに関すること」（p.413）を参照のこと．
181 初期化のための処理を特に記述しない場合はinit .py の内容は空でも良い．

273

プログラム：jouzan.py
1
2
3
4
5
6
7
8
9

# coding : utf -8# 乗算関数def jouzan (x , y ):print ( ’ module : ’ , __name__ )return x * y# テスト実行用メイン部
if __name__ == ’ __main__ ’:print ( ’ テ ス ト 実 行 ： jouzan (3 ,4)= ’ , jouzan (3 ,4))（ cdir.py については後で触れる）
これらパッケージを読み込んで使用する例を次に示す．
例．パッケージを読み込んで使用する>>> from MyPackage.kasan import kasan>>> from MyPackage.jouzan import jouzan

Enter
Enter

←パッケージの読込み (1)←パッケージの読込み (2)>>> kasan(2,3)
Enter
module: MyPackage.kasan
5← kasan の実行←モジュール名の表示←処理結果>>> jouzan(3,4)
Enter
module: MyPackage.jouzan
12← jouzan の実行←モジュール名の表示←処理結果

この例にあるように，

fromパッケージ名. モジュールファイル名

import使用する関数（クラス）名として182 モジュールを読み込む．ここで言うモジュールファイルは，パッケージのディレクトリ配下にあるソース
ファイル（拡張子は除く）のことである．
この例の 2 つのソースプログラムの 7〜9 行目には「テスト実行用メイン部」というものが記述されているが，これについては次に説明する．

4.8.2.1

モジュールの実行

モジュールは他のプログラム（メインプログラム）から呼び出して使用するものであるが，開発中にそのモジュー
ルをテストするために，テスト実行用のメインプログラムを別のソースファイルとして作成するのは煩わしい場合がある．この問題を軽減するために，モジュールのファイルの中に，テスト実行用のメイン部を記述しておいて，直接そのモジュールを Python インタプリタで実行するのが良い．例えば先のパッケージの例において，次のようにして

OS のコマンドシェルからモジュールを直接実行することができる．
Windows での例
C:￥Users￥katsu ＞ py MyPackage/kasan.py
Enter← OS のシェルからモジュールを直接実行
module:main←メインプログラムとして実行されていることがわかる
テスト実行：kasan(2,3)= 5←実行結果
Python のプログラミングにおいては，このような形（下記のような形）で明にメイン部を記述するスタイルが一般的である．

Python のプログラミングスタイル
if

4.8.3

name

== ’ main ’:：（メインプログラム）：

モジュールが配置されているディレクトリの調査作成したプログラムをパッケージとして 1 つのディレクトリにまとめる際に，パッケージのモジュールプログラム（スクリプト）で使用するデータ類を同一のディレクトリに含めることがある．この場合，スクリプトがデータにアク182 詳しくは巻末付録「F.1 ライブラリの読込みに関すること」（p.413）を参照のこと．

274

セスするために当該ディレクトリの位置（パス）を知る必要がある．モジュールの処理（関数やメソッド）の中で，当該スクリプトが配置されているディレクトリのパスを知るには「2.6.7.8 実行中のスクリプトに関する情報」（p.107）の所で紹介した方法を応用する．
実行中のスクリプトが自身のファイル名を取得するには，グローバル変数 ‘ ﬁle ’ を参照する．更に，os.path モ
ジュールの abspath 関数によって， ‘ ﬁle ’ の絶対パスを取得することができる．また，os.path モジュールの dirname
関数によって，それを格納するディレクトリ名を取得することができる．
以上のことを応用して次のようなモジュールファイル cdir.py をパッケージのディレクトリ MyPackage に作成する．
プログラム：cdir.py
1
2
3
4
5
6
7
8
9
10
11
12

# coding : utf -8
import os# ディレクトリの調査
def chkPath ():p = os . path . dirname ( os . path . abspath ( __file__ ) )return p# テスト実行用メイン部
if __name__ == ’ __main__ ’:print ( ’ __file__ : ’ , __file__ )print ( ’ 格 納 場 所 : ’ , chkPath () )このモジュールの chkPath 関数が当該モジュールを格納するパスを返す．動作確認をするために，カレントディレ
クトリをパッケージのディレクトリ MyPackage にして cdir.py の実行を試みる．
（下記）
例．cdir.py を直接実行する（Windows での例）

C:￥Users￥katsu￥MyPackage> py cdir.py

Enter

file : C:￥Users￥katsu￥MyPackage￥cdir.py
絶対パス: C:￥Users￥katsu￥MyPackage←モジュールを実行←モジュールファイルのパス←格納位置のパス

次にカレントディレクトリを別のパス（MyPackage の親ディレクトリ）にして，cdir.py をモジュールとして読み込み，

chkPath 関数の実行を試みる．
（下記）例．モジュールとして chkPath を実行>>> import MyPackage.cdir←モジュールの読込みEnter>>> print( MyPackage.cdir.chkPath() )C:￥Users￥katsu￥MyPackageEnter← chkPath 関数の実行←結果表示

モジュールファイル cdir.py 自身のディレクトリが表示されている．

4.8.4

init .py についてパッケージのディレクトリ内に配置する

init .py には，Python 処理系が当該パッケージを読み込む際に実行する処理（初期化などに関する処理）を記述する．具体的な内容としては，パッケージの開発者が自由に記述することができるが，ここでは応用例を 1 つ示す．
実際にパッケージを開発する際は，それを収めるディレクトリ内に複数のモジュールファイルを配置する．また，サブディレクトリを設置して「サブパッケージ」として階層的にモジュールファイル群を配置することもある．そのようなパッケージを利用する場合，

fromパッケージ. サブパッケージ. サブサブパッケージ.…

importクラスや関数などとして読み込むことになるが，このような煩雑な記述を簡略化することができる．先に示したパッケージの例

MyPackage において

init .py の内容に次のように記述する．

プログラム： init .py
12
34# coding : utf -8# モジュールの読込み
from
MyPackage . kasan
from
MyPackage . jouzan

importimportkasan
jouzan

275

5

from

MyPackage . cdir

import

これにより MyPackage を読み込む際にchkPathinit .py の内容が実行され，それぞれのモジュールファイル内に記述された関数を ‘MyPackage.’ の接頭辞により呼び出すことができる．
（次の例参照）
例．簡略化されたパッケージの扱い>>> import MyPackage←パッケージの読込みEnter← kasan の実行
←実行結果
←実行結果

>>> MyPackage.kasan(2,3)
module: MyPackage.kasan
5

Enter

>>> MyPackage.jouzan(3,4)
module: MyPackage.jouzan
12

Enter

← jouzan の実行
←実行結果
←実行結果

>>> print( MyPackage.chkPath() )Enter
C:￥Users￥katsu￥MyPackage←実行結果← chkpath の実行パッケージ／モジュールの読み込み方などに関しては，巻末付録「F.1 ライブラリの読込みに関すること」（p.413）を参照のこと．

276

ファイル内でのランダムアクセス

4.9

通常の場合，ファイル入出力は順次アクセス（Sequential Access）と呼ばれる手法で行われる．すなわち，読込みの際は先頭からファイル末尾（EOF: End Of File）に向けて順番に読み取られ，書き込みの際はその時点でのファイ
ル末尾にデータが追加される．これに対して，記録媒体の任意のバイト位置にアクセスする手法をランダムアクセス（Random Access）という．具体的には，記録媒体の指定したバイト位置から内容を読み取ったり，指定したバイト位
置にデータを書き込む手法を意味する．ここでは，ファイルに対するランダムアクセスのための基本的な事柄について説明する．

4.9.1

ファイルのアクセス位置の指定（ファイルのシーク）

通常の順次アクセスにおいては，現在開いているファイルのアクセス位置は「次にアクセスすべき位置」が自動的に取られるが，seek メソッドを使用すると，指定した任意のバイト位置にアクセス位置を移動することができる．seek
メソッドの基本的な使い方を表 36 に示す．
表 36: ファイル f に対する seek メソッドの基本的な使い方
書き方

説明

f.seek(n)ファイルの先頭からの相対位置（n バイト目：0 以上）にアクセス位置を移動する．

f.seek(n,0)

同上f.seek(n,1)

現在のアクセス位置からの相対位置（n バイト目：負の値も可）にアクセス位置を移動する．

f.seek(n,2)

ファイルの末尾からの相対位置（n バイト目：0 以下）にアクセス位置を移動する．
※ seek メソッド実行後はシーク結果のバイト位置（ファイルの先頭を基準とする）の値を返す．

4.9.2

サンプルプログラム

ファイルへのランダムアクセスを行うサンプルプログラム fram01.py を示す．このプログラムは 10 バイトのレコー
ドを 3 件持つファイルに対するランダムアクセスを行う．
プログラム：fram01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# coding : utf -8###################################################### ファイル内容を表示する関数######################################################
def dumpf ( f ):for i in range (3):f . seek ( i *10)
rec = f . read (10). decode ( ’ utf -8 ’)print ( rec )print ( ’ ’)###################################################### ファイルのランダムアクセスの試み####################################################### ファイルの作成（空ファイルの準備）
f = open ( ’ fram01 . dat ’ , ’ wb ’)
f . close ()# 読み書き可能な形で再度開く
f = open ( ’ fram01 . dat ’ , ’ rb + ’)#===== ’0000:***** ’ の 形 （ 長 さ 1 0 バ イ ト ） で 3 件 書 き 込 み =====
for i in range (3):f . write ( ’0000:***** ’. encode ( ’ utf -8 ’) )# 内容確認
dumpf ( f )#===== 2 レ コ ー ド 目 に ’0002: two ’ を 書 き 込 み =====
f . seek (20)f . write ( ’0002: two ’. encode ( ’ utf -8 ’) )# 内容確認
dumpf ( f )

277

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

#===== 0 レ コ ー ド 目 に ’000 z : zero ’ を 書 き 込 み =====
f . seek (0)f . write ( ’000 z : zero ’. encode ( ’ utf -8 ’) )# 内容確認
dumpf ( f )#===== 1 レ コ ー ド 目 に ’0001: one ’ を 書 き 込 み =====
f . seek (10)f . write ( ’0001: one ’. encode ( ’ utf -8 ’) )# 内容確認
dumpf ( f )# ファイルサイズの取得
p = f . seek (0 ,2)
print ( ’ File size : ’ ,p , ’ bytes ’)#=== 終 了 ===f . close ()解説：

16,17 行目で空のファイルを新規に作成して，20〜24 行目でファイル内容を初期化している．この結果，ファイルの内容が ’0000:*****’ というレコードを 3 つ持つ形となる．

5〜10 行目はファイルの内容全体を表示するための関数（名前：dumpf）で，プログラム内で度々呼び出されている．
29〜44 行目ではファイル内のバイト位置を seek メソッドで直接指定してランダムアクセスしている．
（順不同の書き込み）
このプログラムを実行した結果を次に示す．
0000:*****
0000:*****
0000:*****
0000:*****
0000:*****
0002: two
000z: zero
0000:*****
0002: two
000z:
0001:
0002:

zero
one
two

File size:←ファイル内容の初期化の結果← 2 レコード目に書き込み← 0 レコード目に書き込み← 1 レコード目に書き込み

30 bytes

278

4.10

オブジェクトの保存と読込み： pickle モジュール

Python 処理系に標準的に添付されている pickle モジュールを利用すると，オブジェクト（データ構造）をバイト
列183 （バイナリ形式のデータ列）に変換する，あるいはその逆の変換を行うことができる．このモジュールが提供する代表的な関数を表 37 に挙げる．
表 37: pickle モジュールが提供する代表的な関数
関数

説明

dumps(オブジェクト)「オブジェクト」をバイト列に変換したものを返す．

dump(オブジェクト, ファイル) 「オブジェクト」をバイト列に変換して「ファイル」に保存する．
loads(バイト列)「バイト列」を展開して元のオブジェクトにして返す．

load(ファイル)

dump 関数により保存されたファイルを読込み，
元のオブジェクトにして返す．

例．リスト⇔バイト列の変換>>> import pickleEnter←モジュールの読込み>>> d = [1,2,3,4,5,6,7,8,9,10]>>> bn = pickle.dumps(d)

Enter

Enter

←リストの用意←バイト列に変換>>> bnEnter←内容確認b’￥x80￥x03]q￥x00(K￥x01K￥x02K￥x03K￥x04K￥x05K￥x06K￥x07K￥x08K￥tK￥ne.’ ←バイト列になっている>>> pickle.loads(bn)Enter←リストに戻す[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]←元のリストになっている
dumps, dump 関数によって得られたバイト列はデータ型に関する情報などを含んでおり，元のデータに復元することができる．
次に，定義されたクラスのインスタンスとして生成されたオブジェクトをファイルに保存し，それを再び読み込んで元のオブジェクトに復元する例を示す．次に示すサンプルプログラム pickle02class.py は三角関数の表を生成してプロットするためのクラス Data を定義している．
（グラフの描画には matplotlib ライブラリ184 を使用する）
プログラム：pickle02class.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8
import mathimport matplotlib . pyplot as plt# 数学関数のモジュール# グラフ描画ライブラリ# - - - ク ラ ス 定 義 --class Data : # 三 角 関 数 の 表 を 扱 う ク ラ ス# - - - コ ン ス ト ラ ク タ --def __init__ ( self ):self . tri = dict ()# 辞書として空の表を生成# - - - デ ー タ の 生 成 --def gen ( self ):for ix in range (629):
x = ix / 100.0# 定義域
ysin = math . sin ( x ); ycos = math . cos ( x )# 正弦関数，余弦関数
self . tri [ x ] = [ round ( ysin ,3) , round ( ycos ,3)] # を 生 成 し て リ ス ト に す る# - - - デ ー タ 列 の 取 り 出 し --def qx ( self ):return list ( self . tri . keys () )def qsin ( self ):return [ self . tri [ x ][0] for x in self . qx ()]def qcos ( self ):return [ self . tri [ x ][1] for x in self . qx ()]# - - - グ ラ フ の プ ロ ッ ト --def plotTriangle ( self ):plt . figure ( figsize =(6 ,2.8) )183 「2.6.3.4 バイト列の扱い」（p.98）参照のこと．
184 Python でグラフを描画する場合によく用いられるライブラリ（公式インターネットサイト：https://matplotlib.org/）

拙書「Python3 ライブラリブック」でも基本的な使用方法を解説しています．

279

26
27

plt . plot ( self . qx () , self . qsin () );plt . show ()plt . plot ( self . qx () , self . qcos () )Data クラスは三角関数表を辞書オブジェクト tri として保持するもので，インスタンス生成後に gen メソッドによりデータを生成する．また，plotTriangle メソッドによりグラフを描画する．このクラスを用いて，

1) データの生成，グラフの描画，データの保存
2) 保存されたデータの復元（Data クラス），グラフの描画の処理を行う例（サンプルプログラム pickle02-1.py，pickle02-2.py）を示す．
プログラム：pickle02-1.py（データの生成，グラフ描画，データの保存）
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8
import pickle# - - - ク ラ ス 定 義 読 込 み --from pickle02class import Data
# - - - デ ー タ の 生 成 と プ ロ ッ ト --d = Data ()# オブジェクトの生成
d . gen ()# データの生成
d . plotTriangle ()# グラフのプロット# - - - p i c k l e に よ る デ ー タ 保 存 --f = open ( ’ pickle02 . dat ’ , ’ wb ’)# バイナリファイルを作成
pickle . dump ( d , f )# 保存
f . close ()プログラム：pickle02-2.py（データの読込み，グラフの描画）
1
2
3
4
5
6
7
8
9
10

# coding : utf -8
import pickle# - - - p i c k l e に よ る デ ー タ 読 込 み --f = open ( ’ pickle02 . dat ’ , ’ rb ’)# バイナリファイルとして開く
d = pickle . load ( f )# 読込み
f . close ()# - - - グ ラ フ の プ ロ ッ ト --d . plotTriangle ()これらプログラムを実行すると，Data クラスのオブジェクトがバイナリファイル pickle02.dat として保存される．特に重要な点として，読込み側のプログラム pickle02-2.py においてクラスの定義の記述が無いことが挙げられる．pickle
モジュールの機能によって保存された pickle02.dat にはデータのクラス定義の情報が含まれており，グラフ描画のための plotTriangle メソッドが実行できることが確認される．
両方のプログラムの実行において図 36 のようなグラフが表示される．

図 36: pickle02-1.py，pickle02-2.py で描画されるグラフ

280

4.11

バイナリデータの作成と展開： struct モジュール

Python に標準的に添付されている struct モジュールを用いると，C 言語の構造体（struct）を作成，あるいは展開することができる．多くのアプリケーションソフトウェアは C 言語の構造体を標準的なデータ構造として採用しており，「バイナリデータ」と呼ばれるものは多くの場合において C 言語の構造体を意味する．従って，ファイル I/O や通信においてそのようなデータ構造を生成，展開するための機能が求められることがある．ここでは，struct モジュー
ルの基本的な使用方法について説明する．

4.11.1

バイナリデータの作成

Python のバイト列としてバイナリデータを作成するには pack 関数を用いる．
書き方：

struct.pack( フォーマット, データ列 · · · )

連結対象の「データ列」は必要なだけコンマで区切って記述できる．第一引数の「フォーマット」には，変換後の C
言語のデータ型を意味する記述（表 38）を与える．連結されて出来上がったバイト列が戻り値となる．

pack 関数の使用例を次に示す．
例．バイナリデータの作成>>> import struct>>> v1 = 1

Enter>>> v2 = 2

Enter>>> v3 = 3

Enter←モジュールの読込み

Enter←ここから値（3 つ）を用意>>> b = struct.pack( ’iii’, v1, v2, v3 )Enter

←上記 3 つの「整数」を連結

>>> b
Enter
←内容確認
b’￥x01￥x00￥x00￥x00￥x02￥x00￥x00￥x00￥x03￥x00￥x00￥x00’←結果表示（バイト列）

変数 v1, v2, v3 の値を整数 ‘i’ として連結してバイト列 b を得ている．フォーマットの記述も，連結対象の 3 個のデータに対応させて ‘iii’ としている．
表 38: C 言語の型を意味するフォーマットの表記（一部）
表記 C 言語の型
意味
バイト長

c

char

長さ 1 のバイト値

1bsigned char

長さ 1 のバイト値（符号あり）

1

B

unsigned char

長さ 1 のバイト値（符号なし）

1

?

Bool

真理値型

1

h

short

短い整数（符号あり）

2

H

unsigned short

短い整数（符号なし）

2

i

int

整数（符号あり）4I

unsigned int

整数（符号なし）

4

l

long

長い整数（符号あり）

4

L

unsigned long

長い整数（符号なし）

4qlong long

更に長い整数（符号あり）

8

Q

unsigned long long

更に長い整数（符号なし）

8

e

（注 1）

浮動小数点数（半精度）

2

f

ﬂoat

浮動小数点数（単精度）

4ddouble浮動小数点数（倍精度）

8

x

（注 2）

パディング

-

注 1: ニューラルネットの扱いにおいて多く用いられる型
注 2: C 言語の構造体としてメモリ境界を合わせるための調整領域

C 言語の char 型に関する注意：
Python の文字列型（str 型）ではマルチバイト文字（Unicode）も 1 つの文字の単位として扱えるが，
C 言語の char 型は 1 バイトが 1 つの単位であるので注意すること．

281

先の例で作成したバイト列 b を展開する方法について説明する．

4.11.2

バイナリデータの展開

バイト列で表現されたバイナリデータを展開するには unpack 関数を用いる．
書き方：

struct.unpack( フォーマット, バイト列 )展開されたデータのタプルが戻り値として得られる．unpack 関数の使用例を次に示す．
例．バイナリデータの展開（先の例の続き）>>> x = struct.unpack( ’iii’, b )
>>> x

Enter

(1, 2, 3)Enter←バイナリデータを展開←内容確認←展開結果がタプルとして得られる【サンプルプログラム】
多数のデータを連結してバイナリデータとして保存し，それを読み込んで展開するプログラムの例を struct01.py に示す．
プログラム：struct01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8
import struct# 20 個 の 整 数# 20 個 の フ ォ ー マ ッ ト

d = [ x for x in range (20)]fmt = ’i ’ * 20
b = struct . pack ( fmt , * d )# ’*d ’ で 引 数 の 並 び と し て デ ー タ の 要 素 を 並 べ る

f = open ( ’ struct01 . bin ’ , ’wb ’ )f . write ( b )f . close ()# バイナリファイルを作成して# 書き込むf = open ( ’ struct01 . bin ’ , ’rb ’ )b2 = f . read ()f . close ()# 上で作成したファイルを開き# 読み込むd2 = struct . unpack ( fmt , b2 )print (
print (
print (
print (

# データを展開’元 の デ ー タ ：’ )d , ’\n ’ )’連 結-> 保 存-> 読 込 み-> 展 開 ：’ )d2 )これは 20 個の整数列のリストを生成し，それをバイナリデータとして連結，保存したものを読み込んで，展開する例
である．pack 関数呼び出し時の引数に ’*d’ という記述をすることで，リストの全要素を引数の並びとしている．このような書き方に関しては「2.7.1.4 関数呼び出し時の引数に ‘*’ を記述する方法」（p.124）で解説している．
このプログラムの実行結果の例を次に示す．
元のデータ：[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
連結->保存->読込み->展開：(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

このサンプルのような手法で，多量のデータをバイナリデータとして保存する，あるいは読み込んで展開することができる．

4.11.3

バイトオーダーについて

2 バイト以上の長さで表現される数値データに関しては，記憶資源上でのバイト毎の格納順番に注意しなければならない．このことを C 言語の int 型（4 バイト整数）を例に挙げて説明する．

16,909,060 という 4 バイトの整数について考える．この値は 1 × 2563 + 2 × 2562 + 3 × 2561 + 4 × 2560 であり，記憶資源上には 1, 2, 3, 4 というバイト値の並びとして表現される．この値を pack 関数でバイト列（バイナリデータ）

282

に変換すると次のようになる．
例．1 × 2563 + 2 × 2562 + 3 × 2561 + 4 × 2560 をバイト列に変換（Intel Core i7, Windows10 で実行）>>> n = 1*(256**3) + 2*(256**2) + 3*(256**1) + 4*(256**0)
>>> n
Enter
16909060>>> import struct

Enter

←値の生成

←内容確認
←結果表示
←モジュールの読込み

Enter←バイナリデータに変換Enter>>> b = struct.pack( ’i’, n )

>>> b
Enter
←内容確認
b’￥x04￥x03￥x02￥x01’←結果表示（バイト値の並びが逆順に見える）
この例は Intel の CPU である Core i7 の計算機（OS は Windows10）で実行したものであるが，バイト列に変換すると，バイト値の並びが逆順になっているように見える．これは，Intel 製 CPU である Core i7 のバイトオーダーがリ
トルエンディアンであることに起因する．
計算機が値をバイト列として記憶資源に格納する際の順序をバイトオーダー（図 37）185 という．バイトオーダーは計算機のアーキテクチャによって異なり，Intel の x86 系とその互換 CPU ではリトルエンディアンである．また，モトローラ社の MC68000 系列の CPU ではビッグエンディアンである．ただし，Java の JVM では独自のアーキテク
チャを実現しており，実行環境の CPU の種類に依らず Java 上では常にビッグエンディアンである．
1×256 3 ＋ 2×256 2 ＋ 3×256 1 ＋ 4×256 0 の主記憶上の格納順番

1

2

3

4

リトルエンディアン

主記憶

主記憶

4

1

3

2

2

3

1

4

↓
アドレス大

↓
アドレス大

1

2

3

4

ビッグエンディアン

図 37: バイトオーダー
このような事情から，バイナリデータを異なるアーキテクチャの計算機環境の間で流用する際にはバイトオーダー
に関して注意しなければならない．struct モジュールの pack / unpack 関数では，実行時にバイトオーダーを指定することが可能である．これに関して実行例を挙げて説明する．
例．バイトオーダーの指定（先の例の続き）>>> lb = struct.pack( ’<i’, n )>>> lbEnterb’￥x04￥x03￥x02￥x01’←リトルエンディアンを明に指定して変換

←内容確認
←結果表示

>>> bb = struct.pack( ’>i’, n )>>> bbEnterb’￥x01￥x02￥x03￥x04’

Enter

Enter

←ビッグエンディアンを明に指定して変換

←内容確認
←結果表示

この例にあるように，型を指定するフォーマットに先立って ‘<’ を付けるとリトルエンディアン，‘>’ を付けるとビッ
グエンディアンとして変換処理される．
▲注意▲

ARM, PowerPC の系列の CPU ではリトルエンディアン / ビッグエンディアンを切り替えることができる186 ので，これら CPU の計算機環境との間でバイナリデータを交換する場合は特に意識すること．

185 リトルエンディアン，ビッグエンディアンの他にもミドルエンディアンなるバイトオーダーを採用している CPU も存在する．
186 バイエンディアン

283

バイナリデータをテキストに変換する方法： base64 モジュール

4.12

Base64 形式187 は，バイナリデータを ASCII データしか通さない通信路で送受信する際に用いられるエンコーディ
ングの形式である．Python には base64 モジュールが標準的に提供されており，このモジュールを利用することで，バイナリデータを Base64 形式のテキストデータに変換することができる．base64 モジュールは次のようにして Python
処理系に読み込む．

import base64
4.12.1

バイト列→ Base64 データ

バイト列（bytes 型）のデータを Base64 形式データに変換するには b64encode 関数を使用する．
例．バイト列 bd を Base64 データ b64 に変換する

b64 = base64.b64encode( bd )得られた b64 の型も bytes である．

4.12.2

Base64 データ→バイト列

Base64 形式データをバイト列（bytes 型）のデータに変換するには b64decode 関数を使用する．
例．Base64 データ b64 をバイト列 bd に変換する

bd = base64.b64decode( b64 )4.12.3

サンプルプログラム

base64 モジュールの基本的な使用方法を，例を示しながら説明する．次に示すプログラム base64-01.py は，バイナ
リ形式のデータファイル python icon.png（画像ファイル：図 38）を，Base64 形式のテキストファイル base64.dat に変換するものである．

図 38: python icon.png
プログラム：base64-01.py（バイナリファイルを Base64 ファイルに変換）
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# coding : utf -8
import base64# バイナリデータ（画像ファイル）の読込み
f = open ( ’ python_icon . png ’ , ’rb ’ )bd = f . read ()# 一度に読込み
f . close ()b64 = base64 . b64encode ( bd )# Base64形式のバイト列に変換# ファイルに保存
f = open ( ’ base64 . dat ’ , ’wb ’ )f . write ( b64 )f . close ()base64-01.py によって作成された Base64 ファイル base64.dat の内容の一部を次に示す．

187 RFC4648

284

ファイル ：base64.dat（内容の一部）
iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN
1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7d15：（途中省略）：AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR/f/AYGSGo1CN4t4AAAAAElFTkSuQmCC

このように，ASCII 文字で内容が構成されていることがわかる．
次に，これを復元してバイナリファイル base64.png を生成するプログラム base64-02.py を次に示す．
プログラム：base64-02.py（Base64 ファイルを復元）
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# coding : utf -8
import base64# Base64データの読込み
f = open ( ’ base64 . dat ’ , ’rb ’ )b64 = f . read ()# 一度に読込み
f . close ()bd = base64 . b64decode ( b64 )# Base64形式のバイト列を復元# ファイルに保存
f = open ( ’ base64 . png ’ , ’wb ’ )f . write ( bd )f . close ()このプログラムによって生成されたバイナリファイル base64.png の内容は図 38 に示したものと同じである．

base64 モジュールは，Base16，Base32，Base85 の各形式の変換機能も提供する．詳しくは公式ドキュメントを参照のこと．

編集可能なバイト列：bytearray

4.13

先の「2.6.3.4 バイト列の扱い」（p.98）で解説したバイト列（bytes 型）はイミュータブルなデータ構造であり，作成後はその内容を変更することができない．
（次の例参照）
例．バイト列を変更しようとする試み>>> b = b’abcdefg’>>> b[1]98Enter← bytes 型のバイト列を作成←インデックス位置が 1 の要素を
←参照はできるが…

Enter>>> b[1] = 66

←値を更新しようとすると…

Enter

Traceback (most recent call last):←エラー（例外）となる
File "<stdin>", line 1, in <module>
TypeError: ’bytes’ object does not support item assignment
これに対して，bytearray 型のバイト列はミュータブルであり，変更が可能である．

4.13.1bytearray の作成方法

bytearray を作成するにはいくつかの方法があるが，生成する長さ（バイト長）を指定する方法が最も単純である．
書き方：

bytearray( バイト長 )例．5 バイトの長さの bytearray を作成>>> b = bytearray( 5 )Enter← bytearray を作成

>>> b
Enter
←内容確認
bytearray(b’￥x00￥x00￥x00￥x00￥x00’)←作成された bytearray

この方法で作成された bytearray の初期値（各バイト要素の値）は 0 である．また，bytearray オブジェクトはbytearray( バイト列表記 ) と表現される．
bytes 型の場合と同様の作成方法もある．
285

例．文字列やバイト値のリストから作成>>> b = bytearray( ’ 日本語’, ’utf-8’ )←文字列から bytearray を作成

Enter

>>> b
Enter
←内容確認
bytearray(b’￥xe6￥x97￥xa5￥xe6￥x9c￥xac￥xe8￥xaa￥x9e’)>>> b = bytearray( [65,66,67] )
>>> b
Enter
bytearray(b’ABC’)←内容←バイト値のリストから bytearray を作成

Enter

←内容確認
←内容

あるいはもっと単純に，bytes 型オブジェクトから bytearray を作成することもできる．
例．bytes 型オブジェクトを bytearray に変換する>>> b = bytearray( b’abcdefg’ )
>>> b
Enter
bytearray(b’abcdefg’)Enter← bytes オブジェクトをコンストラクタに与える

←内容確認
←内容

bytearray はミュータブルなので変更が可能である．
例．bytearray の内容変更（先の例の続き）>>> b[1]98←インデックス位置が 1 の要素の参照
←参照可能

Enter

>>> b[1] = 66

Enter

>>> b
Enter
bytearray(b’aBcdefg’)
4.13.2←値の更新も可能←内容確認←該当位置の要素が変更されている

他の型への変換

bytearray を bytes 型に変換するには ‘bytes(bytearray オブジェクト)’ とする．
例．bytes 型への変換（先の例の続き）>>> bytes( b )b’aBcdefg’Enter← bytes 型への変換←変換結果

bytearray を文字列型に変換するには decode や str を使用する．
例．文字列型への変換>>> b = bytearray( ’ 日本語’, ’utf-8’ )← bytearray オブジェクトの作成

Enter>>> b.decode(’utf-8’)’ 日本語’

Enter←文字列型への変換 (1)←変換結果>>> str( b, ’utf-8’ )’ 日本語’

Enter←文字列型への変換 (2)←変換結果

4.13.3

ファイルへの出力

bytearray オブジェクトは bytes 型の場合と同様の方法でファイルに出力することができる．
例．bytearray オブジェクトをファイルに出力する（先の例の続き）>>> f = open( ’binout01.dat’, ’wb’ )>>> f.write(b)Enter
9←出力したバイト数>>> f.close()

Enter

Enter

←出力用ファイルをオープン← write メソッドによる出力←ファイルを閉じる

この処理によってファイル binout01.dat（下記参照）が作成される．
出力ファイル：binout01.dat
1

日本語

286

4.14

exec と eval

exec 関数を用いると，文字列として記述された Python の文を実行することができる．
例．文字列で表記された Python 文の実行>>> s = ’print("これは文字列として記述した Python の文である．")’ Enter ←文字列として文を記述>>> exec(s)Enter←文字列 s の内容を実行
これは文字列として記述した Python の文である．

←実行結果

exec 関数で実行する文ではグローバル変数（大域変数）を使用することができる．
例．exec におけるグローバル変数の使用>>> g = 1

←グローバル変数に値を設定

Enter>>> s = ’print(g)’

Enter
←文を実行
←グローバル変数が引用されていることがわかる>>> exec(s)1>>> s = ’g = 5’
Enter

←グローバル変数の値を変更する文を記述

Enter

Enter

>>> exec(s)
>>> g
5

←文を記述

Enter

←文を実行

←グローバル変数の内容確認←グローバル変数が変更されていることがわかる

exec 関数の戻り値は None である．
4.14.1

名前空間の指定

exec 関数によって Python の文を実行する際に，グローバル変数の名前空間を指定することができる．具体的には
exec 関数の第 2 引数に辞書オブジェクトを与えることで，使用するグローバル変数に値を設定する．
例．異なる名前空間としてグローバル変数を与える例（先の例の続き）>>> exec( ’print(g)’, {’g’:3} )
3
←結果表示
>>> g
5

Enter

←グローバル変数 g に値 3 を設定して実行Enter←元のグローバル変数 g の内容確認←元のグローバル変数は変更されていない

辞書オブジェクトに与える変数名は文字列型である．

4.14.2eval 関数exec 関数と似た機能を持つ eval 関数がある．eval 関数で実行するものは「文」ではなく「式」であり，実行後はそれを評価した値を返す．
例．eval 関数>>> g = 5

Enter

←グローバル変数に値を設定>>> eval( ’2*g’ )
Enter
10
←戻り値

←式を評価

eval 関数でも使用するグローバル変数の名前空間を変更することができる．
例．異なる名前空間としてグローバル変数を与える例（先の例の続き）>>> eval( ’2*g’, {’g’:15} )
30
←評価結果
>>> g
5

Enter

Enter

←グローバル変数 g に値 15 を設定して評価←元のグローバル変数 g の内容確認←元のグローバル変数は変更されていない

287

4.15

collections モジュール

collections モジュールは様々なデータ構造を提供する．
4.15.1

キュー： dequedeque を使用すると，スタック（FILO）やキュー（FIFO）といったデータ構造を簡単に実現できる．また，リストを使用してこれらデータ構造を実現する場合と比べても処理速度が早い．deque の使用に先立って，次のようにして必要な機能を読み込む．

from collections import dequedeque オブジェクトを作成するには，コンストラクタ deque() を呼び出す．コンストラクタの引数にリストなどのデータ列を与えることで，deque オブジェクトに初期値を与えることができる．引数を省略すると空の deque オブ
ジェクトが作成される．

4.15.1.1

要素の追加と取り出し： append，pop

deque オブジェクトに対して append メソッドを実行することで，その右端に要素を追加することができる．また，pop メソッドを実行すると，deque オブジェクトの右端から要素を取り出して返す．その後，その要素は deque オブ
ジェクトから削除される．
例．deque によるスタックの実現>>> from collections import deque>>> q.append(’a’)
>>> q
Enter
deque([’a’])←モジュールの読込み← 空の deque オブジェクトの作成

Enter>>> q = deque()

Enter

Enter

← 右端に要素を追加← 内容確認← deque オブジェクトの状態>>> q.append(’b’)

Enter← 右端に要素を追加

>>> q
Enter
← 内容確認deque([’a’, ’b’])← deque オブジェクトの状態>>> q.append(’c’)

Enter← 右端に要素を追加

>>> q
Enter
← 内容確認deque([’a’, ’b’, ’c’])← deque オブジェクトの状態>>> q.pop()
Enter
’c’
← 戻り値

← 右端の要素を取り出して削除

>>> q
Enter
← 内容確認deque([’a’, ’b’])← deque オブジェクトの状態>>> q.pop()
Enter
’b’
← 戻り値
>>> q
Enter
deque([’a’])← 右端の要素を取り出して削除← 内容確認← deque オブジェクトの状態>>> q.pop()
Enter
’a’
← 戻り値

← 右端の要素を取り出して削除

>>> q
Enter
← 内容確認deque([])← deque オブジェクトの状態
append，pop と似たメソッドに appendleft，popleft というメソッドもあり，それらは deque の左端に対して要素の追加や取り出しの処理を行う．
課題．ここで説明したメソッド群を用いてキュー（FIFO）を実現せよ．

4.15.1.2

要素の順序の回転： rotate

deque オブジェクトの要素を失うことなくその順序をずらす（回転する）には rotate メソッドを用いる．このメソッドの引数には回転のステップ数を与える．
（ステップ数の暗黙値は 1 である） 正のステップ数を与えると右に，負のス

288テップ数を与えると左に回転する．
例．deque オブジェクトの回転>>> q = deque( [’a’,’b’,’c’,’d’,’e’] )
>>> q
Enter
← 内容確認deque([’a’, ’b’, ’c’, ’d’, ’e’])← deque オブジェクトの状態

>>> q
Enter
← 内容確認deque([’e’, ’a’, ’b’, ’c’, ’d’])← deque オブジェクトの状態← 右に 2 ステップ回転Enter>>> q.rotate(2)

>>> q
Enter
← 内容確認deque([’c’, ’d’, ’e’, ’a’, ’b’])>>> q.rotate(-3)← deque オブジェクトの状態← 左に 3 ステップ回転

Enter

>>> q
Enter
← 内容確認deque([’a’, ’b’, ’c’, ’d’, ’e’])
4.15.2← deque オブジェクトの作成← 右に 1 ステップ回転Enter>>> q.rotate()Enter← deque オブジェクトの状態

要素の集計： Counter

Counter を使用すると，データ構造の要素の数を集計することができる．Counter の使用に先立って，次のようにして必要な機能を読み込む．

from collections import Counter
例．要素数の集計>>> from collections import Counter←モジュールの読込みEnter>>> c = Counter( [’a’,’b’,’a’,’c’,’a’,’b’] )
>>> c
Enter
Counter({’a’:←内容確認
3, ’b’: 2, ’c’:1})

←リストの要素数を集計

Enter

←集計結果

集計結果は Counter オブジェクトとして得られる．これは辞書（dict）のサブクラスであり，辞書に対するメソッドが使用できる．
例．戻り値は辞書と同様の扱いが可能（先の例の続き）>>> c[’a’]
3

Enter

←要素 ’a’ の個数を求める←3個>>> list( c.keys() )[’a’, ’b’, ’c’]>>> list( c.values() )[3, 2, 1]

Enter
Enter

>>> list( c.items() )Enter[(’a’, 3), (’b’, 2), (’c’, 1)]←キーのリストを求める←キーのリスト←値のリストを求める←値のリスト←全エントリのリストを求める←全エントリのリスト

同様の方法で，タプルや文字列の要素も集計できる．
（次の例参照）
例．要素数の集計（先の例の続き）>>> Counter( (’a’,’b’,’a’,’c’,’a’,’b’) )Enter
Counter({’a’: 3, ’b’: 2, ’c’: 1})←集計結果>>> Counter( ’abacab’ )EnterCounter({’a’: 3, ’b’: 2, ’c’:
4.15.2.1←タプルの要素数を集計←文字列の要素数を集計
1})
←集計結果

出現頻度の順に集計結果を取り出す

集計結果の Counter オブジェクトに対して most common メソッドを使用すると，出現頻度の高いものを取り出すことができる．

289

例．出現頻度の高いものを取り出す（先の例の続き）>>> c.most common(1)Enter←最も出現頻度の高いものを抽出[(’a’, 3)]←’a’ の出現頻度が最も高い>>> c.most common(2)[(’a’, 3), (’b’, 2)]Enter←出現頻度の高いものを 2 位まで抽出←’a’ が 1 位，’b’ が 2 位>>> dict( c.most common(2) )Enter←上の結果を辞書に変換{’a’: 3, ’b’: 2}←これで辞書として使える
most common の引数を空にすると，全ての集計結果を頻度の高い順に並べたものを返す．
例．集計結果を出現頻度の高い順に全て取り出す（先の例の続き）>>> c.most common()Enter←引数を空にして実行[(’a’, 3), (’b’, 2), (’c’, 1)]←結果
4.15.3

namedtuple

namedtuple を使用すると，class 文によるクラス定義に依ることなく，ドット表記の属性188 の保持を実現することができる．ただし，namedtuple のオブジェクトはタプルと同様，事後に値を変更することはできない．

namedtuple の使用に先立って，次のようにして必要な機能を読み込む．
from collections import namedtuple
例として「3 つの属性 x,y,z を持つオブジェクト型」である ‘MyNt’ 型を定義して使用する流れを示す．
例．3 つの属性 x,y,z を持つ ‘MyNt’ 型の定義>>> from collections import namedtupleEnter>>> MyNt = namedtuple(’MyNt’,[’x’,’y’,’z’])←モジュールの読込みEnter← ‘MyNt’ 型の定義

このように，

namedtuple(型名, 属性リスト)とすることで「型」が生成される．
「型名」と「属性リスト」の要素は文字列型で与える．この例では，‘MyNt’ という型を生成して，それを MyNt というシンボルに割り当てている．これ以後は MyNt を型としてオブジェクトを生成することができる．
（次の例参照）
例．MyNt 型オブジェクトの生成（先の例の続き）>>> nt = MyNt( x=1, y=2, z=3 )Enter← MyNt 型オブジェクト nt の生成>>> nt.xEnter← nt の x プロパティを参照
1←値が確認できる．
このように，
型名 (値の設定)と記述することで，属性に値を与えてオブジェクトを生成することができる．
例．オブジェクトの構造の確認（先の例の続き）>>> ntEnter←オブジェクト自体（全体）を確認する
MyNt(x=1, y=2, z=3)
←データ構造が確認できる．
>>> type( nt )Enter<class ’ main .MyNt’>← nt の型を確認する←結果表示

オブジェクトを生成する際は，全ての属性に初期値を与えなければならない．
例．オブジェクト生成時に属性値の設定が不足してはならない（先の例の続き）>>> MyNt( x=1, y=2 )Enter←初期値不足での MyNt 型オブジェクト生成の試み

Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>
TypeError: MyNt. new () missing 1 required positional argument:
188 「属性」は「プロパティ」とも呼ばれる．

290

’z’

itertools モジュール

4.16

itertools モジュールは反復処理のためのイテレータを作成する便利な機能を多数提供する．ここではその中からい
くつかの機能を紹介し，それらの基本的な使用方法について解説する．

4.16.1

イテラブルの連結： chain

chain クラスを使用すると，複数のイテラブルを形式的に連結することができる．
書き方：

chain( イテラブルの並び )「イテラブルの並び」は 1 つ以上のオブジェクトをコンマで区切って並べたもので，それらを形式的に連結したイテレータ（chain オブジェクト）を返す．引数に与えるイテラブルは，リストや文字列といったイテラブルオブジェクトの他に，ファイルオブジェクトなど様々なものが使用できる．
例．イテラブルの連結>>> q1 = [’a’,’b’]; q2 = ’cd’>>> for x in chain(q1,q2):...
print(x)
Enter
...
Enter

← chain クラスの読み込みEnter>>> from itertools import chain←イテラブルオブジェクトを 2 つ用意

Enter

Enter

←それらを連結して反復処理に使用する←出力（ここから）abcd←出力（ここまで）別々に用意されたイテラブルオブジェクト q1，q2 が連結され 1 つのイテレータとして扱われていることがわかる．

chain オブジェクトはイテラブルであるだけでなくイテレータである．
（次の例）
例．イテレータとしての chain オブジェクト（先の例の続き）>>> c = chain(q1,q2)Enter← chain オブジェクト c の作成

>>> c
Enter
←内容確認
<itertools.chain object at 0x000001DB14EBE020>← chain オブジェクトになっている>>> next(c)Enter← next 関数の実行’a’←要素が得られている
next 関数で要素を取り出すことができており，chain オブジェクトがイテレータであることがわかる．
4.16.2

無限のカウンタ： count

count クラスを用いると無限長のイテレータが実現できる．
書き方：

count( start=初期値, step=増分 )「初期値」から「増分」ずつ増やしながら次々と値を生成する count オブジェクト（イテレータの一種）を返す．

count( 初期値, 増分 ) と記述しても良い．
例．無限のカウンタ>>> from itertools import countEnter← count クラスの読み込み>>> for x in count(0,2): Enter← 0 から 2 間隔で値を際限なく生成...
s = input(str(x)+’ : q で終了> ’)Enter←’q’ が入力されるまで...
if s == ’q’: breakEnter←際限なく繰り返す
...
Enter
0 :

q で終了> a

Enter

2 :

q で終了> b

Enter

4 :

q で終了> qEnter←入力インタラクション（ここから）←入力インタラクション（ここまで）

この例は，キーボードからの入力受付けを繰り返すもので，’q’ が入力されると for の繰り返しを終了する．count オ
ブジェクトが生成した数値が input 関数のプロンプトに表示されていることが確認できる．

291

4.16.3

イテラブルの繰り返し： cycle

cycle クラスを使用すると，与えられたイテラブルを無限に繰り返すイテレータ（cycle オブジェクト）を生成する
ことができる．
書き方：

cycle( イテレータ )「イテレータ」を無限に繰り返すイテレータを返す．
例．イテレータを際限なく繰り返すEnter>>> from itertools import cycle>>> q = [’a’,’b’,’c’]Enter← cycle クラスの読み込み←このようなイテレータ q を>>> for n,x in enumerate( cycle(q) ): Enter←際限なく繰り返す...
if n < 20: Enter←ただし便宜上，20 回で終了させる...
print(x,end=’ ’)
Enter
...
else: Enter...
print()
Enter
...
break
Enter
...
Enter
←出力

a b c a b c a b c a b c a b c a b c a b▲注意▲cycle オブジェクトは与えられたイテレータの要素を内部に記録することで要素の生成を繰り返す．従って，長大なイテレータをコンストラクタに与える場合は注意が必要である．従って cycle クラス以外のものを状況に応じてプログラマが独自に実装する方が好ましい場合もある．

4.16.4

オブジェクトの繰り返し： repeat

repeat クラスを使用すると，与えられたオブジェクトを指定した回数だけ繰り返すイテレータ（repeat オブジェク
ト）を生成することができる．
書き方：

repeat( オブジェクト, times=回数 )「オブジェクト」を「回数」だけ繰り返すイテレータを返す．
「回数」を省略すると無限に繰り返すイテレータを返す．

repeat( オブジェクト, 回数 ) と記述しても良い．
例．’a’ を 10 回繰り返すイテレータ>>> from itertools import repeat>>> rep = 10

Enter

Enter

← repeat クラスの読み込み←繰り返し回数>>> for n,x in enumerate( repeat(’a’,rep) ):...
if n < rep-1: Enter...
print(x,end=’ ’)
Enter
...
else: Enter...
print(x)
Enter
...
Enter
a a a a a a a a a a
4.16.5Enter←出力

連続要素のグループ化： groupby

groupby クラスを使用すると，与えられたイテラブルを連続要素ごとにグループ化し，それらが並ぶイテレータ（groupby オブジェクト）を生成することができる．
書き方：

groupby( イテラブル )「イテラブル」を連続要素ごとにグループ化し，(要素, 部分列イテレータ) なる形式の要素が並ぶイテレータにして返す．この場合の「部分列イテレータ」は grouper オブジェクトである．

292

例．連続要素のグループ化← groupby クラスの読み込みEnter>>> from itertools import groupby>>> q = [’a’,’a’,’a’,’a’,’b’,’b’,’b’,’c’,’c’,’d’]Enter←連続要素を持つイテラブル>>> for e,x in groupby(q): Enter←グループごとに取り出しながら...
print(e,’: ’,end=’’)
Enter
...
for y in x: Enter←部分列イテレータごとに...
print(y,end=’ ’)
Enter
←出力する
...
print()
Enter
...
Enter
a :
b :
c :
d :

←出力（ここから）a a a a
b b b
c c
d

←出力（ここまで）

この例で作成したイテラブル q がどのようにグループ化されたかを更に次のような形で確認するとわかりやすい．
例．連続要素のグループ化：その２（先の例の続き）>>> [ (e,[y for y in x]) for e,x in groupby(q) ]Enter←リストの内包表記で確認する[(’a’, [’a’, ’a’, ’a’, ’a’]), (’b’, [’b’, ’b’, ’b’]), (’c’, [’c’, ’c’]), (’d’, [’d’])]groupby クラスは指定した「ある特徴」で連続要素をグループ化することもできる．
書き方：

groupby( イテラブル, key=特徴化関数 )要素の特徴を取得する関数を「特徴化関数」に与える．
次の例に示す関数 ft は，与えられた 0 から 29 までの数の所属範囲を ’0〜9’，’10〜19’，’20〜29’ という文字列で特徴化するものである．
例．与えられた数の所属範囲を返す関数（先の例の続き）>>> def ft(x):

Enter

...

if x<10:return ’0〜9’...

if x<20:

return ’10〜19’...

return ’20〜29’

Enter
Enter

Enter

...

Enter

>>>

← Python のプロンプトに戻った

この関数 ft を groupby コンストラクタの引数「key=」に与えてグループ化する例を次に示す．
例．特徴ごとに要素をグループ化する（先の例の続き）>>> q = range(30)[::-1]← 29〜0 の数列を作成

Enter>>> for e,x in groupby(q,key=ft):...

print(e,’:’,end=’’)...

for y in x:

Enter

...
...
...

print(y,end=’ ’)print()

Enter
Enter

Enter

Enter

Enter

20〜29 : 29 28 27 26 25 24 23 22 21 20
10〜19 : 19 18 17 16 15 14 13 12 11 10
0〜9 : 9 8 7 6 5 4 3 2 1 0
4.16.6←関数 ft で特徴化して反復処理←出力（ここから）←出力（ここまで）直積集合： productproduct クラスを使用すると，与えられた複数のイテラブルの直積集合（デカルト積）をイテレータとして生成することができる．
書き方：

product( イテラブルの並び )「イテラブルの並び」の直積集合を作り，イテレータ（product オブジェクト）として返す．

293

例．直積集合Enter>>> q1 = [1,2,3]; q2 = [’a’,’b’,’c’]>>> for x in product(q1,q2):
...
...

else:

...

Enter

print()← 2 つのイテラブルを用意←直積集合を作って

Enter

←出力する

Enter

print(x,end=’ ’)← product クラスの読み込みEnter>>> from itertools import product

Enter
↓出力

(1, ’a’) (1, ’b’) (1, ’c’) (2, ’a’) (2, ’b’) (2, ’c’) (3, ’a’) (3, ’b’) (3, ’c’)
この例のように，直積集合の要素がタプルの形で得られている．
課題．3 つ以上のイテラブルの直積集合を作成し，上記の例に倣って出力を確認せよ．

4.16.7

組合せ： combinations

combinations クラスを使用すると，与えられたイテラブルの要素の組合せをイテレータとして生成することができる．
書き方：

combinations( イテラブル, r=個数 )「イテラブル」の要素から「個数」だけ要素を取り出す組合せを作り，それをイテレータ（combinations オブジェクト）として返す．

combinations( イテラブル, 個数 ) と記述しても良い．
例．組合せ>>> from itertools import combinationsEnter>>> q = [’a’,’b’,’c’,’d’]>>> for x in combinations(q,2):
...
...

else:

...

Enter

print()← combinations クラスの読み込み←このイテラブルからEnter← 2 つの要素を取り出す組合せを作り
←出力する

Enter

print(x,end=’ ’)

Enter

Enter
↓出力

(’a’, ’b’) (’a’, ’c’) (’a’, ’d’) (’b’, ’c’) (’b’, ’d’) (’c’, ’d’)
4.16.8

順列： permutations

permutations クラスを使用すると，与えられたイテラブルの要素の順列をイテレータとして生成することができる．
書き方：

permutations( イテラブル, r=個数 )「イテラブル」の要素から「個数」だけ要素を取り出す順列を作り，それをイテレータ（permutations オブジェクト）
として返す．

permutations( イテラブル, 個数 ) と記述しても良い．
例．順列>>> from itertools import permutationsEnter>>> q = [’a’,’b’,’c’,’d’]>>> for x in permutations(q,2):
...

Enter

print(x,end=’ ’)

...

else:

...

Enter

print()Enter← permutations クラスの読み込み←このイテラブルからEnter← 2 つの要素を取り出す順列を作り
←出力する

Enter
↓出力

(’a’, ’b’) (’a’, ’c’) (’a’, ’d’) (’b’, ’a’) (’b’, ’c’) (’b’, ’d’)(’c’, ’a’) (’c’, ’b’) (’c’, ’d’) (’d’, ’a’) (’d’, ’b’) (’d’, ’c’)

294

列挙型：

4.17

enum モジュール

列挙型のデータ構造を提供する enum モジュールが Python 3.4 から標準的に提供されている．列挙型は，順序のある要素から成るデータ列であり，for 文などのイテレーション（繰り返し制御）に使用することができる189 ．列挙
型の要素は名前と値を持つ．

4.17.1

Enum 型

enum モジュールが提供する最も基本的なデータ型に Enum クラスがある．Enum を使用するにはfrom enum import Enumとして必要なものを読み込む．その後，次の様な記述で Enum オブジェクトを生成する．
書き方：

Enum( ’ 型名’, 要素の列 )「要素の列」には登録する各要素の名前のリスト（あるいは空白で区切られた文字列）を与える．各要素には 1 から始まる整数値（1, 2, 3, …）が暗黙値として設定される．

’a’, ’b’, ’c’ という名前を持つ 3 つの要素から成る Enum オブジェクト E を生成する例を示す．
例．列挙型オブジェクト E の生成>>> from enum import EnumEnter

←モジュールの読み込み←’MyEnum’ という型名の Enum オブジェクトを生成>>> E = Enum(’MyEnum’,[’a’,’b’,’c’]) Enter

>>> E
Enter
←内容確認
<enum ’MyEnum’>←列挙型となっていることがわかる
この例と同じ Enum オブジェクトはE = Enum(’MyEnum’,’a b c’)として生成することもできる．

Enum オブジェクトの要素にアクセスするには，当該オブジェクトの後ろにドット「.」と要素の名前を付けるか，‘[名前]’ を添える．また，要素の名前と値は name，value という属性（プロパティ）として参照できる．
例．Enum の要素へのアクセス（先の例の続き）>>> E.aEnter<MyEnum.a: 1>←名前 ’a’ の要素の内容を確認←結果表示（名前が’a’，値が 1 となっている）>>> E.a.name
Enter
’a’
←結果表示

←明に名前を取り出す>>> E.a.value
Enter
1
←結果表示

←要素の値を取り出す>>> E[’a’].value
Enter
1
←同じ結果

← ‘[名前]’ による要素の参照

Enum オブジェクトに存在しない名前を用いてアクセスするとエラーが発生する．
例．存在しない名前でアクセス>>> E.dEnter←名前 ’d’ の要素にアクセスを試みると…

Traceback (most recent call last):←エラーとなる
File "<stdin>", line 1, in <module>（途中省略）
raise AttributeError(name) from None
AttributeError: d
この例では AttributeError が起こっている．同様に ‘[名前]’ を添える形で存在しない名前の要素にアクセスしようとすると KeyError が起こる．
イテレーション（for 文などによる繰り返し処理）において Enum の全要素に順番にアクセスすることができる．

189 列挙型はイテレータ（p.78「2.5.1.8 イテレータ」参照のこと）ではないので参照によって破壊されない．

295

例．for 文で Enum オブジェクトの要素に順次アクセスする（先の例の続き）>>> for e in E: Enter← for 文で各要素に順番にアクセスする...
print( e.name, ’->’, e.value )Enter←各要素の名前と値を表示
...
Enter
← for 文の終了
←名前と値を順番に表示

a -> 1b -> 2c -> 3

Enum オブジェクトの各要素の名前と値を辞書の形で与えることができる．
例．名前と値のペアを辞書の形で与える>>> E2 = Enum(’MyEnum2’, {’x’:100, ’y’:200, ’z’:300} ) Enter←値の確認>>> E2.y.value
Enter
200
←結果表示
4.17.2←辞書で名前と値を与える

定数の取り扱いを実現する方法の例

多くのプログラミング言語では定数を定義して使用することができる．この場合の定数は値の変更ができないもの
であり，値を持った変数とは異なるものである．

Python の基本的な文法には定数を実現するためのものはないが，enum モジュールを用いることで定数を実現することができる．ただし，Enum クラスによって実現した定数の扱いには注意する必要がある．例えば先の例で作成した E2 というクラスは x，y，z という 3 つの定数を持ち，それらの値は整数型（int）であるが，それらを用いて整数型の演算をしようとすると問題が起こる．
（次の例）
例．Enum の値の取り扱い上の問題（先の例の続き）>>> E2.y + E2.z

← Enum の値を演算に用いる試み

Enter

Traceback (most recent call last):←エラーが発生するFile "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: ’MyEnum2’ and ’MyEnum2’
これは，先に定義した定数クラス MyEnum2 に ’+’ の演算が定義されていないことが原因である．従って，整数型と同じ処理を Enum の定数にも適用するには，整数型（int）と Enum の両方を継承するクラスを定義して，それを整数型の定数のクラスとして用いると良い．
（次の例）
例．整数の定数を定義する

Enter

...

KiB = 1024...

MiB = 1048576

...

Enter

← int と Enum の両方を継承するクラスの定義

Enter>>> class SI(int,Enum):Enter←クラス定義の終了

このように SI クラスを定義すると，int 型と Enum クラス両方の性質を継承した要素が扱える．例の中では KiB，

MiB という 2 つの整数型の要素がクラスのプロパティとして定義されているが，それらは同時に Enum の要素にもなる．これら要素を整数（int 型）の定数と見なして扱うことができる．
例．計算や比較への応用（先の例の続き）>>> SI.KiB * SI.KiB
Enter
1048576←結果表示>>> SI.KiB * SI.KiB == SI.MiB
True
←結果表示

←要素同士の計算が可能

Enter←比較も可能Enum の要素の値は事後に変更することができない．

296

例．値の変更の試み（先の例の続き）

Enter>>> SI.KiB = 1000

←要素の値を変更しようとすると…

Traceback (most recent call last):←エラーが発生するFile "<stdin>", line 1, in <module>（途中省略）
raise AttributeError(’cannot reassign member %r’ % (name, ))AttributeError: cannot reassign member ’KiB’
例．イテレーション（繰り返し処理）の対象としても利用できる（先の例の続き）>>> for e in SI: Enter← for 文で各要素に順番にアクセスする...
print( e.name, ’->’, e.value )Enter←各要素の名前と値を表示
...
Enter
← for 文の終了
KiB -> 1024
←名前と値を順番に表示
MiB -> 1048576
上の例で示した SI のようなクラスは IntEnum クラスとして用意されている．

4.17.3

IntEnum

整数型（int 型）と Enum の両方を継承した IntEnum クラスが使用できる．このクラスの使用に先立って ‘fromenum import IntEnum’ として必要なものを読み込む．
例．IntEnum クラス>>> from enum import IntEnum←モジュールの読み込みEnter>>> class SI2(IntEnum): Enter← IntEnum を継承する SI2 クラスの定義...
KiB = 1024
Enter
...
MiB = 1048576
Enter
...
Enter
←クラス定義の記述の終了←整数としての演算>>> SI2.KiB * SI2.KiB
Enter
1048576←結果表示

これと同様の処理を次のようにしても実行できる．
例．IntEnum クラスのインスタンスを生成>>> SI2 = IntEnum(’SI’, {’KiB’:1024, ’MiB’:1048576} ) Enter←整数としての演算>>> SI2.KiB * SI2.KiB
Enter
1048576←結果表示
4.17.4← IntEnum のインスタンス

auto 関数による Enum 要素への値の割り当て

Enum を継承したクラスを定義する際，各要素の値に auto 関数で自動的に値を与えることができる．auto 関数を使用するにはfrom enum import auto
として Enum モジュールから読み込んでおく必要がある．
例．auto 関数による値の割り当てEnter>>> from enum import Enum, auto>>> class MyInt(int,Enum):
Enter

Enter

←モジュールの読み込み←クラスの定義←値として 10 を割り当てる...

a = 10...

b = auto()Enter← auto による値の割り当て...

c = auto()Enter← auto による値の割り当て

...

Enter

←クラスの定義の記述の終了

この例で定義している MyInt は 3 つの要素 a, b, c を持ち，a には 10 が割り当てられ，後の要素には auto 関数で値が割り当てられている．auto 関数は 1 刻みで増加する形で値を順次生成する．

297

例．各要素の値を調べる（先の例の続き）>>> for e in MyInt: Enter← for 文による繰り返しで全要素を調べる...
print( e.name, ’->’, e.value )Enter←各要素の名前と値を表示
...
Enter
← for 文の記述の終了
a -> 10b -> 11c -> 12← 10 から 1 ずつ増える形で値が設定されている．

先頭の要素も auto 関数で値を設定した場合は 1 から始まる整数が順番に割り当てられる．

4.17.4.1

非数値要素への auto 関数による値の割り当て（参考事項）

文字列（str 型）と Enum 型を継承する次のようなクラスを定義する場合について考える．
例．str と Enum を継承するクラス>>> class MyStr(str,Enum): Enter←クラスの定義...
a = ’start’Enter←値として ’start’ を割り当てる...
b = auto()Enter← auto による値の割り当て...
c = auto()Enter← auto による値の割り当て
...
Enter
←クラスの定義の記述の終了
MyStr をこのように定義することもできるが推奨されず，次のような警告メッセージが出力される．
警告メッセージ：Python 3.12 での実行

<stdin>:3: DeprecationWarning: In 3.13 the default ‘auto()‘/‘ generate next value ‘
will require all values to be sortable and support adding +1
and the value returned will be the largest value in the enum incremented by 1
<stdin>:4: DeprecationWarning: In 3.13 the default ‘auto()‘/‘ generate next value ‘
will require all values to be sortable and support adding +1
and the value returned will be the largest value in the enum incremented by 1
この例のような定義は今後の Python の版では記述できなくなる可能性があるので注意すること．
上で定義した MyStr の各要素の値を調べる．
例．各要素の値を調べる（先の例の続き）>>> for e in MyStr: Enter← for 文による繰り返しで全要素を調べる...
print( e.name, ’->’, e.value, ’type:’, type(e.value) )
Enter
と型を表示
...
Enter

←各要素の名前と値← for 文の記述の終了

a -> start type: <class ’str’>b -> 1 type: <class ’str’>c -> 2 type: <class ’str’>← 最初は ’start’←次の値（文字列としての ’1’）
←更に次の値（文字列としての ’2’）

auto 関数による値の生成は ’1’ から始まっていることがわかる．
（Python 3.7）
ここで紹介したクラス以外にも，enum モジュールは更に Flag，IntFlag といったクラス（ビット演算に関する機能を持つ）を提供する．詳しくは Python の公式インターネットサイトなどの情報を参照のこと．

298

例外（エラー）の処理

4.18「2.4.1.6 例外処理」（p.51）では，プログラムの実行中に発生するエラーや例外を扱うための方法を解説した．try〜

except の例外処理を適切に記述することで，例外が発生する場合においても処理系を中断することなくプログラムの実行を続けることができるが，ここでは更に進んだ内容について解説する．

4.18.1

エラーメッセージをデータとして取得する方法：

traceback モジュール

エラーや例外の際に得られるメッセージを扱うための traceback モジュールを紹介する．このモジュールを使用す
るには次のようにしてモジュールを読み込む．

import traceback
この後，try〜except の例外処理において，format exc 関数を呼び出すと，例外やエラーの発生においてシステムが生成するメッセージを文字列型データとして取得することができる．

format exc を用いたサンプルプログラム error01.py を示す．
プログラム：error01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8
import traceback
try :#エラーが発生する部分
a = 2 * b
except :#エラー処理の部分
print ( ’*** 例 外 が 発 生 し ま し た *** ’)er = traceback . format_exc ()print ( er . rstrip ())
print ( ’**************************\ n ’)
print ( ’ - - - プ ロ グ ラ ム 終 了 - - - ’)print ( ’ 処 理 系 の 動 作 は 中 断 さ れ て い ま せ ん ． ’ )解説プログラムの 6 行目で，値が割当てられていない変数（記号）b が参照されている．通常ならばこの行はエラーとなり，処理系の実行は中断するが，例外処理が施されているので，9 行目以降に処理が移行する．10 行目に

er = traceback.format exc()という記述があり，これによりエラーメッセージが文字列型のデータとして変数 er に格納される．
このプログラムを実行した例を次に示す．
*** 例外が発生しました ***Traceback (most recent call last):
File "C:￥Users￥katsu￥error01.py", line 6, in <module>
a = 2 * b^
NameError: name ’b’ is not defined**************************--- プログラム終了 --処理系の動作は中断されていません．

エラーによるプログラムの中断ははく，エラーメッセージが文字列のデータとして得られていることがわかる．
エラーメッセージだけでなく，例外事象に関する様々な情報を保持する例外オブジェクトを取得する方法について，後の「4.18.3 例外オブジェクト」（p.300）で解説する．

4.18.2

例外を発生させる方法

プログラム中の任意の行において設定された条件を検査し，その結果によって例外を発生させる assert 文がある．
これは，プログラムのデバッグ作業において役立つことがある．

299

次のサンプルプログラム assert01.py について考える．
プログラム：assert01.py
1
2
3
4
5
6

# coding : utf -8
while True :s = input ( ’ 数 値 を 入 力 > ’)if s . isdigit ():n = int ( s )assert n %3!=0 , ’{} は 3 の 倍 数 で す ． ’ . format ( n )このプログラムは，input 関数によってキーボード（標準入力）から文字列を読み込む処理を際限なく繰り返す形になっている．ただし「3 の倍数」を表現する文字列を入力すると assert 文（6 行目）により例外が発生してプログラ
ムの実行が中断する．
（次の例参照）

assert1.py の実行例．
数値を入力>aEnter

数値を入力>10

Enter

数値を入力>20

Enter

数値を入力>33

Enter

Traceback (most recent call last):
File "C:￥Users￥katsu￥assert01.py", line 6, in <module>
assert n%3!=0, ’{} は 3 の倍数です．’.format(n)^^^^^^
AssertionError: 33 は 3 の倍数です．

● assert 文
書き方：

assert条件式, エラーメッセージ「条件式」が真（True）とならない場合（False となる場合）に「エラーメッセージ」を生成して例外 AssertionError
を発生させる．

assert 文とは別に，任意の種類の例外（エラー）を発生させる raise 文も使用できる．
（次の例参照）
例．raise 文で意図的に ValueError を起こす>>> raise ValueError(’ 故意に生成した ValueError’)Enter
Traceback (most recent call last):←エラーメッセージが表示されるFile "<stdin>", line 1, in <module>
ValueError: 故意に生成した ValueError● raise 文
書き方：

raise

例外の名前 (エラーメッセージ)「例外の名前」の例外（エラー）を発生させる．このとき「エラーメッセージ」をメッセージとする．

assert，raise 文で発生する例外は try 文でハンドリングすることができる．
4.18.3

例外オブジェクト

Python 処理系において例外（エラー）が発生すると例外オブジェクトが作成される．これに関して次のサンプルプ
ログラム error02.py を用いて考える．
プログラム：error02.py
1
2
3
4
5
6

# coding : utf -8
try :a = 1/0
except ZeroDivisionError as e :print ( ’ 例 外 オ ブ ジ ェ ク ト : ’ , e )print ( ’ ク ラ ス : ’ , type ( e ))このプログラムは 3 行目で 0 による除算を試みており，これによって ZeroDivisionError という例外が発生するが，この例外の事象（関連情報）が例外オブジェクトとして変数 e に渡されて（4 行目）いる．その内容とクラスに関す

300

る情報を 5〜6 行目で出力している．このプログラムを実行すると次のような出力が得られる．
出力の例．
例外オブジェクト: division by zero
クラス: <class ’ZeroDivisionError’>

このプログラムのように，エラーハンドリングの際にexcept 例外の種類 as 変数と記述することで，発生した例外オブジェクトが「変数」に渡される．また「例外の種類」の部分は，
例外オブジェクトのクラス名である．

4.18.3.1

例外オブジェクトのクラス階層

システムに発生する例外の種類は，例外オブジェクトのクラス階層として分類されており，すべての例外の基底クラ
スは BaseException である．またこのクラス直下の派生クラスに Exception クラスがあり，これの派生クラスとして
凡そ全ての例外や警告のクラスが含まれる．例えば先のプログラム error02.py でハンドリングした ZeroDivisionError
はクラス階層内でBaseException→

Exception→

ArithmeticError→

ZeroDivisionErrorと位置づけられている．従って，例外をハンドリングする際の except の部分をexcept Exception as e:などと記述することで，様々な種類のエラーを一括して扱うことができる．
参考）
後で紹介するプログラム getSubclasses.py（p.324）を用いて全ての例外オブジェクトの階層関係を出力して観察さ
れたい．

4.19

使用されているシンボルの調査

値の設定されている変数やオブジェクトの名前（シンボル）を調べる方法について説明する．グローバルのスコープで定義されているシンボル190 を調べるには globals 関数を使用する．
（次の例参照）
例．グローバルのシンボルを調べる191>>> globals()← globals 関数の実行Enter{’ name ’: ’ main ’, ’ doc ’: None, ’ package ’: None,’ loader ’: <class ’ frozen importlib.BuiltinImporter’>,’ spec ’: None, ’ annotations ’: {},’ builtins ’: <module ’builtins’ (built-in)>}←シンボルへの値の割当が辞書の形で得られる

この結果と in 演算子を用いることで，あるシンボルが定義済みか未定義かを判定することができる．例えば，x というシンボルに何も割当てられていない状況でそれを検証する例を次に示す．
例．シンボルの使用状態を調べる>>> ’x’ in globals()Enter←シンボル ’x’ に値が定義されているかどうかを調べる．
False←未定義であることがわかる>>> x = 2Enter

←シンボル ’x’ に値を割り当てる>>> ’x’ in globals()
Enter←割当状況を再度調べる．
True←値を持つシンボルであることがわかる
関数の内部のスコープ（ローカルのスコープ）で使用されているシンボルを調べるには locals 関数を使用する．

190 グローバル変数（大域変数）など．
191 実行するシステム毎に結果が異なる．

301

4.20

with 構文

実用的なアプリケーションプログラムを開発する際には，情報処理のための主たるアルゴリズムの実装だけにとど
まらず，アクセスするシステム資源の準備処理や終了処理，あるいは例外処理といった細かい点に関する配慮が求められる．例えば，ファイルに対する入出力の処理においては，● ファイルのオープン● ファイルに対する入出力とそれに関連する例外処理（try〜except〜）のハンドリング● ファイルのクローズといったことを実行することになるが，上記強調下線部の処理は主たるアルゴリズムの実装に付随する部分と考える
ことができ，その部分を切り離して記述することで主たるプログラムの部分を簡潔に表現し，可読性を高めることができる場合がある．ここではファイルへのアクセスを例に挙げて with 構文の使用方法について説明する．
次に示すプログラム ﬁleWith01 1.py は，ファイル exﬁle.txt の内容を読み込んで表示するものである．
プログラム：ﬁleWith01 1.py
1
2
3
4
5
6
7
8

# coding : utf -8
fname = ’ exfile . txt ’
f = open ( fname , ’r ’ , encoding = ’ utf -8 ’ )m = f . read ()f . close ()print ( m )入力用のファイルとして次のような内容のものを用意してプログラムの実行を試みる．
入力用ファイル：exﬁle.txt
1

exfile . t x t の 中 身プログラムの実行結果は次のようになる．
例．Windows 環境での実行

C:￥Users￥katsu> py fileWith01 1.py
exfile.txt の中身←コマンドからスクリプトを実行

Enter

←結果表示

次に，同様の処理を実現するプログラムを with 構文で実装したものを ﬁleWith01 2.py に示す．
プログラム：ﬁleWith01 2.py
1
2
3
4
5
6
7

# coding : utf -8
fname = ’ exfile . txt ’with open ( fname , ’r ’ , encoding = ’ utf -8 ’ ) as f :m = f . read ()print ( m )【with 構文の書き方】

with 処理対象のオブジェクトを生成する記述（生成されたオブジェクトに対する処理）

as

生成されたオブジェクト

プログラム ﬁleWith01 2.py では with 構文を用いることでファイルをクローズする処理が省略されているのがわかる
が，この例では with 構文の利便性を理解するには不十分である．
次に，同様の機能を持つプログラムを例外処理までを含んだ形で実装する方法について考える．ﬁleWith01 2.py の

4 行目に，存在しないファイル ‘noﬁle.txt’ を与えた形に書き換えた ﬁleWith02 1.py を次に示す．

302

プログラム：ﬁleWith02 1.py
1
2
3
4
5
6
7

# coding : utf -8
fname = ’ nofile . txt ’# 存 在 し な い フ ァ イ ル nofile . txt

with open ( fname , ’r ’ , encoding = ’ utf -8 ’ ) as f :m = f . read ()print ( ’ 読 み 取 り 結 果 : ’ , m )このプログラムを実行すると，ファイルが存在しない旨の次のようなエラーメッセージが表示される．
例．ファイルが存在しない旨のエラー

C:￥Users￥katsu> py fileWith02 1.py

←コマンドからスクリプトを実行

Enter

Traceback (most recent call last):←エラーメッセージ
File "C:￥Users￥katsu￥fileWith02 1.py", line 4, in <module>with open( fname, ’r’, encoding=’utf-8’ ) as f:^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: ’nofile.txt’‘FileNotFoundError’ が発生しており，プログラムの 4 行目で実行が中断されている．次に，try〜except〜 構文によって例外処理をハンドリングした，プログラムの実行が中断しない形の実装について考える．

with 構文に与えるオブジェクトは，with 構文に対応したメソッドを備えていなければならない．具体的には，with
構文によって処理を開始する時点で呼び出されるる時点で呼び出される

exit

enter

メソッド（初期化処理）と，with 構文による処理を終了す

メソッド（終了処理）である．これらのメソッドを実装したクラスを定義して，そのクラスのインスタンスを with 構文で生成して使用する形にする．これを実現したプログラム例 ﬁleWith02 2.py を示す．
プログラム：ﬁleWith02 2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# coding : utf -8# - - - フ ァ イ ル を 扱 う 独 自 の ク ラ ス --class MyFileReader :# - - - コ ン ス ト ラ ク タ --def __init__ ( self , fname ):self . fn = fname
self . f = None
# - - - 開 始 処 理 --def __enter__ ( self ):try :self . f = open ( self . fn , ’r ’ , encoding = ’ utf -8 ’ )print ( ’ フ ァ イ ル ’ , self . fn , ’ を オ ー プ ン し ま し た ． ’ )except :self . f = None
print ( ’ フ ァ イ ル ’ , self . fn , ’ を オ ー プ ン で き ま せ ん ． ’ )return self
# - - - フ ァ イ ル の 読 込 み --def read ( self ):if self . f :try :r = self . f . read ()print ( ’ フ ァ イ ル か ら デ ー タ を 読 み 込 み ま し た ． ’ )except :r = Noneprint ( ’ フ ァ イ ル か ら 読 み 込 む こ と が で き ま せ ん ． ’ )else :
print ( ’ フ ァ イ ル が オ ー プ ン さ れ て い ま せ ん ． ’ )r = Nonereturn r# - - - 終 了 処 理 --def __exit__ ( self , et , ev , tr ):if self . f :self . f . close ()print ( ’ フ ァ イ ル を ク ロ ー ズ し ま し た ． ’ )else :
print ( ’ 処 理 不 可 能 で 終 了 し ま す ． ’ )return True

303

39
40
41
42
43
44
45

# - - - 実 行 部 分 --fname = ’ nofile . txt ’with MyFileReader ( fname ) as f :m = f . read ()print ( ’ 読 み 取 り 結 果 : ’ , m )解説

3 行目から定義が始まる MyFileReader クラスはファイルのオープンと読み込みに伴う例外処理をハンドリングするためのもので，コンストラクタの引数には対象のファイル名を与えてインスタンスを生成する．このクラスのオブジェクトは with 構文による処理の開始においてメソッドが実行されて対象のファイルがオープンされる．まenter

た，このクラスには read メソッドが定義されており，これによりファイルの内容が読み込まれる．with 構文が終了
する際には

exit

メソッドが呼び出されてファイルがクローズされる．

with 構文を使わない形で例外処理まで含めた処理を実現すると，ファイルをオープンする記述とクローズする記述，更に，それらに関する例外処理のハンドリング，入出力処理に関する例外処理のハンドリングの記述を主たる処理の中に散りばめることになり，プログラム全体の見通しが悪くなる．それに対して，この実装の 42 行目以降を見ると，入出力の主たる処理のみが簡潔に記述されていることがわかる．
このプログラムを実行すると次のように表示される．
例．ﬁleWith02 2.py の実行

C:￥Users￥katsu> py fileWith02 2.py

←コマンドからスクリプトを実行

Enter

ファイル nofile.txt をオープンできません．
ファイルがオープンされていません．
処理不可能で終了します．
読み取り結果: None

←例外のハンドリングによるメッセージ出力

例外事象に対してもプログラムを中断すること無く，プログラムの動作によってメッセージを表示している．また，プ
ログラムの 40 行目で入力用のファイル名として先に示したファイル ‘exﬁle.txt’ を与えて実行すると次のような表示となる．
例．入力ファイルを変えて ﬁleWith02 2.py を実行

C:￥Users￥katsu> py fileWith02 2.py

←コマンドからスクリプトを実行

Enter

ファイル exfile.txt をオープンしました．
ファイルからデータを読み込みました．
ファイルをクローズしました．
読み取り結果: exfile.txt の中身←プログラムよるメッセージ出力

ファイルのオープンと内容の読み取りができていることがわかる．今回のプログラム ﬁleWith02 2.py では， enter
メソッドと read メソッドの中で例外処理のハンドリング（try〜except〜の記述）をしている．
次に，read メソッドによる読み込み時におけるエラーハンドリングをせずにexitに例外のハンドリングを委ねる例（プログラム ﬁleWith02 3.py）について考える．
プログラム：ﬁleWith02 3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# coding : utf -8# - - - フ ァ イ ル を 扱 う 独 自 の ク ラ ス --class MyFileReader :# - - - コ ン ス ト ラ ク タ ： フ ァ イ ル オ ー プ ン --def __init__ ( self , fname ):self . fn = fname
self . f = None
# - - - 開 始 処 理 --def __enter__ ( self ):try :self . f = open ( self . fn , ’r ’ , encoding = ’ utf -8 ’ )print ( ’ フ ァ イ ル ’ , self . fn , ’ を オ ー プ ン し ま し た ． ’ )except :self . f = None
print ( ’ フ ァ イ ル ’ , self . fn , ’ を オ ー プ ン で き ま せ ん ． ’ )return self

304

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# - - - フ ァ イ ル の 読 込 み --def read ( self ):return self . f . read ()# - - - 終 了 ／ 例 外 処 理 --def __exit__ ( self , et , ev , tr ):if self . f :self . f . close ()print ( ’ 例 外 の タ イ プ : \ t ’ , et )print ( ’ 例 外 の 値 : \ t ’ , ev )print ( ’ ト レ ー ス : \ t ’ , tr )return True
# - - - 実 行 部 分 --fname = ’ nofile . txt ’with MyFileReader ( fname ) as f :m = f . read ()# 変数 mが値を持っておれば出力

if ’m ’ in globals ():print ( ’ 読 み 取 り 結 果 : ’ , m )read メソッドの呼び出しにおいて例外処理のハンドリングをしない場合，例外発生時にexit

メソッドが呼び出されて with 構文が終了する．
（次の例参照）
例．ﬁleWith02 3.py の実行

C:￥Users￥katsu> py fileWith02 3.py

ファイル nofile.txt をオープンできません．
例外のタイプ:
例外の値:
トレース:

←コマンドからスクリプトを実行Enter← enter

メソッドによる例外処理<class ’AttributeError’>← exit メソッドによる例外処理’NoneType’ object has no attribute ’read’<traceback object at 0x000001A1F6CD5348>

この実行例では，エラータイプ，エラーの値，トレース情報がexit

メソッドの引数 et,ev,tr にそれぞれ渡されている．実際のアプリケーションプログラムにおいては，これらの値を用いて更に高度な例外処理を実現すると良い．
また，例外が発生せずに正常に with 構文を終了する場合は，これらの引数には None が設定される．試みとして，

ﬁleWith02 3.py の 30 行目で，実際に存在するファイル名 ‘exfile.txt’ を与えてみるとそれが確認できる．
（次の例参照）
例．入力ファイルを変えて ﬁleWith02 3.py を実行

C:￥Users￥katsu> py fileWith02 3.py
例外のタイプ:
例外の値:
トレース:
読み取り結果:

None
None
None
exfile.txt の中身←コマンドからスクリプトを実行

Enter← None になっている← None になっている← None になっている←読み取った内容

ここでは，ファイルのオープンと内容の読み取りを例に挙げて with 構文について説明したが，通信を始めとする
例外事象の発生しやすい資源へのアクセスに関する処理においても with 構文は見やすいプログラムの実現に役立つことが多い．
【with 構文のまとめ】
次のような処理を実現する際に with 構文によってプログラムを見やすく記述することができる可能性がある．
・ 初期化と終了の処理が伴う処理
・ 例外処理が必要となる処理
また，with 構文を使用する場合は，そのためのオブジェクトのクラスを定義し，上記のような処理はクラス内に隠蔽
し，呼び出し元では意識しないように工夫する．

305

デコレータ

4.21

Python では，関数の定義を装飾するためのデコレータを使用することができる．次に示すサンプルプログラム
decorator01.py はデコレータを使用する例であり，まずはこれに沿って説明する．
プログラム：decorator01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8#--- デ コ レ ー タ の 定 義 --------------------------def dcr1 ( f ):# 関数オブジェクトを引数に取る関数# 実際に実行する関数
def retf ( a ):r = f(a)return ’<p > ’ + str ( r ) + ’ </p > ’# デコレータが返す関数オブジェクト
return retf#--- デ コ レ ー タ の 関 数 定 義 へ の 適 用 --------------@dcr1
def mul2 ( n ):# 受 け 取 っ た 数 を2 倍 す る 関 数
return 2* n
@dcr1
def pow2 ( n ):return n **2# 受 け 取 っ た 数 を2 乗 す る 関 数#--- 実 行 --------------------------------------m = mul2 (4)print ( ’ 戻 り 値 : ’ , m , ’ 型 : ’ , type ( m ) )m = pow2 (3)print ( ’ 戻 り 値 : ’ , m , ’ 型 : ’ , type ( m ) )このプログラムでは，与えられた数を 2 倍する関数 mul2 と，与えられた数の 2 乗を求める関数 pow2 が定義されている．一見するとこれら関数は，数の型（整数，浮動小数点数）の値を返すものと思われるが，このプログラムをス
クリプトとして実行すると次のような結果となる．

decorator01.py の実行結果：
戻り値:
戻り値:

<p>8</p> 型:<p>9</p> 型:<class ’str’><class ’str’>関数の戻り値は，計算結果を ‘<p> … </p>’ で括った文字列となっていることがわかる．
解説：
プログラムの 3〜9 行目に定義されている関数 dcr1 は，仮引数 f に受け取った関数オブジェクトを使用して，別の関数（内部関数 retf）を定義し，その関数オブジェクト retf を返すものである．そして，関数 mul2，pow2 の定義の直前に，アットマーク「@」を用いる形で関数 dcr1 をデコレータとして記述している．
デコレータ @dcr1 で装飾された mul2，pow2 の関数定義は，デコレータ関数の内部関数 retf によってその定義が変更される．従ってデコレータは，対象とする関数の定義に一定の変更（装飾）を加える仕組みであると言うことができる．
デコレータの存在意義：

Python のデコレータはプログラミングの概念としては本質的なものではなく，デコレータを用いなくてもアプリ
ケーション開発を十分に行うことができるが，これを用いることでプログラムの可読性を高めることができる場合がある．
【理解を深めるための別の例】
先に上げたプログラム decorator01.py と同じ働きをする別のプログラム decorator02.py を次に示す．
プログラム：decorator02.py
1
2# coding : utf -8#--- デ コ レ ー タ の 定 義 ---------------------------

306

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

def dcr1 ( f ):# 関数オブジェクトを引数に取る関数# 実際に実行する関数
def retf ( a ):r = f(a)return ’<p > ’ + str ( r ) + ’ </p > ’# デコレータが返す関数オブジェクト
return retf#--- デ コ レ ー タ の 適 用 対 象 の 関 数 ----------------def mul2 ( n ):# 受 け 取 っ た 数 を2 倍 す る 関 数
return 2* n
def pow2 ( n ):return n **2# 受 け 取 っ た 数 を2 乗 す る 関 数#--- 実 行 --------------------------------------mul2 = dcr1 ( mul2 )# デコレータ関数による定義の変更
m = mul2 (4)print ( ’ 戻 り 値 : ’ , m , ’ 型 : ’ , type ( m ) )pow2 = dcr1 ( pow2 )# デコレータ関数による定義の変更
m = pow2 (3)print ( ’ 戻 り 値 : ’ , m , ’ 型 : ’ , type ( m ) )このプログラムでは，装飾用の関数 dcr1 をデコレータとしてではなく単なる関数として使用し，関数 mul2，pow2を別の関数として再定義して（19，23 行目）いる．このプログラムを実行すると，先の decorator01.py と同じ結果となる．これら 2 つのプログラムを比較することで，デコレータの働きを確認することができる．
課題．先の decorator01.py に次のような関数定義を加え，その関数の評価結果を確認せよ．
（デコレータの入れ子）

@dcr1
@dcr1
def add1(n):return n+1

4.21.1

引数を取るデコレータ

引数を取るデコレータを定義することが可能であり，引数に受け取った値を用いて他の関数を装飾することができる．次のサンプルプログラム decorator03.py でそれを示す．
プログラム：decorator03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8#--- デ コ レ ー タ の 定 義 --------------------------------------def dcr2 ( tg ): # 引 数 を 取 る デ コ レ ー タ# 実際に実行する関数
def retf ( f ):# 関数オブジェクトを引数に取る関数
def wkf ( a ):# 実際に実行する関数
tg1 = ’<’ + tg + ’>’
tg2 = ’ </ ’ + tg + ’>’r = f(a)return tg1 + str ( r ) + tg2
return wkf# 関数オブジェクトを返す# デコレータが返す関数オブジェクト
return retf#--- デ コ レ ー タ の 関 数 定 義 へ の 適 用 --------------------------@dcr2 ( ’p ’)# 引 数 ’p ’ を 取 る デ コ レ ー タ
def mul2 ( n ):# 受 け 取 っ た 数 を2 倍 す る 関 数
return 2* n
@dcr2 ( ’ body ’)
def pow2 ( n ):return n **2# 引 数 ’ body ’ を 取 る デ コ レ ー タ# 受 け 取 っ た 数 を2 乗 す る 関 数@dcr2 ( ’ html ’)@dcr2 ( ’ body ’)# 引 数 ’ html ’ を 取 る デ コ レ ー タ# 引 数 ’ body ’ を 取 る デ コ レ ー タ

307

26
27
28
29
30
31
32
33
34
35
36
37
38

@dcr2 ( ’p ’)
def html ( s ):return s# 引 数 ’p ’ を 取 る デ コ レ ー タ# 引数をそのまま返す関数#--- 実 行 --------------------------------------------------m = mul2 (1)print ( ’ 戻 り 値 : ’ , m , ’ 型 : ’ , type ( m ) )m = pow2 (3)print ( ’ 戻 り 値 : ’ , m , ’ 型 : ’ , type ( m ) )m = html ( ’ テ キ ス ト メ ッ セ ー ジ ’ )print ( ’ 戻 り 値 : ’ , m , ’ 型 : ’ , type ( m ) )この例のように，デコレータ関数の内部関数を 2 重に構成することで，引数を取るデコレータを定義することができる．このプログラムを実行すると次のような結果となる．

decorator03.py の実行結果：
戻り値:
戻り値:
戻り値:

<p>2</p> 型: <class ’str’><body>9</body> 型: <class ’str’><html><body><p>テキストメッセージ</p></body></html> 型:<class ’str’>

解説：
デコレータ関数 dcr2 の引数はデコレータとして記述する際に与える引数である．最初の内部関数 retf は引数に関数オブジェクトを取り，これが装飾対象の関数に対応する．更に内側の内部関数 wkf は装飾された関数の呼び出しに対応するものであり，wkf の引数に与えたものが装飾対象の関数に渡される．

24〜28 行目に定義された関数 html はデコレータによる装飾が入れ子になっており，結果として HTML の形式で戻り値が得られている．

308

4.22

データ構造の整形表示：

pprint モジュール

pprint モジュールを用いると，長いデータ構造を整形表示することができる．具体的には pprint モジュールの pprint関数を使用する．
例．長いリストの表示>>> lst = [[0]*10]*5←長いリストの作成

Enter>>> print( lst )Enter← print 関数で表示する[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0,
0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
このように，長いリストを print 関数で表示するとディスプレイの右端で折り返して表示される．このような場合，

pprint モジュールの pprint 関数を使用すると次のように見やすく表示される．
例．pprint 関数による整形表示（先の例の続き）>>> from pprint import pprint← pprint モジュールから pprint 関数を読み込む

Enter>>> pprint( lst )Enter← pprint 関数で表示する[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
先の例よりも見やすくなっている．

pprint は辞書型オブジェクトも整形表示する．
例．辞書オブジェクトの整形表示（先の例の続き）>>> dic = {’apple’:’ りんご’,’orange’:’ みかん’,’lemon’:’ レモン’,’ ぶどう’:’grape’,’ 梨’:’pear’}>>> pprint( dic, width=70 )Enter←辞書オブジェクトの作成

Enter←幅を指定して整形表示{’apple’: ’ りんご’,’lemon’: ’ レモン’,’orange’: ’ みかん’,’ ぶどう’: ’grape’,’ 梨’: ’pear’}
キーワード引数 ‘width=’ には幅（表示桁数）を与え，表示対象がこの範囲に収まらない場合に辞書の各要素を 1 行ずつ表示する．

pprint の制御のための引数には様々なものがあり，詳しくは Python の公式インターネットサイトなどを参照のこ
と．

309

4.23

処理環境に関する情報の取得

1 つの Python のアプリケーションプログラムを異なる処理環境で実行する192 場合，当該アプリケーションが実行中の処理環境に関する情報を取得して，プログラムの実行方法を変えなければならないケースが出てくる．ここでは，実行中の処理環境に関する情報を取得するためのいくつかの方法を紹介する．

4.23.1

Python のバージョン情報の取得

sys モジュールを使用すると実行中の Python 処理系のバージョン情報を取得することができる．1 つの方法は，次の例に示すような version プロパティの参照である．
例．Python 処理系のバージョン情報の取得（その 1）>>> import sys← sys モジュールの読込みEnter>>> sys.version
Enter← version プロパティの参照’3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)]’↑ バージョン情報が表示されている
もう 1 つの方法は，version info プロパティの参照で，バージョンに関する各種の情報が namedtuple 193 として得られる．
（次の例を参照）
例．version info プロパティ（先の例の続き）← version info プロパティの参照

Enter>>> v = sys.version info>>> print( v )Enter← version info プロパティの表示
sys.version info(major=3, minor=11, micro=2, releaselevel=’final’, serial=0)←主バージョンのプロパティ ‘major’ の参照>>> v.majorEnter
3 ←結果表示4.23.2←結果表示

platform モジュールの利用

Python 処理系に標準で添付されている platform モジュールを利用すると，処理環境に関する詳しい情報を得ることができる．
例．OS の詳細な版を調べる platform 関数>>> import platform←モジュールの読込みEnter>>> platform.platform()Enter← platform 関数の実行←結果表示’Windows-10-10.0.22621-SP0’

platform モジュールが提供する関数の 1 部を表 39 に示す．
表 39: platform モジュールの関数の一部
関数

戻り値

platform.architecture()

アーキテクチャのビット数と実行可能ファイルのリンク形式のタプル

platform.processor()

プロセッサ名platform.platform()

プラットフォーム名

platform.system()

システム名（OS 名）．’Linux’，’Windows’，’Darwin’（macOS の場合）

platform.version()

システムのリリース情報

platform.mac ver()Apple 社の Macintosh の OS に関する情報（Windows 環境では無意味）

platform.python compiler()

Python 処理系をビルドしたコンパイラに関する情報

処理環境の各種情報を表示するプログラム例を platform01.py に示す．

192 クロスプラットフォームに対応させるという意味．
193 「4.15.3 namedtuple」（p.290）で解説している．

310

プログラム：platform01.py
1
2
3
4
5
6
7
8
9
10
11
12
13

# coding : utf -8
import platform
import sys
print ( ’ sys . version : ’ , sys . version , ’\n ’)print (’ platform . architecture ()\ t : ’ , platform . architecture ())
print ( ’ platform . processor ()\ t : ’ , platform . processor ())
print ( ’ platform . platform ()\ t : ’ , platform . platform ())
print ( ’ platform . system ()\ t : ’ , platform . system ())
print ( ’ platform . version ()\ t : ’ , platform . version ())
print ( ’ platform . mac_ver ()\ t : ’ , platform . mac_ver ())
print ( ’ platform . python_compiler (): ’ , platform . python_compiler ())

このプログラムの実行例を次に示す．
例．Windows 10 での実行例
C:￥Users￥katsu> py platform01.py
sys.version:

Enter

←実行開始

3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)]

platform.architecture() :(’64bit’, ’WindowsPE’)

platform.processor():Intel64 Family 6 Model 140 Stepping 2, GenuineIntel

platform.platform():

Windows-10-10.0.22621-SP0

platform.system():Windows

platform.version():

10.0.22621

platform.mac ver():(’’, (’’, ’’, ’’), ’’)platform.python compiler():

MSC v.1934 64 bit (AMD64)

例．macOS Catalina での実行例
Enter

katsu$ python3 platform01.py
sys.version:←実行開始

3.11.2 (v3.11.2:878ead1ac1, Feb 7 2023, 10:02:41) [Clang 13.0.0 (clang-1300.0.29.30)]

platform.architecture() :(’64bit’, ’’)platform.processor()

:

i386

platform.platform():

macOS-10.15.7-x86 64-i386-64bit

platform.system():Darwinplatform.version():

Darwin Kernel Version 19.6.0: Tue Jun 21 21:18:39 PDT 2022;
root:xnu-6153.141.66~1/RELEASE X86 64

platform.mac ver():(’10.15.7’, (’’, ’’, ’’), ’x86 64’)

platform.python compiler():

4.23.3

Clang 13.0.0 (clang-1300.0.29.30)

実行中のプログラムの PID の取得

os モジュールの getpid 関数を用いると，実行中の当該プログラムのプロセス ID（PID）194 を取得することができる．
例．実行中のプログラム（Python 処理系）の PID を調べる>>> import os

Enter>>> os.getpid()5624← os モジュールの読み込み

Enter← PID の調査←得られた PID

PID は，Python 言語処理系が起動する際に実行環境の OS が与える．
4.23.4

環境変数の参照os モジュールの environ には環境変数とその値が辞書の形で保持されている．すなわち，
os.environ[環境変数の名前]
として環境変数の値が参照できる．例えば，Windows 環境でユーザのホームドライブ，ホームディレクトリは環境変
194 正確には，スクリプトを実行している Python 言語処理系（インタプリタ）の PID．

311

数 ‘HOMEDRIVE’，‘HOMEPATH’ に保持されている195 が，この変数名をキーにして os.environ にアクセスすると値を参照することができる．
（次の例）
例．Windows 環境でユーザのホームドライブとホームディレクトリを取得する>>> import os←モジュールの読込みEnter>>> homed = os.environ[’HOMEDRIVE’]

Enter←ホームドライブを取得>>> homep = os.environ[’HOMEPATH’]Enter←ホームディレクトリのパスを取得

例．ホームドライブとホームディレクトリを確認する（先の例の続き）>>> print( homed )←ホームドライブを表示

Enter←ホームドライブC:>>> print( homep )←ホームディレクトリのパスを表示

Enter￥Users￥katsu←ホームディレクトリのパス>>> home = homed + homep>>> print( home )C:￥Users￥katsu←完全なホームディレクトリを作成

Enter←完全なホームディレクトリを表示

Enter←完全なホームディレクトリ

全ての環境変数の名前と値を表示するプログラムの例を osenv01.py に示す．
プログラム：osenv01.py
1
2
3
4
5
6
7
8
9
10

# coding : utf -8
import os# 環境変数の取得
env = list ( os . environ . keys () )env . sort ()# 変数名のリストを取得# 変数名リストを整列# 環境変数の値の表示
for e in env :print ( e , ’= ’ , os . environ [ e ] )このプログラムを実行した例を次に示す．
実行例．
C:￥Users￥katsu> py osenv01.py

Enter

←実行開始

ALLUSERSPROFILE = C:￥ProgramData
APPDATA = C:￥Users￥katsu￥AppData￥Roaming
COMMONPROGRAMFILES = C:￥Program Files￥Common Files
COMMONPROGRAMFILES(X86) = C:￥Program Files (x86)￥Common Files
COMMONPROGRAMW6432 = C:￥Program Files￥Common Files：（以下省略）：

システムやプロセスの状態を詳細に調べるためのライブラリ psutil がサードパーティによって開発，公開されている．詳しくは巻末付録「E psutil ライブラリ」（p.402）で解説する．

195 Mac，Linux ではユーザのホームディレクトリは環境変数 ‘HOME’ に保持されている．

312

ファイル，ディレクトリに対する操作： shutil モジュール

4.24

Python 処理系に標準的に添付されている shutil モジュールを使用すると，ファイルやディレクトの複製や，圧縮
ファイル，書庫ファイルの取り扱いができる．本書では shutil モジュールが提供するいくつかの基本的な機能について使用例を挙げて紹介する．shutil に関する詳しい事柄は Python の公式ドキュメント（公式インターネットサイトなど）を参照のこと．shutil を使用するには，

import shutil
としてモジュールを Python 処理系に読み込む．

4.24.1

ファイルの複製shutil の copy 関数を使用するとファイルを複製することができる．
書き方：

shutil.copy( 元のファイル, 複製ファイル )「元のファイル」には，元のファイルのファイル名（パス名）を，「複製ファイル」には複製ファイルのファイル名（パス名）を与える．
例．ファイル ’TestFile1.txt’ の複製 ’TestFile1-2.txt’ を作成する>>> import shutilEnter←モジュールの読込み>>> shutil.copy( ’TestFile1.txt’, ’TestFile1-2.txt’ )Enter’TestFile1-2.txt’←複製のファイル名が返される←複製処理当然のことではあるが，copy 関数の実行において，元のファイルが存在していなければならない．元のファイルが存在していない場合は copy 関数実行時に FileNotFoundError というエラーが発生する．
● copy 関数の第 2 引数「複製ファイル」にディレクトリ名を与えると，元のファイルがそのディレクトリの下に同じファイル名で複製される．
● copy 関数は複製時にファイルの内容に加えて，パーミッションも複製する．ただし，複製ファイルのタイム
スタンプなどの情報は copy 関数実行時のものとなる．タイムスタンプなどを含めた更に多くの管理情報を複製するには copy2 関数を使用する．

4.24.2

ディレクトリ階層の複製

shutil の copytree 関数を使用すると，ディレクトリをその内容ごと複製することができる．
書き方：

shutil.copytree( 元のディレクトリ, 複製ディレクトリ )「元のディレクトリ」には，元のディレクトリの名前（パス名）を，「複製ディレクトリ」には複製ディレクトリの名前（パス名）を与える．
例．ディレクトリ ’TestDir’ の複製 ’TestDir2’ を作成する>>> shutil.copytree( ’TestDir’, ’TestDir2’ )Enter’TestDir2’←複製のディレクトリ名が返される←複製処理

copytree の実行に先立って「複製ディレクトリ」が存在していてはならない．
「複製ディレクトリ」が存在している状態で copytree 関数を実行すると FileExistsError というエラーが発生する．

copytree 関数は，ディレクトリ内の個々のファイルの複製に copy2 関数を用いる．
4.24.3

書庫ファイル（アーカイブ）の取り扱いと圧縮処理に関すること

データの長期保存などの目的で，ファイルやフォルダに可逆的な圧縮処理196 を施すことがある197 ．また，複数の保存対象のファイルやフォルダを 1 つの書庫ファイル（アーカイブ）に纏めることがある．書庫ファイルの形式としては ZIP，tar といったものが有名であり，shutil はこれらの書庫の形式に対応している．

196 伸長した際に元と同じデータが得られる圧縮処理
197 ソフトウェアの配布などの場合においても，必要なファイル群が書庫ファイルの形式で扱われることが多い．

313

書庫（アーカイブ）の作成

4.24.3.1

make archive 関数を使用することで，指定したディレクトリの書庫（アーカイブ）を作成することができる．
書き方： shutil.make archive( 書庫名, root dir=対象ディレクトリ, format=書庫形式 )「対象ディレクトリ」の内容を纏め，「書庫名」に指定した書庫（アーカイブ）ファイルを作成する．このとき「書庫形式」に ’zip’, ’tar’, ’gztar’, ’bztar’ など198 を指定することができる．
例．ディレクトリ ’TestDir’ の ZIP アーカイブ ’TestDir.zip’ を作成する>>> shutil.make archive(’TestDir’,root dir=’TestDir’,format=’zip’) Enter ←アーカイブの作成’C:￥￥Users￥￥katsu￥￥TestDir.zip’←作成されたアーカイブファイルのパスが返される書庫（アーカイブ）の展開

4.24.3.2

unpack archive 関数を使用することで書庫ファイルを展開することができる．
書き方： shutil.unpack archive( 書庫ファイル名, extract dir=展開先ディレクトリ )「書庫ファイル名」に指定した書庫ファイルの内容を「展開先ディレクトリ」の下に展開する．
「展開先ディレクトリ」
を省略すると，カレントディレクトリに展開するので注意すること．
例．書庫ファイル ’TestDir.zip’ の内容をディレクトリ ’TestDir’ の下に展開する>>> shutil.unpack archive(’TestDir.zip’,extract dir=’TestDir’) Enter←アーカイブの展開処理の結果の値は無い．
（None となる）

shutil は他にも多くの機能を提供している．詳しくは Python の公式ドキュメントを参照のこと．
ZIP 形式書庫を扱うには，次に説明する zipﬁle モジュールを利用する方法もある．

ZIP 書庫の扱い： zipﬁle モジュール

4.25

ZIP 書庫を扱うための簡単な方法を提供する zipﬁle モジュールが Python に標準的に提供されている．このモジュールを使用するには

import zipﬁleとして Python 処理系に読み込む．

4.25.1

ZIP 書庫ファイルを開く

ZIP 書庫ファイルを開くには ZipFile を使用する．
書き方：

ZipFile( 書庫名, モード, compression=圧縮形式 )「書庫名」には書庫のファイル名（パス名）を指定する．
「モード」にはファイルオープンの際（open 関数）のモードと同じように，’w’：新規作成，’r’：既存書庫の読み込み，’a’：既存書庫への追加を指定する．
「圧縮形式」には表 40 のようなものを指定する．
表 40: 圧縮形式
形式

形式

解説

ZIP STORED

圧縮なし（デフォルト）

ZIP BZIP2

BZIP2 圧縮（要 BZ2 モジュール） ZIP LZMAZIP DEFLATED

解説

ZIP 圧縮（要 zlib モジュール）
LZMA 圧縮（要 lzma モジュール）※ 形式の先頭にモジュール名の接頭辞 ‘zipfile.’ を付けること．

ZipFile を実行すると ZipFile オブジェクトが返され，以降はこれに対してファイル（メンバ）の追加や展開，読み出しなどの処理を行う．書庫に対する処理が終われば ZipFile オブジェクトに対して close メソッドを実行して閉じておく．
以下のようなサンプルデータ（テキストファイル）を書庫に加える例を挙げて使用方法を示す．
198 ’tar’ はデータ圧縮をしない形式．’gztar’, ’bztar’ は圧縮処理にそれぞれ gzip, bzip2 を使用する．

314

ファイル：ziptest1.txt
12

ファイル：ziptest2.txt
1
2

First file :ziptest1 . txt

Second file :ziptest2 . txt

例．ZIP 書庫を新規に作成する←モジュールの読み込みEnter>>> import zipfile>>> z = zipfile.ZipFile( ’ziptest.zip’, ’w’, compression=zipfile.ZIP DEFLATED )Enter

これで書庫 ’ziptest.zip’ が新規に作成され，その ZipFile オブジェクトが z に得られる．

4.25.2

書庫へのメンバの追加書庫にメンバ（ファイル）を加えるには，当該書庫の ZipFile オブジェクトに対して write メソッドを実行する．
例．書庫にファイル ’ziptest1.txt’ を加える（先の例の続き）←メンバの追加Enter>>> z.write(’ziptest1.txt’)

このように write メソッドの引数に追加対象のファイル名を与える．このメソッドを次々と実行することで複数のメンバを追加することができる．

4.25.3

書庫の内容の確認

書庫の ZipFile オブジェクトに対して namelist メソッドを実行することで，書庫内のメンバ名のリストが得られる．
例．書庫の内容の確認（先の例の続き）>>> z.namelist()[’ziptest1.txt’]>>> z.close()

Enter

Enter

←メンバの確認←メンバが 1 つ存在している←書庫を閉じる

この例では最後に書庫を close で閉じているが，再度開いて 2 つ目のメンバを追加する例を示す．
例．既存の書庫を追加モードで開いてメンバを追加する（先の例の続き）>>> z = zipfile.ZipFile( ’ziptest.zip’, ’a’ )>>> z.write(’ziptest2.txt’)

4.25.4←既存の書庫を追加モードで開く←メンバの追加Enter←メンバの確認←メンバが 2 つ存在している>>> z.namelist()Enter[’ziptest1.txt’, ’ziptest2.txt’]>>> z.close()

Enter←書庫を閉じる

Enter

書庫のメンバの読み込み

書庫のメンバをファイルのように開いてその内容を読み込むことができる．
例．書庫のメンバの内容の読み込み（先の例の続き）>>> z = zipfile.ZipFile( ’ziptest.zip’, ’r’ )>>> f = z.open(’ziptest1.txt’)>>> b = f.read()

Enter←書庫を読み込みモードで開く←メンバをファイルのように開くEnter←メンバの内容を読み込む

Enter>>> txt = b.decode(’utf-8’)>>> print( txt )

Enter

Enter

←エンコーディングを指定してテキストに変換

←内容確認
←内容表示

First file:ziptest1.txt>>> f.close()Enter←メンバを閉じる>>> z.close()

Enter←書庫を閉じる

この例のように，書庫の ZipFile オブジェクトに対して open メソッドを実行してメンバをファイルのように開くことができる．

315

4.25.5

書庫の展開

書庫内の指定したメンバを展開する場合は extract メソッドを使用する．
書き方：

ZipFile オブジェクト.extract( 展開対象メンバ, 展開先ディレクトリ )書庫内の「展開対象メンバ」を「展開先ディレクトリ」に展開する．実行後は展開先のパスを文字列で返す．
例．メンバを 1 つ展開する（先の例の続き）>>> z = zipfile.ZipFile( ’ziptest.zip’, ’r’ )Enter←書庫を読み込みモードで開く>>> r = z.extract( ’ziptest1.txt’, ’zipext’ )Enter←メンバの展開処理>>> z.close()

Enter←書庫を閉じる

>>> r
Enter
←展開先の確認’zipext￥￥ziptest1.txt’←展開先書庫の内容を全て展開する場合は extractall メソッドを使用する．
書き方：

ZipFile オブジェクト.extractall( 展開先ディレクトリ )実行後は値を返さない．
例．書庫の内容を全て展開する（先の例の続き）>>> z = zipfile.ZipFile( ’ziptest.zip’, ’r’ )Enter>>> z.extractall( ’zipext’ )>>> z.close()
4.25.5.1

Enter

Enter

←書庫を読み込みモードで開く←書庫の内容を全て展開←書庫を閉じる

パスワードで保護された ZIP 書庫へのアクセス

パスワードで保護（暗号化）された ZIP 書庫のメンバにアクセスする場合は，そのためのメソッドにキーワード引
数 ‘pwd=パスワード’ を与える．この場合の「パスワード」はバイト列の形で与える．例えば ’password’ というパスワードで保護された ZIP 書庫にアクセスする場合は

p = ’password’.encode(’utf-8’)← UTF-8 でエンコーディングされている場合などとしてパスワードをバイト列に変換する．この例ではバイト列形式のパスワードを変数 p に得ている．これを用いて以下のような形で ZIP 書庫にアクセスする．
例．ZipFile オブジェクト z（パスワード付き）へのアクセス● メンバ aaa.txt のオープン：

f = z.open( ’aaa.txt’, pwd=p )● メンバ aaa.txt の展開：

r = z.extract( ’aaa.txt’, ’zipext’, pwd=p )● 全てのメンバの展開：

z.extractall( ’zipext’, pwd=p )【補足】
階層的ディレクトリの内容を一括して ZIP 書庫にする機能（メソッド，関数など）は zipﬁle モジュールには提供されていないので，ディレクトリの内容を列挙する処理を再帰的に行いながら順次メンバを ZIP 書庫に追加する手順を踏む必要がある．ディレクトリの内容をまとめて ZIP 書庫にするには，先に説明した shutil モジュールを使用する方が便利である．

tar 形式の書庫を扱う tarﬁle モジュールも標準的に提供されている．これに関しては Python の公式インターネット
サイトなどの情報を参照のこと．

316

4.26

コマンド引数の扱い：

argparse モジュール

Python でコマンドツールを作成する場合に，当該コマンドの起動の際に受け取る引数を解析する機能が必要となる．最も素朴な方法としては「2.6.9 コマンド引数の取得」（p.113）で解説した通り，sys モジュールの argv からコマ
ンド引数の並びを取得するという方法があるが，実用的なコマンドツールを作成するには，そのコマンドの使用方法に関する情報提示機能（ヘルプ機能）を持たせたり，ハイフン付きのコマンド引数（コマンドラインオプション）の解析や，デフォルト値の設定など，様々な機能を実現する必要がある．

Python 処理系に標準的に添付されている argparse モジュールは，Python スクリプトが起動時に受け取る引数を取り扱うための各種の高度な機能を提供する．ここでは argparse モジュールの最も初歩的な使用方法について説明する．
コマンド引数の形式

4.26.1

OS のシェルから Python スクリプトを起動する際の書式（コマンドラインの書式）としては
py

スクリプト名.py

コマンド引数の列（PSF の Windows 版 Python の場合）

あるいは，pythonスクリプト名.py（Linux，macOS 199 ，Anaconda などの場合）

コマンド引数の列という形を取る．この際の「コマンド引数の列」は空白文字（スペース）で区切られた複数の文字列である．
コマンド引数は，先頭にハイフンを 1 つ，あるいは 2 つ伴う場合があり，それらをオプション引数200 （optional

arguments）と呼ぶ．オプション引数はその名の通り省略可能なものである．例えば，多くのコマンドツールが実現している情報提示機能（ヘルプ機能）として ‘-h’（あるいは ‘–help’）オプションがあり，次のようなコマンドラインの形で使用する．

pythonスクリプト名.py-h

このような形で起動すると多くのコマンドツールは使用方法などを表示して終了する．オプション引数は通常の場合，先頭にハイフン 2 つ ‘--’ を持つ．また，その省略名は通常の場合，先頭にハイフン 1 つ ‘-’ を持つ．
オプション引数以外のコマンド引数を位置引数（positional arguments）と呼ぶ．
使用方法

4.26.2

argparse モジュールは次のようにして読み込む．
import argparse
この後，引数パーサ（Argument Parser）オブジェクトを生成する．
《引数パーサの生成》

argparse.ArgumentParser(description=’ 当該スクリプトに関する説明文’)
説明文を与える引数は省略することができる．
例．引数パーサ PRS を生成する

PRS = argparse.ArgumentParser(description=’ 当該スクリプトに関する説明文’)
引数パーサには初めに次のような処理を行う．

1) 受け付けるオプション引数や位置引数の設定：
2) コマンドラインの解析処理：

add argument メソッド

parse args メソッド

以上の処理は，作成するスクリプトの冒頭部分に記述しておく．

4.26.2.1

オプション引数の設定受け付けるオプション引数を設定するには add argument を使用する．
書き方：

引数パーサ.add argument( ’-省略名’, ’--オプション名’, help=’ 説明文’ )199 macOS では「python3」コマンドで起動することがある．
200 コマンドラインオプションと呼ぶこともある．

317

「help=’ 説明文’」は省略することができる．
例．引数パーサ PRS にオプション ‘-f（省略名）/ --first-option（オプション名）’ を設定する

PRS.add argument( ’-f’, ’--first-option’, help=’ 一番目のオプション’ )4.26.2.2

位置引数の設定

受け付ける位置引数を設定するには add argument を使用する．
書き方：

引数パーサ.add argument( ’ 引数名’, help=’ 説明文’ )「help=’ 説明文’」は省略することができる．
例．引数パーサ PRS に位置引数 ‘args’ を設定する

PRS.add argument( ’args’, help=’ 位置引数です．’ )4.26.2.3

コマンドラインの解析処理

引数パーサに各種の引数を設定した後は，parse args メソッドでコマンドラインを解析する．
例．引数パーサ PRS でコマンドラインを解析する

args = PRS.parse args()
この例では，コマンドラインの解析結果を args に得ている．parse args メソッドの戻り値は Namespace クラスのオブジェクトであり，このオブジェクトのプロパティ（オプション引数と同名）を参照することで引数の値が得られる．
例えば，先の例で設定した ‘--first-option’ オプションの値はargs.first option
として参照できる．
注意）オプション引数の名前の途中にハイフン ‘-’ を含む場合は，参照時にアンダースコア ‘ ’ になる．

4.26.3

サンプルプログラムに沿った説明

次のプログラム argparse01.py はオプション引数と位置引数を受け取り，それらの値を表示するものである．
プログラム：argparse01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# coding : utf -8
import argparse# モジュールの読み込み# 初期化
PRS = argparse . ArgumentParser (description = ’ こ れ は a r g p a r s e モ ジ ュ ー ル の テ ス ト で す ． ’)
# 使用する引数の設定
PRS . add_argument ( ’-f ’ , ’-- first - option ’ , help = ’ 一 番 目 の オ プ シ ョ ン で す ． ’ )PRS . add_argument ( ’-s ’ , ’-- second - option ’ , action = ’ store_true ’ ,help = ’ 二 番 目 の オ プ シ ョ ン で す ． ’ )PRS . add_argument ( ’a ’ , nargs = ’* ’ , help = ’ 位 置 引 数 の 並 び で す ． ’ )# 引数の解析
args = PRS . parse_args ()# 位置引数の内容確認
print ( ’a : ’ , args . a )# オプション引数の内容確認
print ( ’-- fist - option : ’ , args . first_option )print ( ’-- second - option : ’ , args . second_option )引数を与えずにこのプログラムを実行すると次のような結果となる．
実行例．py argparse01.py
a: []--fist-option: None--second-option: False

Enter←位置引数の並びは空←引数の値は None（引数なし）←引数の値は False（偽）位置引数は複数受け取ることができ，それらがリストとして得られる．プログラムの 10 行目で add argument メ
ソッドにキーワード引数 nargs=’*’ を与えているが，これは複数の位置引数を受け取ることができ，かつ全ての位置
引数が省略可能であることを設定するものである．‘nargs=’ の指定方法を表 41 に示す．

318

表 41: add argument メソッドのキーワード引数 ‘nargs=’
値

解説

’*’

複数の位置引数を受け取る．
（全て省略可能）’+’複数の位置引数を受け取る．少なくとも 1 つは引数を与える必要がある．

add argument メソッドのキーワード引数 ‘nargs=’ を省略すると，1 つの位置引数を受け取る形になる．
次に，サンプルプログラム argparse01.py にコマンド引数を与えて起動する例を示す．
実行例．py argparse01.py -f 1 -s 2 3

Enter← 2 つの位置引数が得られた←引数の値は ’1’（文字列）←引数の値は True（真）a: [’2’, ’3’]--fist-option: 1--second-option: True

オプション引数 ‘--first-option’ は直後に 1 つの値を取る．上の実行例では ’1’ が得られている．これに対して‘--second-option’ は直後の値を取らない．
（直後に続く引数は位置引数とみなされる） これはプログラムの 8 行目にあるように，add argument メソッドにキーワード引数 action=’store true’ を与えていることによるもので，この場合の引数の値は真理値（オプション引数が与えられたときに True）となる．このようなオプション引数を特にフラグ（ﬂag）と呼ぶ．

4.26.3.1

ヘルプ機能

argparse の引数パーサはヘルプ機能を備えており，‘-h / –help’ オプションがあらかじめ実装されている．
実行例．py argparse01.py -husage:

Enter

argparse01.py [-h] [-f FIRST OPTION] [-s] [a [a ...]]

これは argparse モジュールのテストです．

positional arguments:a

位置引数の並びです．

optional arguments:-h, --help

show this help message and exit-f FIRST OPTION, --first-option FIRST OPTION
一番目のオプションです．
-s, --second-option
二番目のオプションです．

このようなヘルプメッセージが自動的に生成される．
引数パーサオブジェクトに対して print help メソッドを実行することでヘルプメッセージを表示することもできる．

4.26.3.2

コマンド引数の型の指定

位置引数やオプション引数に与える値はその型を限定することができる．このことに関するサンプルプログラム

argparse02.py を示す．
プログラム：argparse02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# coding : utf -8
import argparse# モジュールの読み込み# 初期化
PRS = argparse . ArgumentParser (description = ’ こ れ は a r g p a r s e モ ジ ュ ー ル の テ ス ト で す ． ’)
# 使用する引数の設定
PRS . add_argument ( ’-s ’ , ’-- seisu ’ , type = int ,help = ’ 整 数 型 の オ プ シ ョ ン で す ． ’ ,default =0 )PRS . add_argument ( ’-m ’ , ’-- moji ’ , type = str ,help = ’ 文 字 列 型 の オ プ シ ョ ン で す ． ’ , default = ’x ’ )PRS . add_argument ( ’ word ’ , type = str ,help = ’ 文 字 列 型 の 位 置 引 数 で す ． ’ )PRS . add_argument ( ’num ’ , type = float , help = ’ f l o a t 型 の 位 置 引 数 で す ． ’ )# 引数の解析
args = PRS . parse_args ()# 位置引数の内容確認
print ( ’ word : ’ , args . word , type ( args . word ) )

319

19
20
21
22

print ( ’ num : ’ , args . num , type ( args . num ) )# オプション引数の内容確認
print ( ’-- seisu : ’ , args . seisu , type ( args . seisu ) )print ( ’-- moji : ’ , args . moji , type ( args . moji ) )

位置引数のみ与えてこのプログラムを起動した例を示す．
実行例．py argparse02.py

単語

3.1415

word: 単語 <class ’str’>
num: 3.1415 <class ’float’>--seisu: 0 <class ’int’>--moji: x <class ’str’>

Enter←引数の値は ’ 単語’（文字列型）←引数の値は 3.1415（float 型）←引数の値は 0（整数型）←引数の値は ’x’（文字列型）

このプログラムの中で add argument メソッドにキーワード引数 ‘type=型名’ を記述している．このような方法でコマンド引数に受け取る値の型を限定することができる．次の例のようにプログラムの起動時に適切でない型の値を与えるとエラーが発生し，プログラムは終了する．
実行例．py argparse02.py

単語

三. 一四

Enter

usage: argparse02.py [-h] [-s SEISU] [-m MOJI] word num
argparse02.py: error: argument num: invalid float value:’ 三. 一四’←型が適切でない旨のエラー

オプション引数は省略することができるが，その際のデフォルト値（暗黙値）を与えるには add argument メソッドにキーワード引数 ‘default=値’ を与える．

4.26.4

サブコマンドの実現方法

コマンドツールの中には，異なる複数の機能を持ち，使用する機能を起動時に選択するものがある．そのような類のコマンドツールは，起動時のコマンド引数にサブコマンドを与える形態（サブコマンドによって使用する機能を選択する）のものが多い．ここでは argparse モジュールでサブコマンドを実現する方法について説明する．
■ 基本的な手順

1) コマンドライン全体の引数パーサオブジェクトを作成する（これまで説明した通り）
2) 上記の引数パーサの下にサブコマンド毎に引数パーサを作成する（入れ子の引数パーサ）
3) サブコマンド毎の引数パーサに処理のための関数（ハンドラ）を設定する
4) 必要に応じてサブコマンド毎の引数パーサにオプション引数や位置引数を設定する
サブコマンドを実現する具体的な方法について argparse03.py を例に挙げて説明する．
プログラム：argparse03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# coding : utf -8
import argparse# モジュールの読み込み#--- 初 期 化 （ 引 数 パ ー サ の 作 成 ） - - PRS = argparse . ArgumentParser (description = ’ こ れ は サ ブ コ マ ン ド を 実 現 す る サ ン プ ル で す ． ’ )#--- サ ブ コ マ ン ド 用 の ハ ン ド ラ （ 関 数 ） - - def cmd_sub1 ():print ( ’ 関 数 cmd_sub1 が 実 行 さ れ ま し た ． ’ )def cmd_sub2 ():print ( ’ 関 数 cmd_sub2 が 実 行 さ れ ま し た ． ’ )# - - - サ ブ コ マ ン ド 毎 の 引 数 パ ー サ の 作 成 --SPRS = PRS . add_subparsers ()# これに子の引数パーサを登録する# サ ブ コ マ ン ド ： sub1
SP_sub1 = SPRS . add_parser ( ’ sub1 ’ , help = ’ こ れ は 関 数 cmd_sub1 を 起 動 し ま す ． ’ )SP_sub1 . set_defaults ( handler = cmd_sub1 )# ’ handler ’ と い う プ ロ パ テ ィ を 設 定# サ ブ コ マ ン ド ： sub2
SP_sub2 = SPRS . add_parser ( ’ sub2 ’ , help = ’ こ れ は 関 数 cmd_sub2 を 起 動 し ま す ． ’ )SP_sub2 . set_defaults ( handler = cmd_sub2 )# ’ handler ’ と い う プ ロ パ テ ィ を 設 定# - - - 引 数 の 解 析 --args = PRS . parse_args ()if hasattr ( args , ’ handler ’):args . handler ()# ’ handler ’ プ ロ パ テ ィ に 登 録 さ れ て い る 関 数 を 起 動 す る

320

25
26

else :
PRS . print_help ()# 未知のサブコマンドの場合はヘルプ表示

このプログラムはサブコマンド ‘sub1’, ‘sub2’ によって起動する関数 cmd sub1, cmd sub2 を選択するものである．サブコマンドを受け付けるための準備として 13 行目にあるように，最上位の引数パーサに対して add subparsers
メソッドを実行して ArgumentParser オブジェクト SPRS を作成している．以後はこの SPRS に対してサブコマンド用の引数パーサオブジェクトを登録する．
プログラムの 15 行目で add parser メソッドを使用してサブコマンド ‘sub1’ 用の引数パーサオブジェクト SP sub1を生成（SPRS 配下）している．また 16 行目で SP sub1 に対して set defaults メソッドを使用して起動する関数（ハンドラ）cmd sub1 を ’handler’ というプロパティに登録している．サブコマンド ‘sub1’ の場合と同様の方法で，サブコマンド ‘sub2’ のための登録処理を 18,19 行目に記述している．

24 行目で Namespace オブジェクト args の ‘handler’ プロパティを参照してハンドラを実行している．これは 16,19
行目で設定したプロパティである．
このプログラムの実行例を示す．
例．ヘルプメッセージの表示： py argparse03.py -husage:

argparse03.py [-h] {sub1,sub2} ...

これはサブコマンドを実現するサンプルです．

positional arguments:{sub1,sub2}
sub1
これは関数 cmd sub1 を起動します．
sub2
これは関数 cmd sub2 を起動します．
optional arguments:-h, --help show this help message and exit

例．サブコマンド ‘sub1’ の指定： py argparse03.py sub1
関数 cmd sub1 が実行されました．

例．サブコマンド ‘sub2’ の指定： py argparse03.py sub2
関数 cmd sub2 が実行されました．

例．登録されていないサブコマンド ‘sub3’ の指定： py argparse03.py sub3
usage: argparse03.py [-h] {sub1,sub2} ...
argparse03.py: error: argument {sub1,sub2}:

invalid choice:’sub3’ (choose from ’sub1’, ’sub2’)

ここで紹介した機能以外にも多くの機能を argparse モジュールは提供している．詳しくは Python の公式インターネットサイトなどを参照のこと．

4.27

スクリプトの終了（プログラムの終了）

4.27.1sys.exit 関数

Python スクリプト（プログラム）の実行を終了するには sys モジュールの exit を使用する．Python スクリプト中でこの関数を実行した時点で当該スクリプトの実行は終了する．
書き方：

sys.exit( 終了コード )201「終了コード」は，当該スクリプトを起動したシェル環境（コマンドウィンドウ，ターミナルウィンドウ）に通知される．
例．Windows のコマンドプロンプトウィンドウでの終了コードの確認
echo %ERRORLEVEL%
例．bash（Linux，macOS）での終了コードの確認
echo $?
201 終了ステータスとも言う．多くの場合，プログラムが正常終了する際は終了コードは 0 とする．

321

sys.exit は SystemExit 例外を起こしてプログラムを強制的に終了させる．
4.27.2os. exit 関数

先の sys.exit とは別に，Python のプロセスを強制的に終了させるものに os. exit 関数（os モジュールの exit 関数）がある．Python スクリプト中でこの関数を実行した時点で当該スクリプトの実行は終了するが，SystemExit 例外は発生しない．
書き方：

4.27.3os. exit( 終了コード )スクリプト終了時に実行する処理： atexit モジュール

atexit モジュールを利用すると，Python スクリプトが終了する時点で実行する処理を登録することができる．このモジュールは利用に先立って

import atexit
として読み込んでおく．スクリプト終了時に実行する処理は register 関数を用いて登録する．
書き方：

register( 関数名, 引数並び… )スクリプト終了時に実行する処理は関数として定義しておき，その関数名を第 1 引数の「関数名」に与え，その関数に与える引数を続けて書き並べる．
「引数並び」にはキーワード引数を与えることもできる．

register 関数は複数実行することもでき，複数の処理を登録することができる．ただしその場合は，register で登録した順序とは逆の順序で，スクリプト終了時に処理が実行される．

register 関数の使用例をサンプルプログラム atexit01.py に示す．
プログラム：atexit01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# coding : utf -8
import sys
import os
import atexit# - - - 終 了 処 理 の た め の 関 数 --def exFunc ( x , y , kw = ’ デ フ ォ ル ト メ ッ セ ー ジ ’ ):print ( ’ 終 了 処 理 : ’ + x + ’ > ’+y , ’, kw = ’+ kw )# - - - 終 了 処 理 の 登 録 --atexit . register ( exFunc , ’A ’ , ’1 番 目 に 登 録 し た 処 理 ’ )atexit . register ( exFunc , ’B ’ , ’2 番 目 に 登 録 し た 処 理 ’ , kw = ’2 番 目 に 実 行 ’ )atexit . register ( exFunc , ’C ’ , ’3 番 目 に 登 録 し た 処 理 ’ , kw = ’1 番 目 に 実 行 ’ )# - - - 主 プ ロ グ ラ ム --print ( ’ 主 プ ロ グ ラ ム か ら の 出 力 ’ )print ( ’ - - - - - - - - - - - - - - - - - - - - - - ’)# sys . exit (1)# os . _exit (1)このプログラムの実行例を次に示す．
実行例．
主プログラムからの出力---------------------終了処理:C> 3 番目に登録した処理 ,kw=1 番目に実行
終了処理:B> 2 番目に登録した処理 ,kw=2 番目に実行
終了処理:A> 1 番目に登録した処理 ,kw=デフォルトメッセージ注意）

atexit.register で登録された処理（終了時処理）は，Python スクリプトが正常に終了する際に実行される．すなわ
ち，sys.exit で終了する際にも終了時処理は実行されるが，os. exit で終了する際には実行されない．これらのことを，先のプログラム atexit01.py の 19〜20 行目のコメント記号「#」を交互に外して確認されたい．

322

4.28

Python の型システム

Python のデータ型は type 関数で調べることができる．
例．整数値 1 の型を調べる← type 関数による型の調査

Enter>>> t = type( 1 )

←内容確認
←型

>>> t
Enter
<class ’int’>

整数値の 1 の型は int であり，この型を意味するオブジェクト <class ’int’> が得られている．
ところで，この <class ’int’> もまた Python のオブジェクトであり，これの型を同様の方法で調べることができる．
（次の例）
例．<class ’int’> の型を調べる（先の例の続き）

Enter>>> t2 = type( t )← type 関数による型の調査

←内容確認
←型

>>> t2Enter<class ’type’>

型を意味するオブジェクトの型は <class ’type’> であることがわかる．

Python では型名を直接参照することもできる．
例．型名そのものを参照（先の例の続き）←「int」を参照←型を表すオブジェクト>>> int
Enter<class ’int’>←「ﬂoat」を参照←型を表すオブジェクト>>> floatEnter<class ’float’>

型を表すオブジェクト <class …> から型名を表す文字列を得るには

name

プロパティを参照する．

例．型名の取り出し（先の例の続き）>>> t. name
’int’

Enter

←型名の取り出し←型名>>> t2. name’type’

Enter←型名の取り出し←型名

4.28.1型の階層（クラス階層）

オブジェクト指向の枠組みでは，全ての型は階層的に分類されている．先の「2.8 オブジェクト指向プログラミング」（p.136）でも解説したように，クラスには継承関係（スーパークラスとそれに属するサブクラスの関係）がある
が，プログラマが作成したクラス定義のみならず，数値や文字列を始めとする組み込みのデータ型も全て 1 つのクラス階層の中に位置づけられている．

Python では全てのデータ型（クラス）は object クラスの配下に位置づけられる．このことは，クラスの継承関係を調べる issubclass 関数で確認することができる．
例．object クラス配下にクラスが位置づけられていることの確認>>> issubclass(int,object)Enter← int クラスが object クラス配下にあるか確認
True←結果（object クラス配下にある）>>> class C: Enter←クラス C の定義
...
pass
Enter
←定義（便宜上 pass とする）
...
Enter
←クラス定義の終了>>> issubclass(C,object)Enter←クラス C が object クラス配下にあるか確認
True←結果（object クラス配下にある）

323

スーパークラス，サブクラスを調べる方法

4.28.1.1

あるクラスのスーパークラスを調べるには，そのクラスのべるには，そのクラスに対して

bases

プロパティを参照する．またサブクラスを調メソッドを実行する．次の例は，int 型のスーパークラスとサブクラ

subclasses

スを調べるものである．
例．int 型のスーパークラスとサブクラスの調査>>> int. basesEnter← int のスーパークラスを参照(<class ’object’>,)←スーパークラスのタプル
Enter← int のサブクラスを調べる>>> int. subclasses ()[<class ’bool’>, <enum ’IntEnum’>, <enum ’IntFlag’>,←サブクラスのリスト<class ’sre constants. NamedIntConstant’>, <class ’subprocess.Handle’>]このように， bases

プロパティからスーパークラスのタプルが得られ， subclasses

メソッドの実行結果からサブクラスのリストが得られる．
注意）実行時の Python 処理系の状態によって出力結果が異なることがある．
【参考】subclasses
対するメソッドは対象とするクラスによって仕様が異なることがある．例えば type クラスに

subclasses

メソッドの実行結果は次のようになる．

例．type クラスに対する

subclasses

メソッド>>> type. subclasses ()Enter←空の引数で実行を試みると…
Traceback (most recent call last):←引数が不足している旨のエラー
File "<stdin>", line 1, in <module>
が発生するTypeError: unbound method type. subclasses () needs an argument>>> type. subclasses (int)Enter←引数「int」を与えて実行[<class ’bool’>, <enum ’IntEnum’>, <enum ’IntFlag’>,← int のサブクラスのリスト<class ’sre constants. NamedIntConstant’>, <class ’subprocess.Handle’>]
このように

type. subclasses (クラス)と，引数にクラスを与えると，そのクラスの配下のサブクラスのリストが得られる．これを応用すると，クラス階層
を再帰的に調べることができる．そのためのサンプルプログラム getSubclasses.py を次に示す．
プログラム：getSubclasses.py
1
2
3
4
5
6
7
8
9
10
11
12

# coding : utf -8
def k ( o ): return o . __name__# クラス名の文字列を取得する関数# クラス階層の出力
def getSubclasses ( cls , n =0):
sc = sorted ( type . __subclasses__ ( cls ) , key = k )for scls in sc :print ( ’’* n + str ( scls ))getSubclasses ( scls , n +1)#
if __name__ == ’ __main__ ’:getSubclasses ( object )このプログラムをスクリプトとして実行すると，object クラス配下の全てのサブクラスが階層的に出力される．また，Python 処理系にモジュールとして読み込み，getSubclasses 関数の引数にクラスを与えると，そのクラスの配下のサブクラスが階層的に出力される．

324

例．int 配下のサブクラスを表示（getSubclasses.py はカレントディレクトリにあるものとする）>>> from getSubclasses import getSubclasses

Enter←モジュールとして読み込む>>> getSubclasses(int)Enter← int 配下のサブクラスを出力<enum ’IntEnum’><enum ’ ParameterKind’><enum ’ Precedence’><flag ’IntFlag’><flag ’BufferFlags’><flag ’RegexFlag’><class ’re. constants. NamedIntConstant’><class ’bool’>
注意．Python の版や実行状態によってクラス階層が異なることがある．
課題．
先の例のように Python の対話モードで getSubclasses(object) として Python 処理系で定義されている全てのクラス階層を表示して眺めよ．

325

TCP/IP による通信

5

ここでは，TCP/IP による通信機能を提供するいくつかのライブラリを紹介して，それらの基本的な使用方法について説明する．

socket モジュール

5.1

TCP/IP 通信はサーバとクライアントの 2 者間の通信（右図）を基本とする．
サーバ，クライアントはそれぞれソケットを用意し，それを介して通信する．
（右下の図）
サーバとクライアントの通信

サーバはクライアントからの接続要求を受け付ける（右図の「サーバソケット」がクライアントからの接続要求を受け付ける）システムであり，通常は接続待ちの状態で待機している．それに対してクライアントからの接続が要求され，接続処理が完了すると，右図の「ソケット」を介して両者間で双方向の通信が可能となる．
（図 39）
サーバ，クライアントそれぞれにソケットを用意するD ᥋⥆๓ࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉࠉ E ᥋⥆ᚋ
図 39: ソケットを介した接続
このような通信を実現するために Python には socket モジュールが用意されている．socket モジュールは次のようにして読み込む．

import socket
5.1.1

ソケットの用意

ソケットは socket コンストラクタで生成する．
書き方：

socket.socket(socket.AF INET, socket.SOCK STREAM)

この処理が正常に終了すると，ソケットオブジェクトが生成されて返される．ソケットを用意する方法はサーバ，ク
ライアントの両方において同じである．

5.1.2

サーバ側プログラムの処理

サーバ側ソケットにはソケットオプション202 を設定する．これには次のように setsockopt メソッドを用いる．
書き方：

ソケットオブジェクト.setsockopt(socket.SOL SOCKET, socket.SO REUSEADDR, 1)

次に，ソケットを IP アドレスとポートにバインドする．これには次のようにして bind メソッドを用いる．
書き方：

ソケットオブジェクト.bind((ホストアドレス, ポート))「ホストアドレス」には当該計算機環境の NIC の IP アドレスを文字列で与える．この部分に ’0.0.0.0’ を与えると，当該計算機環境の全ての NIC が対象となる．
202 詳しい説明は TCP/IP の関連書籍や技術資料に譲る．

326

ここまででサーバ側のソケット（p.326 の図の「サーバソケット」）の準備がほぼ終わる．後は listen メソッドを使用してクライアントからの受信の準備をする．
（下記参照）
書き方：

ソケットオブジェクト.listen()listen メソッドの引数にはバックログの値を与えることができる．これは，サーバのソケットが保持できる接続の待ち行列の長さで，デフォルトで socket.SOMAXCONN の値が与えられている．
実際にクライアントからの接続要求を受信するには，次のように accept メソッドを使用する．
書き方：

ソケットオブジェクト.accept()

この処理が完了すると，相手システム（クライアント）と通信するための新たなソケットオブジェクト（p.326 の図の「ソケット」）とアドレスのタプルが返される．ここで言うアドレスとは，クライアント側の IP アドレスとポート
番号のタプルである．
サーバ側プログラムは，複数のクライアントからの接続要求を受け付けることができ，異なるクライアントから

accept する度に，それぞれに対応するソケットオブジェクトが生成される．
5.1.3

クライアント側プログラムの処理

クライアント側では，生成したソケットに対して次のように connect メソッドを用いてサーバに接続を要求する．
（その前にタイムアウトを設定しておく方が良い）
書き方： ソケットオブジェクト.settimeout(秒数)
書き方： ソケットオブジェクト.connect( (ホストアドレス, ポート番号) )「ホストアドレス」に
connect メソッドの引数には，サーバの「ホストアドレス」と「ポート番号」のタプルを与える．
は IP アドレスもしくは FQDN を文字列で与える．
「ポート番号」は整数値で与える．

5.1.4

送信と受信

（下記参照）
ソケットを介して相手システムにメッセージを送信するには send メソッドを使用する．
書き方：

ソケットオブジェクト.send(データ)送信する「データ」はバイトデータ（bytes 型）で与える．相手システムからのメッセージを受信するには，recv メ
ソッドを使用する．
（下記参照）
書き方：

ソケットオブジェクト.recv(バッファサイズ203 )recv メソッドの処理が正常に終わると，受信したメッセージがバイトデータ（bytes 型）として返される．
通信が終了すると，次のように close メソッドを使用してソケットを閉じておく．
書き方：

5.1.5

ソケットオブジェクト.close()

サンプルプログラム：最も基本的な通信

ここでは，サーバプログラムとクライアントプログラムが相互に接続してメッセージを交換するプログラムを示す．
サーバプログラム：test13-sv.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# coding : utf -8
import socket# 通信先（サーバ）の情報
host = ’127.0.0.1 ’
port = 8001
# サービスの準備
sSock = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )sSock . setsockopt ( socket . SOL_SOCKET , socket . SO_REUSEADDR , 1)
sSock . bind (( host , port ))sSock . listen ()# 接続の受け付け

203 通常は 4096 にする．

327

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

print ( ’ Waiting for connection ... ’)( cSock , cAddr ) = sSock . accept ()print ( ’ Connection accepted !: ’, cAddr )# クライアントから受信
r = cSock . recv (4096)
print ( ’ ク ラ イ ア ン ト か ら > ’,r . decode ( ’ utf -8 ’) )# クライアントへ送信
msg = ’ は い ， 届 い て い ま す よ ． ’ . encode ( ’ utf -8 ’)cSock . send ( msg )# ソケットを終了する
cSock . close ()sSock . close ()クライアントプログラム：test13-cl.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# coding : utf -8
import socket# 通信先（サーバ）の情報
host = ’127.0.0.1 ’
port = 8001
# 接続処理cSock = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )cSock . settimeout (3.0)
print ( ’ Connecting ... ’)cSock . connect (( host , port ))print ( ’ Connection accepted ! ’)# サーバへ送信
msg = ’ 受 信 で き て い ま す か ？ ’ . encode ( ’ utf -8 ’)cSock . send ( msg )# サーバから受信
r = cSock . recv (4096)
print ( ’ サ ー バ か ら > ’,r . decode ( ’ utf -8 ’) )# ソケットを終了する
cSock . close ()先にサーバプログラムを起動しておき，次にクライアントプログラムを起動すると両者が接続される．接続が確立されると，クライアント側からサーバ側に対して「受信できていますか？」と送信される．サーバ側はこれを受信して標準出力に出力した後，クライアント側に対して「はい，届いていますよ．
」と送信する．クライアント側はこれを受信して標準出力に出力する．実行例を次に示す．
サーバ側の実行例：
Waiting for connection...
Connection accepted!: (’127.0.0.1’, 55735)
クライアントから> 受信できていますか？

クライアント側の実行例：
Connecting...
Connection accepted!
サーバから> はい，届いていますよ．

ここに示したサンプルは，クライアント側が一度だけメッセージをサーバに送信し，それを受けたサーバ側が一度だけクライアントにメッセージを送信して終了するものである．実用的な通信においては，クライアントとサーバがデータのやり取りを複数回繰り返すだけでなく，1 つのサーバが複数のクライアントからの接続要求を受け付け，各クライアントとの通信を個別に実行する．次に，実用的な通信処理のための具体的な方法について解説する．

328

実用的な通信機能を実現する方法

5.1.6

実用的なサーバ-クライアント通信においては，1 つのサーバが複数のクライアントからの接続要求を同時に受け付け，個々のクライアントを識別して通信を行う．また，通信処理には待ち時間が発生することが一般的である．このように，待ち時間が発生する複数の処理を並行して実行するには非同期処理の形態で通信システムを構築するのが一般的である．

5.1.6.1

socket ライブラリと asyncio ライブラリの併用

ここでは，先の「4.5 非同期処理：asyncio」（p.248）で解説した非同期処理を応用して通信システムを構築する方法について解説する．
■ サーバがクライアントからの接続要求を受け付ける処理

socket ライブラリでは，サーバのソケットオブジェクトに対して accept メソッドを実行することでクライアントからの接続要求を受け付ける．これと同様の処理を asyncio のイベントループ上で非同期に行うことができる．具体的には，イベントループオブジェクトに対して sock accept メソッドを実行する．
書き方：

await イベントループオブジェクト.sock accept( サーバソケット )「サーバソケット」による接続要求の受け付けを「イベントループオブジェクト」で非同期に実行する．接続要求を受け付けるとクライアントのソケットとアドレスのタプルを返す．この場合のアドレスは，クライアント側の IP アドレ
スとポート番号のタプルを意味する．戻り値に関しては socket ライブラリの accept メソッド（p.327）に準じている．
■ 相手が送信したデータを受信する処理

socket ライブラリでは，クライアントのソケットオブジェクトに対して recv メソッドを実行することで，相手が送信したデータを受信する．これと同様の処理を asyncio のイベントループ上で非同期に行うことができる．具体的には，イベントループオブジェクトに対して sock recv メソッドを実行する．
書き方：

await イベントループオブジェクト.sock recv( クライアントソケット, バッファサイズ )「クライアントソケット」からのデータの受信を「イベントループオブジェクト」で非同期に実行する．このとき受信用の「バッファサイズ」を整数値で指定する．受信したデータはバイト列（bytes 型）で返される．
相手システムが「バッファサイズ」以下の大きさのデータを送信した場合は，sock recv メソッドの結果はそのデー
タ全体となり，「バッファサイズ」よりも大きなデータを送信した場合は，最初の「バッファサイズ」の部分だけを返し，残りは受信バッファに残される．受信バッファに残されたデータは次回の sock recv メソッドの実行時に読み取られる．受信バッファの残部が更に「バッファサイズ」より大きい場合は，次回の sock recv メソッドの実行において，残部のデータの先頭の「バッファサイズ」の大きさの部分が得られ，その残部が受信バッファに残される．
（以下同様）
相手システムが接続を終了すると，自システム側の sock recv メソッドは空のバイト列 b’’ を返す．これを応用することで，相手システムの終了を検知することができる．
■ 相手にデータを送信する処理

socket ライブラリでは，クライアントのソケットオブジェクトに対して send メソッドを実行することで，相手にデータを送信する．これと同様の処理を asyncio のイベントループ上で非同期に行うことができる．具体的には，イベントループオブジェクトに対して sock sendall メソッドを実行する．
書き方：

await イベントループオブジェクト.sock sendall( クライアントソケット, データ )「クライアントソケット」を通じて相手に「データ」を送信する処理を，「イベントループオブジェクト」で非同期に実行する．
「データ」はバイト列（bytes 型）で与える．
クライアントとサーバは互いに recv，sendall メソッドを用いて送受信を繰り返す．一連の通信を終了するにはクライアントソケットに対して close メソッドを実行する．
書き方：

クライアントソケット.close()■ クライアントがサーバに対して接続要求する処理

socket ライブラリでは，クライアントのソケットオブジェクトに対して connect メソッドを実行することで，サーバに対して接続要求をする．これと同様の処理を asyncio のイベントループ上で非同期に行うことができる．具体的

329

には，イベントループオブジェクトに対して sock connect メソッドを実行する．
書き方：

await イベントループオブジェクト.sock connect(
クライアントソケット, (IP アドレス, ポート番号) )クライアントが「クライアントソケット」を用いて，「IP アドレス」，「ポート番号」で指定したサーバに接続要求する．
またこの処理は「イベントループオブジェクト」で非同期に実行される．
「IP アドレス」は文字列として記述する．またこの部分にサーバの FQDN を記述しても良い．
【サンプルプログラム】

socket ライブラリ，asyncio ライブラリを併用して通信を実現した例を asyncSocketSv01.py （サーバ）， asyncSocketCl01.py（クライアント）に示す．
サーバプログラム：asyncSocketSv01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# coding : utf -8
import asyncio
import socket# 個別のクライアントとの通信
async def handleCl ( cSoc , addr ):loop = asyncio . get_running_loop ()# 現行のイベントループを取得
while True :# クライアントとの通信実行する処理
req = await loop . sock_recv ( cSoc , 1024 )# クライアントから受信
msg = req . decode ( ’ utf -8 ’)print (f ’{ addr }: { msg } ’)r = b ’[ echo ] ’+ req
await loop . sock_sendall ( cSoc , r ) # ク ラ イ ア ン ト へ 送 信
if msg == ’end ’: break# クライアントからの終了指示を受けた場合
cSoc . shutdown ( socket . SHUT_RDWR )# ソケットの終了
cSoc . close ()# ソケットを閉じる# サーバの作成と起動
async def sv ():# サーバを作成し，初期設定して起動
sSoc = socket . socket ( socket . AF_INET , socket . SOCK_S TREAM )sSoc . setsockopt ( socket . SOL_SOCKET , socket . SO_REUSEADDR , 1)
sSoc . bind (( ’0.0.0.0 ’ , 8000))sSoc . listen (5)sSoc . setblocking ( False )# 今回は必須ではない# 複数のクライアントからの接続要求に応える処理
loop = asyncio . get_running_loop ()# 現行のイベントループを取得
while True :cSoc , addr = await loop . sock_accept ( sSoc )# 接続要求の受け入れ
print (f ’ Connection from { addr } ’)loop . create_task ( handleCl ( cSoc , addr ))# 当該クライアントとの通信処理
asyncio . run ( sv () ) # サ ー バ の タ ス ク を イ ベ ン ト ル ー プ に 投 入 し て 実 行

クライアントプログラム：asyncSocketCl01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# coding : utf -8
import asyncio
import socket# クライアント用コルーチン
async def client ():loop = asyncio . get_running_loop ()# 現行のイベントループの取得
cSoc = socket . socket ( socket . AF_INET , socket . SOCK_S TREAM )# ソケットの作成
await loop . sock_connect ( cSoc , ( ’127.0.0.1 ’ , 8000) )# サーバに接続要求
while True :# メッセージを入力して送信する処理
msg = input ( ’ 終 了 : end > ’). rstrip ()await loop . sock_sendall ( cSoc , msg . encode ( ’ utf -8 ’) ) # サ ー バ に デ ー タ 送 信
res = await loop . sock_recv ( cSoc , 1024 ) # 直 後 に サ ー バ か ら の デ ー タ を 受 信
print ( f " Received : { res . decode ( ’ utf -8 ’)}")# 入 力 さ れ た デ ー タ が end な ら w h i l e を 終 了
if msg == ’end ’: breakcSoc . shutdown ( socket . SHUT_RDWR )# ソケットを終了
cSoc . close ()# ソケットを閉じる
asyncio . run ( client () )# クライアントのタスクをイベントループに投入して実行

330

クライアントプログラム asyncSocketCl01.py では，同じ計算機で実行されてるサーバに対して

await loop.sock connect( cSoc, (’127.0.0.1’, 8000) )で接続した後は，コンソールから入力された文字列をバイト列に変換してサーバに送信する処理を繰り返す．このとき，’end’ を入力するとクライアントプログラムが終了する．また，それを受けたサーバは接続を終了する．
サーバプログラム asyncSocketSv01.py では，コルーチン sv() 内でサーバソケットを生成してクライアントからの接続要求を受け付ける．この処理は while ループで繰り返され，複数のクライアントからの接続要求を次々と受け付ける．各クライアントから要求に応えるのはコルーチン handleCl で，この中の while ループによってクライアントから次々と送られてくるデータを処理している．この場合の処理は，受信したデータをクライアントにエコーバックするというものである．また，’end’ を受信するとクライアントソケットを閉じて handleCl のタスクを終了する．handleClのタスクは複数のクライアントからの要求に応じて個別に起動し，イベントループ上で非同期に実行される．
ここに示したサンプルでは，サーバ，クライアント共に，クライアントソケット cSoc を閉じる前に

cSoc.shutdown(socket.SHUT RDWR)
として終了させており，より安全な形で接続を閉じている．
上のプログラムを実行するには，先にサーバプログラムを起動し，次にクライアントプログラムを起動する．サー
バプログラムの起動直後はコンソールには何も出力されないが，クライアントが同じ計算機の別のコンソールで起動した際に←クライアント側のポート番号は実行時に適宜設定されるConnection from (’127.0.0.1’, 57961)などと出力される．クライアント側のコンソールには「終了:end>」というプロンプトが表示され，ユーザに対して文字の入力を促す．これに対して，例えば「こんにちは．
」と入力して「Enter」を押すとそれがサーバに送信され，サーバ側のコンソールに(’127.0.0.1’, 57961):

こんにちは．

などと出力される．また直後に，この内容がクライアントにエコーバックされ，クライアント側のコンソールにReceived:[echo] こんにちは．

と出力される．このような入力→送信→エコーバックのサイクルはクライアント側で ’end’ と入力するまで繰り返される．
上のサーバプログラムを終了するには，コンソールから CTRL + C とキーボード操作を行う．今回はサーバ側に例外処理を実装していないので，サーバ終了時にエラーメッセージが表示される．
上のクライアントプログラムは，サーバと同じ計算機環境で複数起動することが可能で，各クライアントからの通信を 1 つのサーバが同時に対応する．
（試されたい）5.1.6.2

asyncio ライブラリのみで通信を実現する方法

asyncio ライブラリはその内部で socket ライブラリを使用して TCP/IP 通信のための機能を実現している．またasyncio では，イベントループ上で通信の処理を完結させることができるように API が設計されており，socket ライ
ブラリを明に意識せずに通信処理を実現することができる．
■ サーバオブジェクトの生成

asyncio ライブラリでは独自にサーバクラス（Server クラス）を実装しており，このクラスのインスタンスを用いてサーバを実現することができる．サーバのインスタンスは start server 関数（コルーチン）で作成する．
書き方：

await asyncio.start server( ハンドラ関数, IP アドレス, ポート番号 )当該計算機で通信を受け付ける NIC の「IP アドレス」を文字列で指定し，「ポート番号」を整数値で指定する．
「IP ア
ドレス」に ’0.0.0.0’ を指定すると，当該計算機の全ての NIC が対象となる．
クライアントとの具体的な通信処理は，指定した「ハンドラ関数」（後述）で行う．start server 関数は生成したサーバのインスタンス（Server オブジェクト）を返す．
■ サーバオブジェクトの起動と停止

Server オブジェクトに対して serve forever メソッドを非同期に実行することで，イベントループ上でサーバが起動
する．

331

書き方：

await Server オブジェクト.serve forever()また，close メソッドでそれを停止することができる．ただし close メソッドは同期処理であり，その処理の終了を

wait closed メソッドで非同期に待機すること．
書き方：

Server オブジェクト.close()await Server オブジェクト.wait closed()■ ハンドラ関数
接続要求を受け付けたクライアントとの具体的な通信処理は，start server 関数に指定したハンドラ関数で行う．この関数は 2 つの引数を取るコルーチンとして定義する．
書き方：

async 関数名 ( リーダ, ライタ ):（応答処理）

この関数はクライアントからの接続要求に対して呼び出され，その際に自動的に引数が渡される．
「リーダ」は Stream-

Reader クラスのオブジェクトで，クライアントが送信したデータの受信処理を司る．また「ライタ」は StreamWriter
クラスのオブジェクトで，クライアントに対する応答の送信処理を司る．
■ StreamReader オブジェクトによるデータの受信
非同期の read メソッドによって，相手システムからのデータを受信することができる．
書き方：

await リーダ.read( データ長 )StreamReader オブジェクトの「リーダ」から「データ長」（バイト単位）のサイズのデータを読み取る．この処理は非同期に実行され，受信完了を待機する．read メソッドは読み取ったデータをバイト列（bytes 型）として返す．
相手システムが「データ長」よりも小さなデータを送信した場合は，read メソッドの結果はそのデータ全体となり，「データ長」よりも大きなデータを送信した場合は，最初の「データ長」の部分だけを返し，残りは受信バッファに残される．受信バッファに残されたデータは次回の read メソッドの実行時に読み取られる．受信バッファの残部が更に「データ長」より大きい場合は，次回の read メソッドの実行において，残部のデータの先頭の「データ長」の大きさの部分が得られ，その残部が受信バッファに残される．
（以下同様）
相手システムが接続を終了すると，自システム側の read メソッドは空のバイト列 b’’ を返す．これを応用すると，
相手システム側の終了を検知することができる．
■ StreamWriter オブジェクトによるデータの送信

write メソッドによって，相手システムにデータを送信することができる．
書き方：

ライタ.write( データ )StreamWriter オブジェクトの「ライタ」を介して相手システムに「データ」（bytes 型）を送信する．write メソッド
は同期処理であり，この直後に，非同期の drain メソッドで送信完了を待機する．
書き方：

await ライタ.drain()

クライアントとサーバは互いに read，write メソッドを用いて送受信を繰り返す．一連の通信を終了するにはライタに対して close メソッドを実行する．
書き方：

ライタ.close()

この処理は同期処理であり，終了処理の完了を非同期の wait closed メソッドで待機する．
書き方：

await ライタ.wait closed()■ クライアント側でのサーバへの接続要求
非同期の open connection 関数で，サーバに対して接続要求ができる．
書き方：

await asyncio.open connection( ホスト名, ポート番号 )「ホスト名」，「ポート番号」のサーバに接続要求する．接続が確立すると StreamReader オブジェクト（リーダ）とStreamWriter オブジェクト（ライタ）のタプルが返される．
「ホスト名」にはサーバの IP アドレスもしくは FQDN の文字列を与える．
「ポート番号」は整数値で与える．
データの送信と受信の処理は，サーバ側の場合と同様に，リーダに対する read メソッド，ライタに対する write メ332

ソッドで行う．クライアント側での通信の終了の処理もサーバの場合と同様である．
■ 相手システム，自システムに関する情報の取得
ライタ（StreamWriter オブジェクト）に対して get extra info メソッドを実行することで，相手システムや自システムに関する情報を取得することができる．
書き方：

ライタ.get extra info( ’peername’ )相手システムのホスト名（あるいは IP アドレス）とポート番号のタプルを返す．get extra info の引数に ’sockname’を与えると，自システムの IP アドレスとポート番号のタプルを返す．
【サンプルプログラム】

asyncio ライブラリのみ使用する形で通信を実現した例を asyncSocketSv02.py （サーバ）， asyncSocketCl02.py（クライアント）に示す．
サーバプログラム：asyncSocketSv02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# coding : utf -8
import asyncio# 個別のクライアントとの通信（ハンドラ関数）
async def handleCl ( rd , wt ):# リ ー ダ ( rd ) と ラ イ タ ( wt ) が シ ス テ ム か ら 与 え ら れ る ．
addr = wt . get_extra_info ( ’ peername ’)# クライアント情報の取得
print (f ’ Connection from { addr } ’)while True :# クライアントとの応答サイクル
dt = await rd . read (1024)# クライアントからのデータ受信を非同期に待機
if not dt :# クライアント側から通信終了を検出すると，
break# 応答サイクルを終了する．
msg = dt . decode ( ’ utf -8 ’)print ( f "{ addr }: { msg }")res = f "[ echo ] { msg }". encode ( ’ utf -8 ’)
wt . write ( res )# クライアントへデータ送信（同期処理）
await wt . drain ()# 送信処理の完了を非同期に待機する．
if msg . strip () == ’end ’:# ク ラ ア ン ト か ら の デ ー タ が ’ end ’ な ら ，break# 応答サイクルを終了する．
wt . close ()# 接続の終了処理（同期処理）
await wt . wait_closed ()# 接続終了を非同期に待機する．
# サーバの作成と起動
async def exe ():# サーバインスタンスの生成
sv = await asyncio . start_server ( handleCl , ’127.0.0.1 ’ , 8000)
try :await sv . serve_forever ()# サーバをイベントループ上で起動（永続稼働）
except asyncio . CancelledError : # 強 制 終 了 な ど の 検 知
print ( ’ サ ー バ 終 了 ’ )# 終了メッセージ
finally :# サーバ終了時の処理
sv . close ()# サーバを閉じる処理（同期処理）
await sv . wait_closed ()# その処理の完了を非同期に待機する．
asyncio . run ( exe () )# サ ー バ の 起動-終 了 の タ ス ク を イ ベ ン ト ル ー プ に 投 入

クライアントプログラム：asyncSocketCl02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8
import asyncio# クライアント用コルーチン
async def client ():# サーバに接続要求し，リーダとライタを取得
rd , wt = await asyncio . open_connection ( ’127.0.0.1 ’ , 8000)
while True :# サーバへのデータ送信と応答受信のサイクル
msg = input ( ’ 終 了 : end > ’). rstrip () # コ ン ソ ー ル 入 力 の 受 付 け
wt . write ( msg . encode ( ’ utf -8 ’) )# サーバにデータ送信（同期処理）
await wt . drain ()# データの送信完了を非同期に待機
dt = await rd . read (1024)# サーバからの応答受信を非同期に待機
print ( f " Received : { dt . decode ( ’ utf -8 ’)}")
if msg == ’end ’:# コ ン ソ ー ル 入 力 が ’ end ’ な ら ，break# サ ー バ と の 受信-送 信 サ イ ク ル を 終 了

333

16
17
18
19

wt . close ()await wt . wait_closed ()asyncio . run ( client () )# 接続終了の処理（同期処理）# 接続終了処理を非同期に待機# クライアントのタスクをイベントループに投入

これらは先の asyncSocketSv01.py，asyncSocketCl01.py と同様の通信処理を実現するものであるが，サーバ側の停止処理を例外処理の形で実装している．このため，サーバを CTRL + C で終了するとエラーメッセージを出力せずに「サーバ終了」と出力する．

5.1.6.3

通信の処理において注意すべき例外今回挙げたサンプルプログラムは，基本的な機能の解説を目的として作られているので，例外処理なども十分ではない．特に通信の処理においては様々な例外が発生する可能性があるので，適切に例外処理を実装することが重要である．
通信処理の実装の際に注意すべき例外として基本的なものを表 42 に挙げる．
表 42: 通信の処理で発生する例外（一部）
例

外

解説

ConnectionRefusedError

サーバに接続できなかった場合に発生する．サーバが起動していないことやネットワークの問題が原因である．

TimeoutError

接続やデータの送受信がタイムアウトした場合に発生する．ネットワークの遅延やサーバの応答が遅い場合に発生することがある．

ConnectionResetError

接続がリセットされた場合に発生する．これは，リモートホストが接続を強制的に終了した場合に発生する．

BrokenPipeError

データの送信中に接続が切断された場合に発生する．これは，リモートホスト
が接続を閉じた後にデータを送信しようとした場合に発生する．

asyncio.CancelledError

非同期タスクがキャンセルされた場合に発生する．タスクのキャンセル後のリソースの解放といった適切な後処理のためにこのハンドリングが必要である．

OSError

一般的な入出力エラー．ネットワークの問題やファイルシステムのエラーなど，
様々な原因で発生する．

334

WWW コンテンツ解析

5.2

WWW は TCP/IP 通信の基礎の上に成り立っているサービスであり，Python と各種のライブラリを使用すること
で，WWW サーバへのリクエストの送信，コンテンツの取得，コンテンツの解析などが実現できる．ここでは，WWW
コンテンツの取得と解析204 に関する基礎的な事柄について説明する．

requests ライブラリ

5.2.1

requests ライブラリは WWW サーバに対して各種のリクエストを送信したり，WWW サーバからコンテンツを取得するための基本的な機能を提供する．このライブラリはインターネットサイト http://docs.python-requests.org/ から入手できる．利用に先立って Python システム用にインストールしておく必要があるので，ソフトウェア管理ツー
ル205 を使用してインストールする．requests ライブラリを Python で使用するには次のようにして読み込む．

import requests
5.2.1.1

リクエストの送信に関するメソッド■ コンテンツの取得（GET リクエストの送信）

URL を指定してコンテンツを取得するには get メソッドを使用する．
書き方：

r = requests.get(コンテンツの URL)

BASIC 認証を行ってコンテンツを取得するには次のようにする．
書き方：

r = requests.get(コンテンツの URL, auth=(ユーザ名, パスワード))■ フォームの送信（POST リクエストの送信）
フォームの内容206 を WWW サーバに送信するには post メソッドを使用する．ことのきフォームの項目の「名前」と「値」の対応を Python の辞書型オブジェクト207 にして与える．
書き方：

requests.post(コンテンツの URL, 辞書型オブジェクト)

これら各メソッドが返すオブジェクトにリクエスト結果の情報が保持されている．

5.2.1.2

取得したコンテンツに関するメソッド

WWW サーバにリクエストを送信すると，それに対するサーバからの応答が返され，それら情報がメソッドの戻り値となる．以後これを応答オブジェクトと呼ぶ．
例．ウィキペディアサイトの Python に関する記事の取得

import requests
r = requests.get(’https://ja.wikipedia.org/wiki/Python’)
この結果，r にサーバからの応答（WWW コンテンツを含む）が応答オブジェクトとして得られる．次に紹介する各種のメソッドを使用することで，取得した応答オブジェクトから様々な情報を取り出すことができる．
■ 取得したコンテンツ全体

WWW サーバから送られてきたコンテンツ全体は応答オブジェクトの text プロパティに保持されている．すなわ
ち，
応答オブジェクト.textとすることでコンテンツ全体を取得できる．先の例で得られた応答オブジェクトの text プロパティを表示すると次のようになる．

204 これら一連の処理はウェブスクレイピングと呼ばれている．
205 PSF 版 Python での導入方法に関しては，巻末付録「A.4 PIP によるライブラリ管理」（p.363）を参照のこと．Anaconda の場合はAnaconda Navigator でパッケージ管理を行う．
206 ＜ FORM ＞... ＜/FORM ＞で記述された HTML コンテンツ．
207 INPUT タグの ’NAME=’ と ’VALUE=’ に指定するものを辞書型オブジェクトにする．

335

例．r.text の表示（先の例の続き）<!DOCTYPE html><html class="client-nojs" lang="ja" dir="ltr"><head><meta charset="UTF-8"/><title>Python - Wikipedia</title><script>document.documentElement.className = document.documentElement.className.
replace( /(＾|￥s)client-nojs(￥s|＄)/, "＄1client-js＄2" );</script><script>(window.RLQ=window.RLQ||[]).push(function()mw.config.
set("wgCanonicalNamespace":"","wgCanonicalSpecialPageName":false,：（以下省略）：■ 応答のステータスの取得
応答オブジェクトの status code プロパティには，リクエスト送信に対する WWW サーバからの応答が保持されている．
例．r.status code の表示（先の例の続き）

200■ エンコーディング情報の取得
応答オブジェクトの encoding プロパティには，得られたコンテンツのエンコーディングに関する情報が保持されている．
例．r.encoding の表示（先の例の続き）

UTF-8■ ヘッダー情報の取得
応答オブジェクトの headers プロパティには，得られたコンテンツのヘッダー情報（Python の辞書型オブジェクト）が保持されている．
例．r.headers の内容（先の例の続き）{’Date’:’Tue, 09 May 2017 06:22:40 GMT’,’Content-Type’:’’text/html; charset=UTF-8’,’Content-Length’:’46335’.
’Connection’:’keep-alive’,’Server’:’mw1264.eqiad.wmnet’,：（途中省略）：’Cache-Control’:’private, s-maxage=0, max-age=0, must-revalidate’,’Accept-Ranges’:’bytes’}■ Cookie 情報の取得
応答オブジェクトの cookies プロパティには，得られたコンテンツの Cookie 情報（RequestsCookieJar 型オブジェ
クト208 ）が保持されている．

5.2.1.3

Session オブジェクトに基づくアクセス

WWW サーバとの間で情報をやり取りする際のセッション情報は，Session オブジェクトとして扱うことができ，
Session オブジェクトに対してコンテンツの取得といったメソッドが使用できる．
例．Session オブジェクトに基づく処理>>> import requests

Enter>>> s = requests.Session()←ライブラリの読込み

Enter← Session オブジェクトの生成>>> r = s.get(’https://ja.wikipedia.org/wiki/Python’)Enter←コンテンツの取得

この例は Session オブジェクトに基づいてコンテンツの取得を行うものであり，処理の結果として応答オブジェクト rが得られている．
208 本書では解説を割愛する．

336

本書での requests ライブラリに関する解説は以上で終わるが，より多くの情報が配布元サイトや有志の開発者たちによって配信されているのでそれらを参照すること．

requests ライブラリは WWW サーバとの通信における基本的な機能を提供するが，取得した WWW コンテンツの解析といったより高度な処理を行うには，更に別のライブラリを使用した方が良い．次に紹介するライブラリは，取得した WWW コンテンツ（より一般的に XML コンテンツ）の解析や，あるいはコンテンツの構築自体を可能とするものである．

Beautiful Soup ライブラリ

5.2.2

Beautiful Soup は HTML を含む XML 文書の解析や構築を可能とするライブラリであり
https://www.crummy.com/software/BeautifulSoup/から入手することができるので，利用に際して Python システムにインストール209 しておく．また利用するには，次のようにして Python に読み込む．

from bs4 import BeautifulSoup
以後は Beautiful Soup を BS と略す．

5.2.2.1

BS における HTML コンテンツの扱い

BS では，与えられた HTML（XML）コンテンツを独自のデータ構造である BeautifulSoup オブジェクト（以下 BS
オブジェクトと略す）に変換して保持し，それに対して解析や編集の処理を行う．
次のような HTML コンテンツ test15.html がある場合を例に挙げて BS の使用方法を説明する．

HTML コンテンツ：test15.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<! DOCTYPE html >< html >< head >< meta charset =" UTF -8" >< title > P y t h o n に 関 す る 情 報 </ title ></ head >< body ><h1 > P y t h o n に 関 す る 情 報 </ h1 ><p > 下 記 の リ ン ク を ク リ ッ ク し て P y t h o n に 関 す る 紹 介 を 読 ん で く だ さ い ． </ p ><a href =" https :// ja . wikipedia . org / wiki / Python " > ウ ィ キ ペ デ ィ ア の 記 事 へ < / a ><h2 > Beautiful S o u p に 関 す る 情 報 </ h2 ><p > 下 記 の リ ン ク を ク リ ッ ク し て Beautiful S o u p の ド キ ュ メ ン ト を 閲 覧 し て く だ さ い ． </ p ><a href =" https :// www . crummy . com / software / BeautifulSoup / bs4 / doc /" >Beautiful S o u p の ド キ ュ メ ン ト </ a ></ body ></ html >この HTML コンテンツを読み込んで BS オブジェクトに変換する例を次に示す．
例．HTML コンテンツの読み込み>>> from bs4 import BeautifulSoup←ライブラリの読込みEnter>>> txt = open(’test15.html’,’r’,encoding=’utf-8’).read()>>> sp = BeautifulSoup(txt,’html5lib’)

Enter

Enter

← HTML ファイルの読込み← BS オブジェクトの生成

この例では，ファイル test15.html の内容を txt に読込みし，それを BeautifulSoup のコンストラクタの引数に与えて BS オブジェクト sp を生成している. コンストラクタの 2 番目の引数にはコンテンツを解析するためのパーサ（’html5lib’ の部分）を指定する．パーサとしてはこの例の html5lib 以外にも lxml などもあるが，それらも使用に際しては別途インストールしておく．
■ BS オブジェクトから文字列への変換（整形あり）

BS オブジェクトに対して prettify メソッドを実行すると，BS オブジェクトの内容を整形して文字列オブジェクトに変換する．
209 PSF 版 Python での導入方法に関しては，巻末付録「A.4 PIP によるライブラリ管理」（p.363）を参照のこと．Anaconda の場合はAnaconda Navigator でパッケージ管理を行う．

337

例．prettify メソッドによる変換>>> print( sp.prettify() )Enter←変換して表示<!DOCTYPE html><html><head><meta charset="utf-8"/><title>Python に関する情報</title></head><body><h1>
Python に関する情報</h1>：（途中省略）：<a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/">
Beautiful Soup のドキュメント</a></body></html>

整形しないテキストは BS オブジェクトのプロパティ contents が保持している．
（次の例参照）

BS オブジェクトの contents プロパティ>>> print( sp.contents )[’html’, <html><head><meta charset="utf-8"/><title>Python に関する情報</title></head>：（途中省略）：</body></html>]

このようにリストの形式で保持されている．従って HTML のテキストは

BS オブジェクト.contents[1]として取り出すことができる．
■ 指定したタグの検索

BS オブジェクトに対して指定したタグの検索を実行するには ﬁnd all メソッドを使用する．
例．<a>タグを全て取り出す．
>>> sp.find all(’a’)

Enter

←検索実行

[<a href="https://ja.wikipedia.org/wiki/Python">ウィキペディアの記事へ</a>,<a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/"> Beautiful Soup のドキュメント</a>]

見つかったタグをリストにして返していることがわかる．
■ コンテンツの階層構造

BS オブジェクトの構造は基本的にリストである．従って先に説明した contents プロパティに要素の添え字を付けて更に配下の contents プロパティを取り出すということを繰り返すことで全ての要素にアクセスできる．

contents に添え字を付けて取り出したものは，1 つのタグで記述された HTML の文であり，それが持つ name プロ
パティにはそのタグの名前が保持されている．
例．タグの取り出し>>> sp.contents[1].contents[2].name’body’←処理結果← body タグの取り出しEnter

本書での Beautiful Soup ライブラリに関する解説は以上で終わるが，より多くの情報が配布元サイトや有志の開発者たちによって配信されているのでそれらを参照されたい．

338

外部プログラムとの連携

6

外部のプログラムを Python プログラムから起動する方法について説明する．C 言語や Java といった処理系でプログラムを翻訳，実行する場合と比べると，インタプリタとしての Python 処理系ではプログラムの実行速度は非常に遅い．従って，大きな実行速度を要求する部分の計算処理は，より高速な外部プログラムに委ねるべきである．実際に，科学技術系の計算処理やニューラルネットワークのシミュレーション機能を Python 用に提供するライブラリの多くは外部プログラムとの連携を応用している．
計算速度の問題に限らず，外部の有用なプログラムを呼び出して Python プログラムと連携させることは，高度な情報処理を実現するための有効な手段となる．

Python から外部プログラムを起動するには subprocess モジュールを使用する．このモジュールは次のようにして
Python 処理系に読み込む．
import subprocess

外部プログラムを起動する方法

6.1《 外部プログラムの起動 》
書き方：

subprocess.run( コマンド文字列, shell=True)

オペレーティングシステム（OS）のコマンドシェルを起動して「コマンド文字列」で与えられたコマンドを実行する．run メソッドはコマンドの終了を待ち，CompletedProcess オブジェクトを返す．コマンド文字列は，コ
マンド名と引数（群）を空白文字で区切って並べたものである．

この方法はコマンドシェルを介するので，外部プログラム起動時にシェル変数の設定などが反映される．ただし，シェルも 1 つのプロセスとして起動するので，シェルを介さずに外部プログラムを起動する場合に比べると，システ
ムに対するプロセス管理の負荷が高くなる．シェルを介さずに外部プログラムを起動するには，run メソッドの引数にキーワード引数 shell=False を指定する．
例．Windows のコマンド ’dir’ を発行する例．

>>> import subprocessEnter←モジュールの読み込み>>> subprocess.run(’dir *.eps’,shell=True)
Volume in drive C has no label.
Volume Serial Number is 18EE-2F9E

Enter← dir コマンドでファイルの一覧表示

Directory of C:￥Users￥katsu￥TeX￥Python
2016/07/23
2016/07/23
2016/07/23
2017/05/21
2017/04/29

18:16
19:09
19:22
18:10
14:23

530,687 ClientServer.eps
511,071 CSsocket0.eps
546,418 CSsocket1.eps
851,177 Earth small.eps
528,051 HBoxVBox.eps：（以下省略）：
これは，Windows のコマンドシェル（コマンドプロンプト）である cmd.exe を起動して，その内部コマンド210 である dir を実行している例である．呼び出された外部プログラムはサブプロセスとして実行される．

6.1.1

標準入出力の接続

サブプロセス（外部プログラム）の標準入出力に対してデータを送受信する方法について説明する．独立したプロ
グラム同士が通信するための代表的な方法にソケットとパイプがあり，subprocess モジュールはパイプを介した標準入出力の送受信を実現するための簡便な方法を提供している．

210 Windows の cmd.exe によって解釈されて実行されるコマンド（cmd.exe 自体が持つ機能）であり，dir 自体は単独の実行形式（*.exe）

プログラムではない．

339

《 サブプロセスとのパイプを介した通信 》
書き方：

subprocess.Popen( コマンド文字列, shell=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE )キーワード引数 stdin, stdout, stderr に subprocess.PIPE を与えることで，サブプロセスの標準入力，標準出力，標準エラー出力が Python プログラム側からアクセスできるようになる．

Popen メソッドを実行すると，戻り値として Popen オブジェクトが返され，これのプロパティ stdin, stdout,stderr に対して各種の入出力用メソッドを使用することで，サブプロセスに対して実際にデータを送受信することができる．

【サンプルプログラム】
ここでは，C 言語で作成したシミュレーションプログラムを Python から起動する例を挙げて説明する．
■ シミュレーションプログラム
円の軌跡を描く次のようなダイナミクスをシミュレートするプログラムを考える．

dx
= −y,
dt

dy
=x
dt

このダイナミクスを離散化すると次のような式となる．

Δx = −y · Δt,

Δy = x · Δt

これを実現するプログラムは，x = x - y*dt,

y = y + x*dtとなり，x,y に適当なる初期値を与えてこのプログラムを繰り返すとダイナミクスのシミュレーションが実現できる．
これを C 言語で記述したものが sbpr01.c である．
このプログラムは (x, y) = (10.0, 0.0) を初期値として，時間の刻み幅 dt を 10−8 として円の軌跡をシミュレートする．軌跡が円周を一周するとシミュレーションが終了する．
外部プログラム：sbpr01.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# include# include< stdio .h >< time .h >int main (){double x , y , dt ;longc;clock_t t1 , t2 ;/* 座 標 と 微 小 時 間 *//* ル ー プ カ ウ ン タ *//* 時 間 計 測 用 変 数 *//* シ ミ ュ レ ー シ ョ ン の 初 期 設 定 */x = 10.0;
y = 0.0;
dt = 0.00000001;/* 時 間 間 隔 */t1 = clock ();/* 開 始 時 刻 */for ( c = 0 L ; c < 628318530 L ; c += 1 L ) {y += x * dt ;x -= y * dt ;/* 中 ヌ キ 出 力 */if ( c % 200000 L == 0 ) {printf ("%16.12 lf ,%16.12 lf \ n " ,x , y );}}t2 = clock ();/* 終 了 時 刻 *//* 計 算 時 間 の 表 示 （ 標 準 エ ラ ー ） */fprintf ( stderr ,"% ld ( msec )" , t2 - t1 );}このプログラムを翻訳して実行すると，標準出力に次のような形で x, y の値を出力する．

340

10.000000000000, 0.000000100000
9.999979999707, 0.020000086666
9.999919999507, 0.039999993333
9.999819999640, 0.059999739999
9.999680000507, 0.079999246666
9.999500002667, 0.099998433337：（以下省略）：

このプログラムからの出力をテキストデータとして保存して gnuplot 211 でプロットした例を図 40 に示す．

図 40: gnuplot によるプロット例
このシミュレーションは dt を非常に小さく取っており，ダイナミクスが終了するまで x, y の移動計算を 6 億回以上実行する．これは Python のプログラムとして実行するには時間的にも適切ではないため，C 言語で実装した．
次に，このシミュレーションプログラムを Python プログラムから呼び出して，データプロットのためのライブラ
リ matplotlib 212 を使ってプロットする例を示す．

Python 側のプログラムを sbpr01.py に示す．
プログラム：sbpr01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# coding : utf -8
import subprocess
import matplotlib . pyplot as plt# サブプロセスの生成
pr = subprocess . Popen ( ’ sbpr01 . exe ’ , stdout = subprocess . PIPE , shell = True )# サブプロセスの標準出力からのデータの受け取り
lx = [];
ly = []# これらリストのデータを蓄積
buf = pr . stdout . readline (). decode ( ’ utf -8 ’). rstrip () # 初 回 読 取 り （ 1 行 ）while buf :[ bx , by ] = buf . split ( ’ , ’)
# CSVの切り離し
lx . append ( float ( bx ) ); ly . append ( float ( by ) ) # デ ー タ の 蓄 積# 次 回 読 取 り （1 行 ）buf = pr . stdout . readline (). decode ( ’ utf -8 ’). rstrip ()# matplotlibによるプロット
plt . plot ( lx , ly , ’o - ’ , label =" circle ")plt . xlabel (" x ")plt . ylabel (" y ")plt . legend ( loc = ’ best ’)
plt . show ()211 オープンソースとして公開されているデータプロットツール．
（http://www.gnuplot.info/）
212 インターネットサイト https://matplotlib.org/ でライブラリとドキュメントが公開されている．

341

このプログラムは Windows 環境で実行するものである．先のシミュレーションプログラムが Windows の実行形式
ファイル sbpr01.exe として作成213 されており，これと sbpr01.py は同じディレクトリに配置されているものとする．
このプログラムを実行すると，シミュレーション結果が図 41 のようなプロットとして表示される．

図 41: matplotlib を用いたプロット

6.1.1.1

外部プログラムの標準入力のクローズ

外部プログラムの標準入力への送信を終了してクローズするには close メソッドを用いる．具体的には，サブプロ
セスオブジェクトの stdin に対して close メソッドを実行する．
例．サブプロセス pr の stdin を閉じる

pr.stdin.close()
多くのコマンドツールは，標準入力が閉じられると終了する．そのようなコマンドツールを Python から起動した
場合，この方法で当該サブプロセスを終了することができる．
非同期の入出力

6.1.2

先の例（sbpr01.py）では，サブプロセスからの出力を受け取る繰り返し処理が終了するまで他の処理はできない．
サブプロセスとのパイプを介した入出力を非同期に実行する最も簡単な方法は，入出力の繰り返し処理を独立したスレッドで実行すること214 である．ここではサンプルプログラムを示しながらそのための方法を例示する．
【サンプルプログラム】
一定時間が経過する毎に経過時間を表示するプログラム（一種のタイマー）を C 言語で記述したものを sbpr02.c に示す．
外部プログラム：sbpr02.c
1
2
3
4
5
6
7
8
9
10
11

# include# include< stdio .h >< time .h >int main ( ac , av )int ac ;char ** av ;{int
n , c = 1;
clock_t d , t1 , t2 ;/* 時 間 計 測 用 変 数 */if ( ac < 3 ) {213 実行形式ファイルのパス名（ファイル名）などの形式は OS 毎に異なるので注意すること．
214 UNIX 系 OS のデーモンプロセスや Windows のサービスのように，入出力や通信の処理を受け付ける常駐型プログラムを Python で実現するには asyncio ライブラリを使用するのが良い．詳しくは Python の公式サイトを参照のこと．

342

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

fprintf ( stderr ," Usage : sbpr02 Duration ( ms ) Iteration ...");
return -1;} else {sscanf ( av [1] ,"% ld " ,& d );sscanf ( av [2] ,"% d " ,& n );}/* 開 始 時 刻 */t1 = clock ();printf ("% ld \ n " , t1 );while ( -1 ) {t2 = clock ();/* 現 在 時 刻 */if ( t2 - t1 >= d ) {printf ("% ld \ n " , t2 );fflush ( stdout ); /* 出 力 バ ッ フ ァ を フ ラ ッ シ ュ */t1 = t2 ;c ++;if ( c > n ) {break ;}}}
fprintf ( stderr ,"% s % s % s : finished .\ n " , av [0] , av [1] , av [2]);}このプログラムは，起動時の第 1 引数に経過時間 (ms) を，第 2 引数に計測回数を与えるものである．また経過時間を標準出力に，終了のメッセージを標準エラー出力に出力する．このプログラムを翻訳して実行した例を次に示す．

C:￥Users￥katsu￥Python> sbpr02 3000 2
0
3001
6001
sbpr02 3000 2: finished.

← 3 秒経過を 2 回通知する指定←経過時間を標準出力に出力←終了メッセージを標準エラー出力に出力

これを外部プログラムとして同時に複数並行して起動するプログラムの例を sbpr02.py に示す．
プログラム：sbpr02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# coding : utf -8
import subprocessfrom threading import Thread# サブプロセスの生成
pr1 = subprocess . Popen ( ’ sbpr02 . exe 3000 3 ’ , stdout = subprocess . PIPE , shell = True )pr2 = subprocess . Popen ( ’ sbpr02 . exe 2250 4 ’ , stdout = subprocess . PIPE , shell = True )# pr1からの入力を受け取る関数
def Exe1 ():while True :buf = pr1 . stdout . readline (). decode ( ’ utf -8 ’). rstrip ()if buf :print ( ’ プ ロ セ ス 1: ’ , buf )else :break# pr2からの入力を受け取る関数
def Exe2 ():while True :buf = pr2 . stdout . readline (). decode ( ’ utf -8 ’). rstrip ()if buf :print ( ’ プ ロ セ ス 2: ’ , buf )else :break# サブプロセスの入力を受け付けるスレッド
th1 = Thread ( target = Exe1 , args =() )th2 = Thread ( target = Exe2 , args =() )# スレッドの起動
print ( ’*** 実 行 開 始 *** ’)

343

33
34
35
36
37
38
39

th1 . start ()th2 . start ()# スレッド終了の待ち受け
th1 . join ()th2 . join ()print ( ’*** 実 行 終 了 *** ’)

解説：

6,7 行目で外部プログラムを 2 つサブプロセスとして生成して，それぞれ pr1, pr2 としている．それらの標準出力をパイプ経由で取得する処理を，関数 Exe1, Exe2 として定義（10〜16 行目）している．それら関数を独立したス
レッドとして生成（28,29 行目）して起動（33,34 行目）している．それらスレッドは同時に並行して別々に動作する．

37,38 行目では，2 つのスレッドが終了するのを待機している．スレッドの扱いに関しては「4.4 マルチスレッドとマ
ルチプロセス」（p.228）を参照のこと．
このプログラムを実行した例を次に示す．

*** 実行開始 ***プロセス 2: 0
プロセス 2: 2251
プロセス 1: 0
プロセス 1: 3000
プロセス 2: 4504
プロセス 1: 6000
プロセス 2: 6768
sbpr02.exe 3000 3:
プロセス 1: 9000
プロセス 2: 9031
sbpr02.exe 2250 4:*** 実行終了 ***finished.
finished.

各プロセスからの出力（経過時間）が標準出力に，各プロセスからの終了メッセージが標準エラー出力に出力されている215 ．

6.1.3

外部プロセスとの同期（終了の待機）

Popen メソッドで生成されたプロセスが終了するまで待機するには wait メソッドを使用する．すなわち，Popenで生成されたプロセス pr の終了に同期して，終了するまで処理をブロックする（終了まで待機する）には，

pr.wait()
とする．

6.1.4

外部プログラムを起動する更に簡単な方法

外部プログラムと呼び出し側の Python のプログラムの間で標準入出力の接続をしない場合には，os モジュールのsystem 関数を使って更に簡単に外部プログラムを起動することができる．
書き方：

os.system(’ 外部プログラムを起動するためのコマンドライン’)

これを Windows の環境で実行した例を次に示す．

215 出力のリダイレクトをしない場合，標準出力，標準エラー出力とも同じターミナルウィンドウになり，両方が混在した形で表示される．
．

344

例．dir コマンドの実行（Windows 環境）← os モジュールの読込みEnter>>> import osEnter← dir コマンドの発行

Volume in drive C has no label.
Volume Serial Number is 18EE-2F9E←実行結果の表示>>> os.system( ’dir*.pdf’ )Directory of C:￥Users￥katsu
2017/09/23
2018/09/22
2018/09/16
2018/09/14
2018/05/12
0

13:37
38,937 lab rep speed1.pdf
12:07
354,666 python ai note.pdf
14:30
4,206,175 python main.pdf
20:48
5,420,705 python modules.pdf
14:47
3,640,064 python stat.pdf
5 File(s)20,829,517 bytes
0 Dir(s) 54,815,989,760 bytes free
← os.system 関数の戻り値

参考．この方法で外部プログラムを起動する場合，データの受け渡しはファイルを介すると良い．例えば，
先の例において，dir コマンドの出力結果を Python プログラム側で受け取るには次のような方法がある．
例．dir コマンドの実行結果をファイルを介して受け取る（Windows 環境）

Enter>>> import os← os モジュールの読込みEnter>>> os.system(’dir *.pdf > temp.txt’)←標準出力をファイル ‘temp.txt’ に保存← os.system 関数の戻り値0>>> f = open(’temp.txt’,’r’)>>> t = f.read()>>> print( t )

Enter
Enter

Enter

←ファイル ‘temp.txt’ を開く216←ファイルの内容を読み取って t に受け取る← t の内容を表示

Volume in drive C has no label.
Volume Serial Number is 18EE-2F9E←ファイルの内容の表示

Directory of C:￥Users￥katsu
2017/09/23
2018/09/22
2018/09/16
2018/09/14
2018/05/12

13:37
38,937 lab rep speed1.pdf
12:07
354,666 python ai note.pdf
14:30
4,206,175 python main.pdf
20:48
5,420,705 python modules.pdf
14:47
3,640,064 python stat.pdf
5 File(s)20,829,517 bytes
0 Dir(s) 54,815,989,760 bytes free

216 open 関数には引数 ‘encoding=’ を与えてファイルのエンコーディングを指定しなければならない場合がある．

345

サウンドの入出力

7

ここでは基本的なサウンドデータの取り扱い方法について説明する．主な内容は

1. データ（ファイル）としてのサウンドの入出力
2. リアルタイムのサウンド入力と再生の 2 つである．

基礎知識

7.1

この章の内容を理解するに当たり必須となる知識を次に挙げる．
・量子化ビット数
音の最小単位を表現するビット数であり，ある瞬間の音の大きさを何ビットで表現するかを意味する．量子化ビット数が大きいほど取り扱う音の質（音質）が良い．一般的な音楽 CD などでは量子化ビット数は 16（2 バイト）である．
・サンプリング周波数（サンプリングレート）
連続的に変化するアナログの音声をサンプリングによって離散化してデジタル情報として扱うが，1 秒間に音声を何回サンプリングするか（1 秒の音声を何個に分割するか）がサンプリング周波数である．この数値が大きいほど扱う
音声の音質が良くなる．一般的な音楽 CD などではサンプリング周波数は 44.1KHz であり，1 秒の音声を 44,100 個に分割している．
・チャネル数
同時に取り扱う音声の本数がチャネル数である．日常的に鑑賞するオーディオはアナログ／デジタルの違いに関わらず，左右の音声を別々に扱っており，左右それぞれのスピーカーから再生されることが一般的である．この場合は「左右合計で 2 チャネルの音声」を扱っていることになる．高級なオーディオセットでは 2 チャネル以上の音声の取り扱いが可能なものもある．通常の場合ステレオ音声は 2 チャネル，モノラル音声は 1 チャネルの扱いを意味する．

WAV 形式ファイルの入出力：wave モジュール

7.2

wave モジュールを使用することで，WAV 形式217 のサウンドデータをファイルから読み込んだり，ファイルに書き出すこと218 ができる．
（本書では整数で波形を表現する形の WAV 形式ファイルについて説明する219 ）WAV 形式ファイルの取り扱いも通常のファイルの場合と基本的には同じであり，
1. WAV 形式ファイルをオープンする
2. WAV 形式ファイルから内容を読込む（あるいは書き込む）
3. WAV 形式ファイルを閉じるという流れとなる．wave モジュールを使用するには次のようにしてモジュールを読み込む．

import wave
7.2.1

WAV 形式ファイルのオープンとクローズ

通常のファイルの取り扱いと同様に，WAV 形式ファイルを開く場合も「読込み」もしくは「書き込み」のモードを指定する．開く場合には wave モジュールの open を，閉じる場合は close を使用する．
《 WAV 形式ファイルのオープン 》
書き方：

wave.open(ファイル名, モード)

WAV 形式ファイルのファイル名（パス名）を文字列で与え，モードには ’rb’（読込み）か ’wb’（書き込み）を指定する．open 関数が正常に終了すると「読込み」の場合は Wave read オブジェクトが，「書き込み」の場合はWave write オブジェクトが返され，それらに対して音声データの読み書きを行う．
217 Microsoft 社と IBM 社が開発した音声フォーマットである．音声データの圧縮保存にも対応しているが，非圧縮の PCM データを扱うことが多い．本書では非圧縮のものを前提とする．
218 wave モジュールはサウンドデータの解析などに使用するものであり，音声を録音・再生する機能はない．録音や再生には別のライブラリ（後述の PyAudio など）を使用する．
219 32-bit ﬂoating-point の WAV 形式ファイルの扱いについては拙書「Python3 ライブラリブック」で解説しています．

346

読み書きの処理を終える際は close メソッドを Wave read オブジェクトや Wave write オブジェクトに対して実行
する．
書き方：

7.2.1.1

Wave read/Wave write オブジェクト.close()

WAV 形式データの各種属性について

WAV 形式ファイルを開いて生成した Wave read オブジェクトから基本的な属性情報を取り出すには表 43 のようなメソッドを使用する．
表 43: Wave read オブジェクト wf からの情報の取得
メソッド
得られる情報wf.getnchannels()

チャネル数

wf.getsampwidth()

量子化ビット数をバイト表現にした値

wf.getframerate()

サンプリング周波数 (Hz)wf.getnframes()

ファイルの総フレーム数

フレームについてwave モジュールで WAV 形式データを読み込む場合，音声再生の単位となるフレーム（サンプリングにおける 1 時
点の値の全チャネルのセット）の数を指定する．すなわち「n フレームを WAV 形式ファイルから読み込む」という形の扱いとなる．表 43 の中にある総フレーム数は当該ファイルを構成する全てのフレームの数である．

7.2.2

WAV 形式ファイルからの読込み

Wave read オブジェクトからフレームデータを読み込むには readframes メソッドを使用する．
《 フレームデータの読込み 》
書き方：

Wave read オブジェクト.readframes(フレーム数)

引数には読み込むフレーム数を指定する．実際のファイルに指定したフレーム数がなければ存在するフレームのみの読込みとなる．このメソッドの実行により読み込まれた一連のフレームがバイト列として返される．

7.2.3

サンプルプログラム

Wave read オブジェクトから各種の属性情報を取得するプログラム wave00.py を次に示す．
プログラム：wave00.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# coding : utf -8
import wave
# WAV形式ファイルのオープン
wf = wave . open ( ’ sound01 . wav ’ , ’ rb ’)
print ( ’ チ ャ ネ ル 数 : \ t \t ’ , wf . getnchannels () )print ( ’ 量 子 化 ビ ッ ト 数 : \ t \t ’ ,8* wf . getsampwidth () , ’\ t ( bit ) ’ )print ( ’ サ ン プ リ ン グ 周 波 数 : \ t ’ , wf . getframerate () , ’\ t ( Hz ) ’ )print ( ’ フ ァ イ ル の フ レ ー ム 数 : \ t ’ , wf . getnframes () )b = wf . readframes (1)print ( ’1 フ レ ー ム の サ イ ズ : \ t ’ , len ( b ) , ’\ t ( bytes ) ’ )wf . close ()このプログラムを実行した例を次に示す．
チャネル数:
量子化ビット数:
サンプリング周波数:
ファイルのフレーム数:
1 フレームのサイズ:

1
16
(bit)
22050 (Hz)18170162(bytes)347

7.2.4量子化ビット数とサンプリング値の関係

WAV 形式では，量子化ビット数として 8 ビット（1 バイト）か 16 ビット（2 バイト）のサンプリングデータを扱うことが多い．またそのようなサンプリングデータを符号付きの整数値として扱う場合，表 44 のような範囲の値となる．
表 44: サンプリング値を符号付きの整数で表現する場合の値の範囲
量子化
データ型
解説

8 ビット（1 バイト）符号付き 1 バイト整数-128〜127

16 ビット（2 バイト）符号付き 2 バイト整数-32768〜32767

WAV 形式の音声データを表 44 のような形式で出力する際は，この範囲の整数値として調整する必要がある．また入力の際は，この範囲の整数値として波形データを取得する．

7.2.5

読み込んだフレームデータの扱い

WAV 形式ファイルから取得したフレームデータは適切な型のデータに変換することで音声データ解析などに使用することができる．数値データ解析のためのライブラリである numpy を用いて音声データを解析用の配列データに変換する例をサンプルプログラム wave01.py に示す．
プログラム：wave01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# coding : utf -8
import wave
import numpy# WAV形式ファイルのオープン
wf = wave . open ( ’ sound01 . wav ’ , ’ rb ’)# 各種属性の取得
chanel = wf . getnchannels ()qbit = 8* wf . getsampwidth ()freq = wf . getframerate ()frames = wf . getnframes ()b = wf . readframes ( frames )data = numpy . frombuffer (b , dtype = ’ int16 ’)print ( ’ デ ー タ タ イ プ : ’ , type ( data ))print ( ’ デ ー タ 数 : ’ ,len ( data ) )##########################################################
音 声 の 波 形 デ ー タ が data に 格 納 さ れ て い ま す ．
##
波 形 の 振 幅 は -32768〜 32767です．
##
こ の デ ー タ を numpy を は じ め と す る パ ッ ケ ー ジ で##解析処理することができます．
##########################################################
wf . close ()このプログラムの 16 行目でフレームデータを numpy の ndarray オブジェクトに変換しており，解析が可能となる．
ステレオ（2 チャンネル）音声の場合は[左，右，左，右，…]の順序で数値が格納されている．フレームデータを展開するには「4.11 バイナリデータの作成と展開： struct モジュール」（p.281）で説明した方法もある．
※ numpy ライブラリについての解説は他の情報源に譲る220 ．

先のプログラム wave01.py を少し拡張した，WAV 形式データの波形をプロットするプログラム wave01-2.py を次に示す．
220 拙書「Python3 ライブラリブック」で解説しています．

348

プログラム：wave01-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# coding : utf -8
import wave
import numpy
import matplotlib . pyplot as plt# WAV形式ファイルのオープン
wf = wave . open ( ’ aaa . wav ’ , ’ rb ’)# 各種属性の取得
chanel = wf . getnchannels ()qbit = 8* wf . getsampwidth ()freq = wf . getframerate ()frames = wf . getnframes ()# デ ー タ を numpyの配列に変換
b = wf . readframes ( frames )d = numpy . frombuffer (b , dtype = ’ int16 ’)d_left = d [0::2]# 左音声
d_right = d [1::2]# 右音声
t = [ i / freq for i in range ( len ( d_left ))]# 時間軸の生成# WAV形式ファイルのクローズ
wf . close ()# matplotlibによるプロット( fig , ax ) = plt . subplots (2 , 1 , figsize =(10 ,5))
plt . subplots_adjust ( hspace =0.6)
ax [0]. plot (t , d_left , linewidth =1)
ax [0]. set_title ( ’ left ’)ax [0]. set_ylabel ( ’ level ’)ax [0]. set_xlabel ( ’ t ( sec ) ’)ax [0]. grid ( True )ax [1]. plot (t , d_right , linewidth =1)
ax [1]. set_title ( ’ right ’)ax [1]. set_ylabel ( ’ level ’)ax [1]. set_xlabel ( ’ t ( sec ) ’)ax [1]. grid ( True )plt . show ()解説

17 行目で WAV 形式のデータを numpy の配列データに変換し，更に 18-19 行名で左右のデータとして分離し，最終的に matplotlib ライブラリによって可視化している．このプログラムを実行して表示されたグラフの例を図 42 に示す．

図 42: WAV 形式データのプロット※ matplotlib ライブラリについての解説は他の情報源221 に譲る．
221 拙書「Python3 ライブラリブック」で解説しています．

349

7.2.6WAV 形式データを出力する例 (1)：リストから WAV ファイルへ

WAV 形式データを出力するには Wave write オブジェクトに対して各種の属性情報を設定（表 45 参照）し，バイ
ナリデータとして作成した波形データを出力する．
表 45: Wave write オブジェクトへの属性情報の設定
Wave write wf に対するメソッド 設定する属性情報

wf.setnchannels(n)n=チャネル数

wf.setsampwidth(n)n=量子化ビット数をバイト表現にした値

wf.setframerate(f)f=サンプリング周波数 (Hz)1KHz の正弦波形のデータをリストの形式で生成して，それを WAV 形式データとしてファイルに保存するプログ
ラム wave02.py を次に示す．
プログラム：wave02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# coding : utf -8
import wave
import structfrom math import sin################################################## 1 K H z の 正 弦 波 サ ウ ン ド を 4 4 .1 K H z で サ ン プ リ ン グ## する際の sin関数の定義域の刻み幅##################################################
dt = ( 3 . 1 4 1 5 9 2 6 5 3 5 9 * 2 ) * 1 0 0 0 / 44100##################################################
10 秒 間 の 正 弦 波 デ ー タ を 生 成##################################################
t = 0.0
dlist = []for x in range (441000): # 10 秒 間 の デ ー タ
y = int (32767.0 * sin ( t ))dlist . append ( y )t += dt# 数値のリストをバイナリデータに変換
data = struct . pack ( ’h ’* len ( dlist ) , * dlist )print ( ’ デ ー タ サ イ ズ : ’ , len ( data ) , ’ バ イ ト ’ )##################################################
WAV形式で保存################################################### WAV形式ファイルの作成（オープン）
wf = wave . open ( ’ out01 . wav ’ , ’ wb ’)# 各種属性の設定
wf . setnchannels (1)wf . setsampwidth (2)wf . setframerate (44100)# チ ャ ネ ル 数=1# 量 子 化 ビ ッ ト 数=2 バ イ ト （16 ビ ッ ト ）# サ ン プ リ ン グ 周 波 数 = 4 4 . 1 KHz# ファイルへ出力
wf . writeframesraw ( data )wf . close ()解説

10〜20 行目の部分で正弦波形のデータをリスト dlist として作成している．それを 23 行目でバイナリデータ dataに変換している．変換には struct モジュールを使用している．この部分に関しては，「4.11 バイナリデータの作成と展
開： struct モジュール」（p.281），「2.7.1.4 関数呼び出し時の引数に ‘*’ を記述する方法」（p.124）を参照のこと．

30 行目で WAV 形式ファイル ‘out01.wav’ を作成して，33〜35 行目の部分で WAV 形式として必要な各種の属性情報を設定している．実際の出力は 38 行目で行っており，バイト列をそのまま WAV 形式データとして出力するためのメソッド writeframesraw を使用している．WAV 形式データの出力にはこの他にも writeframes メソッドもある．

350

writeframesraw と writeframes の違いは，出力するフレーム数の設定に関することであるが，詳しくは公式サイトのドキュメントを参照のこと．

WAV 形式の属性情報の設定には setparams メソッドを使用することもでき，33〜35 行目の部分を次のように短く記述することもできる．

wf.setparams( (1,2,44100,len(dlist),’NONE’,’not compressed’) )引数に与えるタプルは次のような 6 つの要素を持つ．

1 番目の要素
3 番目の要素
5 番目の要素7.2.7-

チャネル数，
サンプリング周波数，’NONE’，

2 番目の要素
4 番目の要素
6 番目の要素-

量子化ビット数のバイト値，
出力フレームの個数，’not compressed’

WAV 形式データを出力する例 (2)：NumPy の配列から WAV ファイルへ

音声データの解析や合成には，数値演算のためのライブラリである NumPy を使用することが多い222 ．ここでは，

NumPy の配列として作成した波形データを WAV ファイルに出力する方法について例を挙げて説明する．サンプルのプログラム wave02-2.py を示す．
プログラム：wave02-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# coding : utf -8
import wave
import numpy# NumPyライブラリ########################################################################## 周 波 数 1 K H z の 正 弦 波 を サ ン プ リ ン グ 周 波 数 4 4 .1 K H z で 1 0 秒 の 長 さ で 作 成 す る##########################################################################
r = 44100# サ ン プ リ ン グ 周 波 数 （ Hz）
f = 1000# サ ウ ン ド の 周 波 数 （ Hz）
T = 10# サウンドの長さ（秒）# 刻み幅（秒）dt = 1 / r# 波 形 の 作 成 （ NumPyの配列）
x = numpy . arange (0 ,T , dt )# 時間軸
w = 2.0 * numpy . pi * f# ω
y = 32767.0 * numpy . sin ( w * x )# 波 形 デ ー タ （ 振 幅 を -32767 〜32767 に 調 整 ）# 要 素 を2 バ イ ト 整 数 に 変 換 し て 波 形 デ ー タ を 保 存 用 の バ ッ フ ァ に す る
b = y . astype ( numpy . int16 ). tobytes ()########################################################################## WAVファイルとして保存する##########################################################################
wf = wave . open ( ’ out01 -2. wav ’ , ’ wb ’) # フ ァ イ ル を 出 力 用 に 開 く
wf . setnchannels (1)# チ ャ ン ネ ル 数=1 （ モ ノ ラ ル ）wf . setsampwidth (2)# 量 子 化 ビ ッ ト 数=2 バ イ ト=16 ビ ッ ト
wf . setframerate ( r )# サ ン プ リ ン グ 周 波 数 = 4 4 . 1 KHz
wf . writeframesraw ( b )# ファイルに書き出し
wf . close ()# ファイルを閉じる

解説
このプログラムは，正弦波の波形（1KHz，10 秒間）を WAV ファイル ‘out01-2.wav’ に出力するものである．7〜

15 行目で波形データが NumPy の配列（ndarray）データとして y に得られている．更に 17 行目で配列 y をバイト列（bytes 型）のデータに変換して変数 b に与えている．
（NumPy の astype，tobytes メソッドを使用）

WAV ファイルへの出力（21〜26 行目）は，先に解説した ‘wave02.py’ と同様の方法を用いる．また，WAV 形式の属性情報の設定には setparams メソッドを使用することもでき，22〜24 行目の部分を次のように短く記述することもできる．

wf.setparams( (1,2,r,len(y),’NONE’,’not compressed’) )7.2.8

サウンドのデータサイズに関する注意点

本書では解説を簡単にするために，WAV 形式ファイルの入出力を 1 度で行っている．すなわち，音声ファイルの全フレームを一度に読み込んだり，全フレームを一度でファイルに書き込むという形を取った．実用的なオーディオ
222 NumPy については拙書「Python3 ライブラリブック」で解説しています．

351

アプリケーションでは扱う音声データが大きい（数十 MB〜数百 MB）場合が多く，全フレームを一度に読み書きするのはシステムの記憶資源の関係上，現実的でないことが多い．実際には使用するシステム資源から判断して「現実的な入出力の単位」のサイズを定めて，そのサイズの入出力を繰り返すという形でサウンドデータを取り扱うことが望ましい．これに関する具体的な方法については，「7.3.2 WAV 形式サウンドファイルの再生」，「7.3.3 音声入力デバ
イスからの入力」の所で実装例を挙げて示す．

352

サウンドの入力と再生：PyAudio ライブラリ

7.3

PyAudio ライブラリを利用することで，リアルタイムの音声入出力ができる．先に説明した wave モジュールは WAV
形式の音声ファイルを取り扱うための基本的な機能を提供するものであり，これと PyAudio を併せて利用することでサウンドの入出力とファイル I/O が実現できるので，実用的なサウンドの処理が可能となる．

PyAudio は PortAudio ライブラリの Python バインディングである．PortAudio はクロスプラットフォーム用のオー
プンソースのサウンドライブラリであり，開発と保守は PortAudio community によって支えられている．PyAudioの利用に際しては，予め PortAudio をインストールしておく必要223 がある．PortAudio に関する情報はインターネッ
トサイト http://www.portaudio.com/ を参照のこと．

PSF 版 Python では PyAudio ライブラリは PIP で導入（p.363 「A.4 PIP によるライブラリ管理」を参照）することができる．Anaconda の場合は Anaconda Navigator でパッケージ管理を行う．また，PyAudio に関して本書で解説していない情報については PyAudio のドキュメントサイト https://people.csail.mit.edu/hubert/pyaudio/docs/ を参照のこと．

PyAudio を使用するには，次のようにしてライブラリを読み込んでおく．
import pyaudio
7.3.1

ストリームを介したサウンド入出力

PyAudio では，サウンドの入力源や再生のための出力先をストリームとして扱う．すなわち，サウンドの入力はストリームからデータを取得する形で行い，サウンドの再生はストリームにデータを書き込む形で行う．
【PyAudio オブジェクト】

PyAudio を用いたサウンド入出力は PyAudio オブジェクトを基本とする．PyAudio の使用に際しては予め PyAudio
オブジェクトを生成しておく．
《 PyAudio オブジェクトの生成 》
書き方：

pyaudio.PyAudio()

この結果 PyAudio オブジェクトが生成される．
実行例：

p = pyaudio.PyAudio()

実行結果として PyAudio オブジェクト p が得られる．

PyAudio オブジェクトに対して open メソッドを使用することでストリームが得られる．open メソッドの引数にサウンドの取り扱いに関する属性情報などを与える．
《 ストリームの生成 》
書き方：

PyAudio オブジェクト.open( channels=チャネル数, rate=サンプリング周波数,
format=量子化に関する情報, input=入力機能を使用するか,
output=出力機能を使用するか)

これを実行した結果ストリームが得られる．キーワード引数 input, output には真理値を指定する．input, outputに同時に True を設定することができ，その場合は「入出力両用」のストリームが得られる．
キーワード引数 format には次のようにして生成した値を指定する．

PyAudio オブジェクト.get format from width(バイト数)
バイト数には量子化ビット数をバイト単位で表現した整数値を指定する．
ストリームの使用を終える場合は，ストリームのオブジェクトに対して stop stream メソッドを実行し，更に close
メソッドを実行する．また PyAudio の使用を終える場合は，PyAudio オブジェクトに対して terminate メソッドを実行する．
223 Windows の版によってはこの処理が必要ない場合がある．macOS の場合は brew などの管理ツールで PortAudio をインストールしておく．

353

7.3.2WAV 形式サウンドファイルの再生

WAV 形式ファイルから読み込んだフレームデータをシステムのサウンド出力で再生する方法についてプログラム
例を挙げて説明する．まずはブロッキングモードと呼ばれる素朴な形での再生（プログラム pyaudio01.py）について説明する．
プログラム：pyaudio01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# coding : utf -8
import wave
import pyaudio###################################################### WAV形式サウンドファイルの読込み####################################################### ファイルのオープン
wf = wave . open ( ’ sound01 . wav ’ , ’rb ’)# 属性情報の取得
ch = wf . getnchannels ()# チャネル数
qb = wf . getsampwidth ()# 量子化ビット数（バイト数）
fq = wf . getframerate ()# サンプリング周波数
frames = wf . getnframes ()# ファイルの総フレーム数# 内容の読込み
buf = wf . readframes ( frames )# ファイルのクローズ
wf . close ()###################################################### PyAudioによる再生####################################################### PyAudioオブジェクトの生成
p = pyaudio . PyAudio ()# ストリームの生成
stm = p . open ( format = p . g e t _ f o r m a t _ f r o m _ w i d t h ( qb ) ,channels = ch , rate = fq , output = True )# ストリームへのサウンドデータの出力
stm . write ( buf )# ストリームの終了処理
stm . stop_stream ()stm . close ()# PyAudioオブジェクトの廃棄
p . terminate ()解説

8〜17 行目で WAV 形式サウンドデータを取得して，バイトデータ buf として保持している．生成したストリーム
stm に対して write メソッドを使用（27 行目）して buf の内容を書き込んでいる．
pyaudio01.py（ブロッキングモードの再生）では，サウンドの再生がメインプログラムのスレッドで実行されるので，サウンドの再生が終了するまで write メソッド部分でプログラムの流れがブロックされる．
（待たされる）
実用的なアプリケーションでは，サウンド再生はメインプログラムとは別のスレッドで実行されるべきであり，サウンド再生中もメインプログラムの流れはブロックされるべきではない．次にサウンド再生を別のスレッドで実行する方法について説明する．
【コールバックモードによる再生の考え方】
ストリームへのサウンド出力処理にはコールバックモードと呼ばれる形態がある．これは，WAV 形式ファイルからの
音声フレームの入力と，それをストリームに出力するサイクルをコールバック関数という形で定義しておき，PyAudioがこの関数を別スレッドで実行するものである．コールバック関数の呼び出しは，WAV 形式ファイルから読み込むべきフレームが無くなるまで自動的に繰り返される．コールバック関数は次のような形で定義する．
《 コールバック関数の定義 》
書き方：

def

関数名 (入力データ, フレーム数, 時間に関する情報, フラグ）：
（WAV 形式ファイルから「フレーム数」だけ読み込む処理）

return ( 読み込んだバイトデータ, pyaudio.paContinue )354このように定義した関数を PyAudio が自動的に繰り返し呼び出す．
「入力データ」にはストリームからサウンドを入力する際に取得したバイトデータが与えられる．
（再生処理の場合はこの仮引数は無視する）「フレーム数」は一度に読み取るべきフレームの数であり，コールバック関数を呼び出す際に PyAudio がこの引数に適切な値を与える.「時間に関する情報」「フラグ」に関しては説明を省略する．
（詳しくは PyAudio のドキュメント
サイトを参照のこと）
この関数は，WAV 形式ファイルから readframes メソッドを使用して読み込んだデータと，pyaudio.paContinue という値をタプルにして返す（return する）ものとして定義する．pyaudio.paContinue に関する説明は省略する．
（詳し
くは PyAudio のドキュメントサイトを参照のこと）
定義したコールバック関数は，ストリームを生成する段階で，open メソッドにキーワード引数

stream callback=関数名として与えることでストリームに登録する．ストリームに対して start stream メソッドを使用することでサウンドの再生が開始する．
コールバック関数の呼び出しによる方法でサウンドを再生するプログラム pyaudio02.py を次に示す．
プログラム：pyaudio02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# coding : utf -8
import wave
import pyaudio###################################################### WAV形式サウンドファイルの読込み####################################################### ファイルのオープン
wf = wave . open ( ’ sound01 . wav ’ , ’rb ’)# 属性情報の取得
ch = wf . getnchannels ()# チャネル数
qb = wf . getsampwidth ()# 量子化ビット数（バイト数）
fq = wf . getframerate ()# サンプリング周波数###################################################### PyAudioによる再生#######################################################---- 再 生 用 コ ー ル バ ッ ク 関 数 （ こ こ か ら ） -----------def sndplay ( in_data , frame_count , time_info , status ):buf = wf . readframes ( frame_count )return ( buf , pyaudio . paContinue )#---- 再 生 用 コ ー ル バ ッ ク 関 数 （ こ こ ま で ） -----------# PyAudioオブジェクトの生成
p = pyaudio . PyAudio ()# ストリームの生成
stm = p . open ( format = p . g e t _ f o r m a t _ f r o m _ w i d t h ( qb ) ,channels = ch , rate = fq , output = True ,stream_callback = sndplay )# コールバック関数による再生を開始
stm . start_stream ()# 待ちループ：「 exit」と入力すれば終了処理に進む
while stm . is_active ():cmd = input ( ’ 終 了 - > exit : ’)if cmd == ’ exit ’:print ( ’ 終 了 し ま す … ’ )break# ストリームの終了処理
stm . stop_stream ()stm . close ()# PyAudioオブジェクトの廃棄
p . terminate ()# WAVファイルのクローズ
wf . close ()

355

解説

19〜21 行目がコールバック関数 sndplay の定義である．この関数は，入力元の WAV 形式データファイルに対応する Wave read オブジェクト（プログラム中の wf）に readframes メソッドを実行して，音声データを取り出すものである．29 行目ではこの関数をストリームに登録している．32 行目でサウンド再生のコールバック処理が開始し，メ
インプログラムは更に下の行の実行に移る．

35〜39 行目はコマンド待ちのループであり，標準入力に対して exit と入力することで，42 行目以降の終了処理に
進む．

7.3.2.1

サウンド再生の終了の検出

コールバックモードによるサウンドの再生において，Wave read オブジェクトからの読み込みが終了（ファイル末
尾に到達）したことを検出するには，ストリームに対して is active を実行する．この結果，読み込みが終了していれば False を，終了していなければ True を返す．これは，サウンド再生の終了の検出のための基本的な方法となる．プ
ログラム pyaudio02.py の 35 行目でもこれを応用してサウンド再生の終了を検知している．
読み込みが一度終了した Wave read オブジェクトに対して rewind メソッドを実行すると，サウンドの再生位置をファイルの先頭に戻すことができる．これを応用すると，サウンドの繰り返し再生が可能となる．具体的には再生が終了したストリームに対して stop stream メソッドを実行し，再生対象の Wave read オブジェクトに対して rewindを実行した後に再度ストリームに対して start stream メソッドを実行する流れとなる．
音声入力デバイスからの入力

7.3.3

ここでは，システムに接続されたマイクやライン入力などの音声入力デバイスからリアルタイムにサウンドを入力する方法224 について説明する．
サウンドの入力に関しても，PyAudio オブジェクトから生成したストリームオブジェクトを介して処理をする．ス
トリームの生成に関してもサウンド再生の場合とよく似ており，異なるのは open メソッドの引数にinput=Trueというキーワード引数を与えることと，1 度の入力で受け取るフレーム数を指定する

frames per buffer=フレーム数というキーワード引数を与える点である．ストリームオブジェクトからサウンドを入力するには read メソッドを使用
する．
《 サウンドの入力 》
書き方：

ストリームオブジェクト.read(フレーム数)

これを実行することで，引数に与えたフレーム数のサウンドを入力してバイナリデータとして返す．

素朴なブロッキングモードによってサウンドを入力するプログラム pyaudio03.py を次に示す．
プログラム：pyaudio03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# coding : utf -8
import wave
import pyaudio###################################################### PyAudioによる音声入力####################################################### PyAudioオブジェクトの生成
p = pyaudio . PyAudio ()# ストリームの生成
stm = p . open ( format = pyaudio . paInt16 ,channels =2 , rate =44100 ,frames_per_buffer =1024 , input = True )#-----------------------------------------------# ストリームからサウンドを取り込む回数の算定# ・1 回 の 読 込 み で1024 フ レ ー ム の 入 力

224 入力デバイスの用意ができていることが前提となる．この準備がなければ作成したプログラムは正しく動作しない．
（エラーとなる）

356

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

#
#
#
n

・ 毎 秒44100 回 の サ ン プ リ ン グ
・5 秒 間 の サ ウ ン ド 採 取ということはデータの読込み回数は次の通り= int ( 44100 / 1024 * 5 )# 5秒 間 の 入 力 デ ー タ を リ ス ト に 蓄 積
print ( ’ Recording started ! ’)
# データリストの初期化
dlist = []for i in range ( n ):buf = stm . read (1024)
dlist . append ( buf )print ( ’ finished . ’)
# リストの要素を連結してバイナリデータ変換
data = b ’ ’
for i in range ( n ):data += dlist [ i ]print ( ’ data size : ’, len ( data ))# ストリームの終了処理
stm . stop_stream ()stm . close ()# PyAudioオブジェクトの廃棄
p . terminate ()###################################################### WAV形式サウンドファイルへの書き込み####################################################### ファイルのオープン
wf = wave . open ( ’ out02 . wav ’ , ’wb ’)# 属性情報の取得
wf . setnchannels (2)# チャネル数
wf . setsampwidth (2)# 量子化ビット数（バイト数）
wf . setframerate (44100) # サ ン プ リ ン グ 周 波 数# 内容の書き込み
wf . writeframes ( data )# ファイルのクローズ
wf . close ()解説
これは 5 秒間のサウンド入力を受け付け，それを WAV 形式ファイルとして保存するものである．23〜26 行目の部分で入力したサウンドデータ（バイト列）を要素とするリスト dlist を作成し，29〜31 行目の部分でそのリストの要素を全て連結したバイトデータ data を作成している．

44 行目以降の部分では，バイトデータ data を WAV 形式ファイルとして保存している．
次にサウンド入力を別のスレッドで実行する方法について説明する．
コールバックモードでサウンドを入力すると，入力処理が別のスレッドで実行されるので，メインルーチンの処理の流れがブロックされない．コールバックモードのサウンド入力を行うプログラム pyaudio04.py を次に示す．
プログラム：pyaudio04.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# coding : utf -8
import wave
import pyaudio###################################################### 書き込み用 WAV形式サウンドファイルの準備####################################################### ファイルのオープン
wf = wave . open ( ’ out03 . wav ’ , ’wb ’)# 属性情報の取得
wf . setnchannels (2)# チャネル数
wf . setsampwidth (2)# 量子化ビット数（バイト数）
wf . setframerate (44100) # サ ン プ リ ン グ 周 波 数###################################################### PyAudioによる音声入力#######################################################---- 入 力 用 コ ー ル バ ッ ク 関 数 （ こ こ か ら ） ------------

357

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

def sndrec ( in_data , frame_count , time_info , status ):wf . writeframes ( in_data )return ( None , pyaudio . paContinue )#---- 入 力 用 コ ー ル バ ッ ク 関 数 （ こ こ ま で ） -----------# PyAudioオブジェクトの生成
p = pyaudio . PyAudio ()# ストリームの生成
stm = p . open ( format = pyaudio . paInt16 , channels =2 ,rate =44100 , frames_per_buffer =1024 ,input = True , stream_callback = sndrec )# コールバック関数による入力を開始
stm . start_stream ()# 待ちループ：「 exit」と入力すれば終了処理に進む
while stm . is_active ():cmd = input ( ’ 終 了 - > exit : ’)if cmd == ’ exit ’:print ( ’ 終 了 し ま す … ’ )break# ストリームの終了処理
stm . stop_stream ()stm . close ()# PyAudioオブジェクトの廃棄
p . terminate ()# WAV形式ファイルのクローズ
wf . close ()解説
コールバック関数の基本的な書き方は先に説明した通りであるが，このプログラムでは関数（sndrec）内の処理がWAV 形式ファイルへの出力となっている．また return するタプルの最初の要素も今回は意味を持たないので Noneとしている．
このプログラムではサウンド入力と同時に WAV 形式ファイルに保存しているが，フレームデータを累積するような処理にするなど，さまざまな応用が可能である．

358

付録
A

Python に関する情報

A.1

Python のインターネットサイト■ 英語サイト：https://www.python.org/■ 日本語サイト：

https://www.python.jp/■ Anaconda 公式サイト： https://www.anaconda.com/■ Anaconda 日本語情報： https://www.python.jp/install/anaconda/

A.2

Python のインストール作業の例

Python3 のインストール方法の例を挙げる．
A.2.1

PSF 版インストールパッケージによる方法

PSF 版インストールパッケージは，Python の公式団体（The Python Software Foundation）が配布する「純正のPython」とも呼べるディストリビューションである．PSF 版と後述の Anaconda では Python 環境の管理方法が異な225るため，同一の計算機環境で両者を混在させる場合は注意を要する．

【Windows にインストールする作業の例】
先に挙げた Python のインターネットサイトから Python のインストールプログラム（インストーラ：図 43）を入手する．

図 43: Windows 用インストーラ（64 ビット用）
インストーラのアイコンをダブルクリックしてインストールを実行する．図 44 は「Customize installation」を選んで詳細の設定を選択し，インストール対象のユーザは「all users」とした例である．各種ライブラリを導入，保守するためのツールである「pip」のインストールを指定している．

→→→
図 44: インストール処理の例（Windows）

225 複数の異なる版の Python を同一計算機環境で扱うための仮想環境を構築するなどして安全に運用することも可能である．

これに関しては本書では扱わない．

359→

【Mac にインストールする作業の例】

Apple 社の macOS には既に Python2.7 がインストールされている226 ことがあるが，Python3 を使用するには，先に挙げた Python のインターネットサイトから Python3 のインストーラ（図 45）を入手してインストールする．

図 45: Mac 用インストーラ
インストーラのアイコンをダブルクリックしてインストールを実行する．作業の流れの例を図 46 に示す．

→→

図 46: インストール処理の例（Mac）

A.2.2

Anaconda による方法

Anaconda はデータ処理の分野で Python を利用する際によく用いられるディストリビューションであり，多くのライブラリが予め同梱されている．各種 OS 用のものが配布されており，Python 環境全体の管理も比較的に簡単である
ことから，このディストリビューションの評価が高まってきている．

Anaconda は前述の PSF 版とパッケージの管理方法が異なるため，同一の計算機環境で両者を混在させる場合は注意を要する．
（混在は推奨されない）

Anaconda のインストーラ（図 47）は前述の Anaconda 公式サイトから入手することができる．

図 47: Anaconda インストーラ
このインストーラを起動して，案内に沿ってインストール作業（図 48）を行う．

Anaconda は現在も活発に版が更新されており，インストール手順などに関しても公式サイトを参照されたい．

226 macOS Monterey 12.3 の版から廃止された．

360

→

→

→

→

→

→

図 48: Anaconda のインストール作業の例

A.3

Python 起動のしくみ

A.3.1

PSF 版 Python の起動

PSF 版の Python 処理系は通常，Python ランチャー（Python Launcher）を介して起動される．標準的なインストールを行うと，Windows 環境では Python 本体は C:\Program Files\Python311\python.exe （Python3.11 の場
合）としてインストールされる．もちろん，このパスを直接指定して Python 処理系を起動することもできるが，通常，Windows 環境では py コマンドを用いて起動する．この py コマンドが Windows 環境における Python ランチャー
であり，このコマンドを用いることにより，複数の異なるバージョンの Python の起動を選択することができる．例
えば 3.10 と 3.11 という 2 つの異なるバージョンの Python を 1 つの環境にインストールすることができ，次のようにして起動するバージョンを選択することができる．

py -3.10：

Python3.10 を起動

py -3.11：

Python3.11 を起動

Apple 社の macOS にも当該 OS 用の Python ランチャーがインストールされる．ただし，Windows の場合とは起動方法が異なる．Mac のコマンドでは，下記のように起動するバージョンを選択することができる．

python3.10：

Python3.10 を起動

python3.11：

Python3.11 を起動

Windows 環境の Python ランチャーでは，-0（ゼロ）オプションを指定することで，インストールされている Pythonのバージョンを確認することができる．
（次の例参照）
例．インストールされている Python のバージョンの確認（Windows 環境）

C:￥Users￥katsu>py -0

Enter-V:3.11 *Python 3.11 (64-bit)-V:3.10

Python 3.10 (64-bit)←ゼロオプションによるバージョンの確認←このバージョンがデフォルトで起動する

この例では，3.10，3.11（それぞれ 64 ビット版）がインストールされていることを示している．

A.3.2

Anaconda Navigator の起動

Anaconda では Anaconda Navigator（図 49）というインターフェースを用いて Python と関連ツールを利用する．
ENVIRONMENTS のタブ（図 50）で Anaconda のパッケージ管理ができる227 ．
A.3.3

Anaconda Prompt の起動

Anaconda の環境下でコマンド操作を行うには Anaconda Prompt を起動する．Windows 環境では Anaconda に関するツールをスタートメニュー（図 51）から起動する．
227 パッケージ管理は conda コマンドでも可能である．特に Anaconda Navigator によるパッケージ管理が正しく動作しない場合などにconda コマンドが役立つ．conda コマンドに関しては後の「A.3.3.1 conda コマンドによる Python 環境の管理」（p.363）で解説する．

361

図 49: Anaconda Navigator

図 50: Anaconda Navigator でのパッケージ管理

図 51: Windows のスタートメニューから使用する Anaconda

Anaconda 環境下でコマンドウィンドウを起動するには，図 51 中の「Anaconda Prompt」を選択する．

362

図 52: Anaconda Prompt を起動したところ
本書で例示する Python の対話モードと同様の操作を行うには，Anaconda Prompt から Python を起動するのが良い．
（次の例参照）
例．Anaconda Prompt から Python を起動(base) C:￥Users￥katsu> python

Enter← Python インタプリタの起動

Python 3.9.13 (main, Aug 25 2022, 23:51:50) [MSC v.1916 64 bit (AMD64)] ::Type "help", "copyright", "credits" or "license" for more information.

Anaconda, Inc.

on win32←対話モードのプロンプト>>>

これは python コマンドでインタプリタを起動している例である．

A.3.3.1

conda コマンドによる Python 環境の管理

Anaconda Prompt で conda コマンドによる Python 環境の管理ができる．
（表 46 参照）
表 46: conda コマンドによる Python 環境の管理（代表的な例）
コマンド

解説

conda update conda

Anaconda 環境のアップデート

conda update --allAnaconda 環境下のソフトウェアのアップデート

conda update ライブラリ名指定したライブラリのアップデート

conda list

インストールされているライブラリを一覧表示

conda search ライブラリ名

ライブラリをリポジトリ内で検索
ライブラリ名を省略すると入手可能なものの一覧が得られる．

conda install ライブラリ名

ライブラリのインストール

conda uninstall ライブラリ名

ライブラリのアンインストール

詳しくは Anaconda の公式情報サイトを参照のこと．

A.4

PIP によるライブラリ管理

PSF 版 Python では PIP を用いて各種のライブラリの導入と更新といった管理作業ができる．
▲注意▲

Anaconda の環境では PIP の使用は慎重にすること． PSF 版 Python と Anaconda ではパッケージ管理の方法が異なる．

PIP は OS のコマンドシェル（Windows の場合はコマンドプロンプト）で pip コマンドを発行228 することで実行する．pip コマンド実行時の引数やオプションの代表的なものを表 47 に挙げる．
表 47: pip コマンド起動時の引数とオプション（一部）
実行方法

動作

pip list

現在インストールされているライブラリの一覧を表示する．

pip list –o

上記の内，より新しい版が入手可能なものを表示する．

pip search キーワード「キーワード」を含む名前のライブラリで入手可能なものの一覧を表示する．

pip install ライブラリ名指定したライブラリを新規にインストールする．

pip install -U ライブラリ名指定したライブラリを更新する．

pip uninstall ライブラリ名指定したライブラリを削除する．

228 Apple 社の OS X，macOS では pip3 コマンドで PIP を起動しなければならない場合がある．

363

例．requests ライブラリをインストールする作業
C:￥Users￥katsu> pip install requests
Enter←インストールの開始
Collecting requests
Using cached requests-2.28.2-py3-none-any.whl (62 kB)
Requirement already satisfied: charset-normalizer<4,>=2 inc:￥program files￥python311￥lib￥site-packages (from requests) (3.0.1)
Requirement already satisfied: idna<4,>=2.5 inc:￥program files￥python311￥lib￥site-packages (from requests) (3.4)
Requirement already satisfied: urllib3<1.27,>=1.21.1 inc:￥program files￥python311￥lib￥site-packages (from requests) (1.26.14)
Requirement already satisfied: certifi>=2017.4.17 inc:￥program files￥python311￥lib￥site-packages (from requests) (2022.12.7)
Installing collected packages: requests
Successfully installed requests-2.28.2

PIP でインストールできるライブラリは wheel という形式で配布されるものであり，表 47 の処理はインターネットに公開されている wheel ライブラリの情報に基いて実行される．従って PIP はインターネットに接続された計算機環境で使用することが前提となっているが，wheel 形式ライブラリのファイルをダウンロードして，オフライン環境でPIP を実行してそれをインストールすることも可能である．
wheel 形式ライブラリはファイル名として whl という拡張子を持ち，それをインストールするには
pip install wheel ライブラリ名.whlというコマンド操作を行う．
例． ダウンロードした SciPy ライブラリをオフラインでインストールする作業D:￥work> pip install SciPy-1.8.1-cp311-cp311-win amd64.whl
Processing d:￥work￥scipy-1.8.1-cp311-cp311-win amd64.whl：（途中省略）：
Installing collected packages: numpy, SciPy
Successfully installed SciPy-1.8.1 numpy-1.24.2

Enter←インストール開始

これは SciPy ライブラリのファイル SciPy-1.8.1-cp311-cp311-win amd64.whl をインストールした例である．

A.4.1

PIP コマンドが実行できない場合の解決策

コマンドラインから pip が実行できない場合があるが，原因としては，コマンドサーチパスに pip コマンドのディレクトリが登録されていないことなどが挙げられる．その場合は，pip コマンドのディレクトリをコマンドサーチパ
スに登録すると解決するが，より簡単な解決策もある．それは python 処理系から pip を起動する方法である．具体的には，pip をコマンドとして起動するのではなく，次のようなコマンドラインとして投入する．
【Python を介して PIP を起動する方法】

Windows の場合： py -m pip 引数の列 · · ·Mac の場合：

python3 -m pip 引数の列 · · ·例．インストールされているライブラリの一覧を表示する

py -m pip list
これを OS のコマンドラインから投入する．

364

Kivy に関する情報

B■ 公式インターネットサイト（英語）：https://kivy.org/

このサイトでインストール手順が説明されている．

B.1

Kivy 利用時のトラブルを回避するための情報

B.1.1

Kivy が使用する描画 API の設定

Kivy はグラフィックス描画の基礎に OpenGL 229 を用いるが，使用する計算機環境によっては，OS が提供するOpenGL の版が Kivy に適合しない場合もある．そのような場合は Kivy を使用したアプリケーションプログラムを実行する際にエラーや例外が発生する．しかし，Kivy では使用するグラフィックス用の API を環境変数の設定により選択することができるので，この件に関する問題が発生する場合は os モジュールの environ プロパティに使用する APIを設定すると良い．具体的には次のような記述となる．

import osos.environ[’KIVY GL BACKEND’] = ’angle sdl2’指定できる API の例を表 48 に挙げる．
表 48: Kivy で使用できるグラフィックス API
指定する記号

解説glUNIX 系 OS 用の OpenGL

glew（デフォルト） Windows 環境で通常の場合に用いられる API

B.1.2

sdl2

Windows や UNIX 系 OS で gl や glew が使用できない場合にこれを用いる．
kivy.deps.sdl2 をインストールしておく必要がある．

angle sdl2

Windows 環境で Python 3.5 以上の版を使用する際に利用できる．
kivy.deps.sdl2 と kivy.deps.angle をインストールしておく必要がある．

SDL について

Kivy は SDL（Simple DirectMedia Layer）を利用しているため，適切な版の SDL が計算機環境にインストールされている必要がある．SDL は公式インターネットサイト（http://www.libsdl.org/）から入手することができる．Kivy
が動作しない場合は SDL の再インストールを検討するべきである．

B.2

GUI デザインツール

Kivy のための GUI アプリケーションデザインツール Kivy Designer が現在開発中であり，インターネットサイト
https://github.com/kivy/kivy-designer から情報が入手できる．

229 グラフィックス描画のための，クロスプラットフォームの API．

365

Tkinter：基本的な GUI ツールキット

CTkinter は，Python 処理系に標準的に添付されている GUI ツールキットであり，
import tkinterとすることで必要なライブラリを読み込むことができる．このライブラリは Tcl/Tk 230 の Tk の部分を Python から利用するためのものであり，本書で取り上げた Kivy に比べて GUI のデザイン性と機能面が素朴である反面，その扱いが非常に容易である．本書では Tkinter の最も基本的な部分に限って使用例を示す．より詳しい情報に関してはPython の公式インターネットサイトなど231 を参照のこと．

C.1

基本的な扱い方Tkinter では，GUI の要素をウィジェットと呼び，様々なウィジェットを階層的に構成することで GUI アプリケー
ションを実現する．また，GUI アプリケーションの最上位のウィジェットに対してイベントループを実行する形で GUI
アプリケーションの動作を実現する．
■ 最上位ウィジェットの生成

GUI アプリケーションの最上位のウィジェットのインスタンスは，Tk() を実行することで生成する．また，それに対して mainloop メソッドを実行することでイベントループが開始する．

Tk を用いた最も単純な GUI アプリケーションの実現方法を次に例示する．
例．最も単純な（基本的な）GUI アプリケーション>>> import tkinter← Tkinter ライブラリの読み込みEnter>>> tkinter.Tk().mainloop()Enter←最上位ウィジェットの生成とイベントループの開始

これにより図 53 のような GUI アプリケーションのウィンドウが表示される．

図 53: Tkinter による最も簡単な GUI アプリケーション
この例では，tkinter.Tk() で GUI の最上位のウィジェットを生成し，それに対して mainloop() を実行している．
これによりイベントを待ち受けるループが起動し，ウィンドウを閉じることでアプリケーションが終了する．
実用的な GUI アプリケーションを構築する流れは次のようなものである．
【GUI アプリケーションの構築と実行の流れ】

1.

最上位ウィジェットの生成
これが GUI アプリケーションとなる．

2.

各種ウィジェットを生成して上記ウィジェット配下に登録する

Frame オブジェクトを生成して，それを GUI のコンテナとして使用し，それに対してラベル，ボタン，入力
フィールドなど，各種のウィジェットを生成して配置する．各種ウィジェットにはイベントに対する処理のための関数を登録する．
（イベントハンドリングの実装）
ここで生成した Frame オブジェクトを最上位のウィジェットに登録する．
230 Tcl/Tk: GUI ツールキット Tk をスクリプト言語 Tcl から利用することで GUI 形式のアプリケーションプログラムを実現する

スクリプティング環境である．Tk は Tcl 以外の各種の言語からも API として呼び出すことで利用することができる．
231 ニューメキシコ工科大学（http://www.nmt.edu/）が編纂し公開している “Tkinter8.5 reference: a GUI for Python”（John W. Shipman 著）が Tkinter に関して詳しい．Web 版と PDF 版が公開されている．

366

3.

イベントループの開始
最上位のウィジェットに対して mainloop() を実行して GUI アプリケーションを開始する．
（イベントループの開始）

使用例を次に示す．

C.1.1

使用例

ここでは，ボタンに反応する GUI アプリケーション tk01.py の実装例を示す．このアプリケーションは図 54 に示
すように，「表示」「消去」の 2 つのボタンを備え，「表示」をクリックするとメッセージを表示し，「消去」をクリックするとそのメッセージを消去する．

←消去，表示→図 54: ボタンに反応する GUI アプリケーション実装したプログラムの例 tk01.py を次に示す．
プログラム：tk01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# coding : utf -8
import tkinter# Tkinterの読み込み# - - - イ ベ ン ト ハ ン ド リ ン グ 用 の 関 数 --def cmdDisp ( ):# 「表示」ボタンに対する処理
global lb2
lb2 [ ’ text ’] = ’ ク リ ッ ク さ れ ま し た ’
print ( ’ 「 表 示 」 ボ タ ン が ク リ ッ ク さ れ ま し た ’ )def cmdDel ( ):# 「消去」ボタンに対する処理
global lb2
lb2 [ ’ text ’] = ’’print ( ’ 「 消 去 」 ボ タ ン が ク リ ッ ク さ れ ま し た ’ )# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk01 main window ’ )root . geometry ( ’300 x30 +20+10 ’ )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置

fr = tkinter . Frame ( root )# GUI構築用のコンテナ
fr . pack ()# frをrootに配置
lb1 = tkinter . Label ( fr , text = ’ ク リ ッ ク し て く だ さ い → ’ )lb1 . pack ( side = ’ left ’ )# 文 字 の ラ ベ ル1
# lb1をfrに配置

b1 = tkinter . Button ( fr , text = ’ 表 示 ’ , command = cmdDisp ) # ボ タ ン 1
b1 . pack ( side = ’ left ’ )# b1をfrに配置
lb2 = tkinter . Label ( fr , text = ’
lb2 . pack ( side = ’ left ’ )’ )# 文 字 の ラ ベ ル2 （ 文 字 な し ）# lb2をfrに配置

b2 = tkinter . Button ( fr , text = ’ 消 去 ’ , command = cmdDel )b2 . pack ( side = ’ left ’ )# ボ タ ン2
# b2をfrに配置# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

解説：「表示」ボタンのクリックに対して実行する関数 cmdDisp と，「消去」ボタンのクリックに対して実行する関数

cmdDel が 5〜13 行目に定義されている．
16 行目で，アプリケーションの最上位のウィジェット root を生成し，17 行目でウィンドウのタイトルを設定（titleメソッド）し，18 行目でウィンドウのサイズと位置を設定（geometry メソッド）している．

367

GUI を構築するためのコンテナとして，20 行目で Frame オブジェクト fr を生成している．このときコンストラ
クタの第 1 引数に，登録先の上位のオブジェクトを与える．更に 21 行目で，pack メソッドを用いて，配置（表示位置）を決定している．
文字を表示するためのラベルウィジェットは Label クラスのオブジェクトであり，コンストラクタの第 1 引数に「親ウィジェット」（登録先の上位ウィジェット）を，キーワード引数 ‘text=’ に表示する文字列を与える．23 行目で Label
ウィジェットを生成しており，24 行目で上位の fr の上での配置を設定している．29〜30 行目でも同様の手順で Label
オブジェクトを生成・配置している．ラベルウィジェット生成後に表示内容（テキスト）を与えるには，そのラベル
オブジェクトにスライス ‘[’text’]’ を付けたものに値を設定する．
（7,12 行目）
ボタンウィジェットは Button クラスのオブジェクトであり，コンストラクタの第 1 引数に「親ウィジェット」（登録先の上位ウィジェット）を，キーワード引数 ‘text=’ に表示する文字列を与える．また，キーワード引数 ‘command=’にクリックされた際に実行する関数の名前を与える．26 行目で「表示」の Button ウィジェットを生成しており，27行目で上位の fr 上での配置を設定している．32〜33 行目でも同様の手順で Button オブジェクトを生成・配置している．

C.1.1.1

ウィンドウサイズ変更の可否の設定

Tk() で生成した最上位ウィジェットに対して resizable メソッドを使用することで，ウィンドウのサイズ変更の可否を設定できる．
書き方：

ウィジェット.resizable(横方向の変更可否, 縦方向の変更可否)

このメソッドの引数には真理値（True/False）を与える．False を与えるとリサイズの禁止が設定される．

C.1.2

ウィジェットの配置

先の tk01.py の例では，pack メソッドを使用してウィジェットを配置した．pack メソッドはウィジェットを「縦方向もしくは横方向の一次元」に配置するものであるが，この他にも二次元的な配置や，座標指定による自由な配置のためのメソッドもある．
【サンプルプログラム】
ウィジェットの配置を確認するためのサンプルプログラム tk02.py を次に示す．このプログラムは，pack メソッド
による一次元の配置と，grid メソッドによる二次元の配置を確認するためのものである．後に示す「試み」により確認できる．
プログラム：tk02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# coding : utf -8
import tkinter# Tkinterの読み込み# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk02 main window ’ )root . geometry ( ’300 x60 +20+10 ’ )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置

fr = tkinter . Frame ( root )# GUI構築用のコンテナ
fr . pack ()# frをrootに配置# 配置テスト用のボタン群
b11 = tkinter . Button ( fr ,b12 = tkinter . Button ( fr ,b21 = tkinter . Button ( fr ,b22 = tkinter . Button ( fr ,# - - - 配 置 --# 横方向# b11 . pack ( side = ’ left ’);# b11 . pack ( side = ’ right ’);# 縦方向# b11 . pack ( side = ’ top ’);# b11 . pack ( side = ’ bottom ’);text = ’ b11 ’text = ’ b12 ’text = ’ b21 ’text = ’ b22 ’

)
)
)
)

b12 . pack ( side = ’ left ’)b12 . pack ( side = ’ right ’)b21 . pack ( side = ’ top ’)b21 . pack ( side = ’ bottom ’)# 縦横（二次元）

368

27
28
29
30
31

# b11 . grid ( row =0 , column =0);
# b21 . grid ( row =1 , column =0);b12 . grid ( row =0 , column =1)
b22 . grid ( row =1 , column =1)# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

試み：(1) 一次元の配置
・20 行目，21 行目のどちらかのコメント「#」を外すことで，pack メソッドによる横方向の配置が確認できる．
・23 行目，24 行目のどちらかのコメント「#」を外すことで，pack メソッドによる縦方向の配置が確認できる．

pack メソッドに与えるキーワード引数 ‘side=’ の値によって配置がどのようになるかを確認すること．
試み：(2) 二次元の配置
・27 行目，28 行目の両方のコメント「#」を外すことで，grid メソッドによる縦横の配置が確認できる．

grid メソッドに与えるキーワード引数 ‘row=’,‘column=’ の値によって行と列の位置が指定できる．
tk02.py の実行結果の例を図 55 に示す．

(a) 20 行目のコメントを削除(b) 23 行目のコメントを削除(c) 27,28 行目のコメントを削除

図 55: pack や grid メソッドによるボタンの配置
コメントの削除によってボタンの配置の様子が確認できる．
■ ウィジェットの伸縮の制御

pack でウィジェットを配置する際，キーワード引数 ‘ﬁll=’，‘expand=’ に値を設定（表 49）することにより，ウィジェットの伸縮を制御できる．
表 49: キーワード引数 ‘ﬁll=’ と ‘expand=’キーワード引数

値

効果

ﬁll=

’x’

横方向に伸ばす’y’

縦方向に伸ばす’both’

縦横両方向に伸ばす

True
False

サイズの拡張を可能にする
サイズを拡張しない

expand=

ラベルウィジェットの伸縮制御を試みるサンプルプログラム tk02-2.py を示す．
プログラム：tk02-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# coding : utf -8
import tkinter# Tkinterの読み込み# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk02 -2 main window ’ )root . geometry ( ’280 x280 +20+10 ’ )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置

fr = tkinter . Frame ( root )# GUI構築用のコンテナ
fr . pack ( fill = ’ both ’ , expand = True ) # f r を r o o t に 配 置# 配置テスト用のラベル
lb1 = tkinter . Label ( fr , text = ’ ラ ベ ル １ ’ , font = ’32 ’ ,fg = ’# ff0000 ’ , bg = ’# ffff00 ’ )lb1 . pack ( fill = ’x ’ , expand = True )# 横に伸ばすlb2 = tkinter . Label ( fr , text = ’ ラ ベ ル ２ ’ , font = ’32 ’ ,fg = ’# ffff00 ’ , bg = ’# ff0000 ’ )lb2 . pack ( fill = ’ both ’ , expand = True )# 縦横に伸ばす

369

20
21
22
23
24
25
26

lb3 = tkinter . Label ( fr , text = ’ ラ ベ ル ３ ’ , font = ’32 ’ ,fg = ’# ffffff ’ , bg = ’#000000 ’ )lb3 . pack ( fill = ’y ’ , expand = True )# 縦に伸ばす# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

このプログラムの実行例を図 56 に示す．

→
ウィンドウサイズの変更に伴ってラベルのサイズが変わる

図 56: ウィジェットの伸縮

各種のウィジェット

C.2

ここでは，特に利用頻度の高いウィジェットを紹介し，その使用方法を例示する．

C.2.1

チェックボタンとラジオボタン

チェックボタン232 とラジオボタンの使用方法についてサンプルプログラムを示しながら説明する．ここでは図 57のような GUI アプリケーションを考える．

(a) アプリケーション起動直後(b) チェックボタンを操作した場合の表示(c) ラジオボタンを操作した場合の表示

図 57: チェックボタンとラジオボタン
このアプリケーションは最上段に 3 つのチェックボタン，中段に 3 つのラジオボタン，最下段に文字列表示用のラベルを備えている．チェックボタンやラジオボタンを操作すると，それらの状態をラベルに報告する．
・チェックボタンのコンストラクタ

Checkbutton(上位ウィジェット, text=ボタンに表示する文字列,
onvalue=既チェック時の値, oﬀvalue=未チェック時の値, variable=状態保持用オブジェクト,
command=操作時に起動する関数の名前 )チェックボタンは「既チェック／未チェック」の状態を保持するウィジェットであり，その状態を状態保持用オブジェ
クト（Variable クラスのオブジェクト）に保持する．

C.2.1.1

Variable クラス

Variable クラスは各種状態（値）を保持するための次のような各種クラスを提供する．

232 Tkinter 以外の GUI ツールキットでは「チェックボックス」と呼ぶことが多い．

370

StringVar:

文字列の値を保持するオブジェクト

IntVar:整数の値を保持するオブジェクト

DoubleVar:

浮動小数点数の値を保持するオブジェクト

BooleanVar:

真理値を保持するオブジェクト

これらクラスのオブジェクトは，値の変更などをイベントとして検知する233 機能があり，Tkinter の他の様々なウィジェットでも使用する．Variable オブジェクトに対して set メソッドや get メソッドを使用して値の設定と参照ができる．
・ラジオボタンのコンストラクタ

Radiobutton(上位ウィジェット, text=ボタンに表示する文字列,
value=選択時の値, variable=状態保持用オブジェクト, command=操作時に起動する関数の名前 )複数のラジオボタンを同一のグループでまとめるには「状態保持用オブジェクト」として同一のオブジェクトを指定する．また図 57 にもある通り，同一グループのラジオボタンは見出し付きの枠で囲んで表示することも多く，その場合は上位ウィジェットとして，ラベルフレーム（tkinter.ttk.Labelframe クラスのオブジェクト）を使用する．
図 57 のアプリケーションの実装例を tk03.py に示す．
プログラム：tk03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# coding : utf -8
import tkinterfrom tkinter import ttk# Tkinterの読み込み# tkinter . t t k の 読 み 込 み# - - - イ ベ ン ト ハ ン ド リ ン グ 用 の 関 数 --def cmdChk ():msg = ’ Checkbutton ’+\’: item -0: ’+ str ( vChk1 . get ())+\’, item -1: ’+ str ( vChk2 . get ())+\’, item -2: ’+ str ( vChk3 . get ())
lbText [ ’ text ’] = msg
def cmdRd ():msg = ’ Radiobutton : ’+ vRd . get ()lbText [ ’ text ’] = msg# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk03 main window ’ )root . geometry ( ’300 x110 +20+10 ’ )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置

frMain = tkinter . Frame ( root )# GUI構築用のコンテナ
frMain . pack ()# frMainをrootに配置#----frChk = tkinter . Frame ( frMain )frChk . pack ( side = ’ top ’ )# チェックボタン用コンテナ# frChkをfrMainに配置# チェックボタン１
vChk1 = tkinter . IntVar ()# Variableオブジェクト
btnChk1 = tkinter . Checkbutton ( frChk , text = ’ item -0 ’ ,onvalue =1 , offvalue =0 , variable = vChk1 ,command = cmdChk )btnChk1 . pack ( side = ’ left ’ )# チェックボタン２
vChk2 = tkinter . IntVar ()# Variableオブジェクト
btnChk2 = tkinter . Checkbutton ( frChk , text = ’ item -1 ’ ,onvalue =1 , offvalue =0 , variable = vChk2 ,command = cmdChk )btnChk2 . pack ( side = ’ left ’ )# チェックボタン３

233 Variable クラスのオブジェクトに対して trace メソッドを用いてコールバック関数を登録できる．後述の「C.2.5 スケール（スライダ）とプログレスバー」（p.376）のところで事例を紹介する．

371

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

vChk3 = tkinter . IntVar ()# Variableオブジェクト
btnChk3 = tkinter . Checkbutton ( frChk , text = ’ item -2 ’ ,onvalue =1 , offvalue =0 , variable = vChk3 ,command = cmdChk )btnChk3 . pack ( side = ’ left ’ )#----# ラジオボタン用ラベルフレーム
lfrRd = ttk . Labelframe ( frMain , text = ’ Radio button ’)lfrRd . pack ( side = ’ top ’ )vRd = tkinter . StringVar ()vRd . set ( ’A ’)# ラジオボタン用変数# ラジオボタン１
btnRd1 = tkinter . Radiobutton ( lfrRd , text = ’ item -A ’ ,variable = vRd , value = ’A ’ , command = cmdRd )btnRd1 . pack ( side = ’ left ’ )# ラジオボタン２
btnRd2 = tkinter . Radiobutton ( lfrRd , text = ’ item -B ’ ,variable = vRd , value = ’B ’ , command = cmdRd )btnRd2 . pack ( side = ’ left ’ )# ラジオボタン３
btnRd3 = tkinter . Radiobutton ( lfrRd , text = ’ item -C ’ ,variable = vRd , value = ’C ’ , command = cmdRd )btnRd3 . pack ( side = ’ left ’ )#----# テキスト表示用ラベル
lbText = tkinter . Label ( frMain )lbText . pack ( side = ’ top ’ )# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

C.2.2

エントリ（テキストボックス）とコンボボックス

文字列を入力するにはエントリあるいは，tkinter.ttk が提供するコンボボックスが利用できる．
・エントリのコンストラクタ

Entry(上位ウィジェット, textvariable=状態保持用オブジェクト, width=長さ )エントリは基本的な文字入力用ウィジェットである．コンボボックスは文字の入力に加えて，予め設定しておいた
選択肢から選択する形式の入力も可能である．
・コンボボックスのコンストラクタ

Combobox(上位ウィジェット, textvariable=状態保持用オブジェクト, width=長さ )コンボボックス（tkinter.ttk.Combobox クラスのオブジェクト）に選択肢を設定するには，そのオブジェクトにスライス ‘[’values’]’ を付けたものに選択肢を要素として持つタプルを与える．
キーワード引数 ‘width=’ にはウィジェットの横幅を設定する．
【サンプルプログラム】
エントリとコンボボックスを使用した，図 58 のような動作をするサンプルプログラムを tk04.py に示す．
プログラム：tk04.py
1
2
3
4
5
6
7
8
9
10

# coding : utf -8
import tkinterfrom tkinter import ttk# Tkinter# tkinter . ttk# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk04 main window ’ )root . geometry ( ’300 x120 +20+10 ’ )frMain = tkinter . Frame ( root )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置# GUI構築用のコンテナ372

→「クリック」ボタンにより入力内容がラベルに表示される．

図 58: チェックボタンとラジオボタン
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

frMain . pack ()# frMainをrootに配置#----# エントリ
vEnt1 = tkinter . StringVar ()vEnt1 . set ( ’ 初 期 テ キ ス ト ’ )# エントリ用変数

ent1 = tkinter . Entry ( frMain , width =40 , textvariable = vEnt1 )ent1 . pack ( side = ’ top ’ )#----# コンボボックス
vCmb1 = tkinter . StringVar ()# コンボボックス用変数
vCmb1 . set ( ’ （ 選 ん で く だ さ い ： 入 力 も 可 能 ） ’ )cmb1 = ttk . Combobox ( frMain , width =37 , textvariable = vCmb1 )cmb1 [ ’ values ’] = ( ’ 選 択 肢 １ ’ , ’ 選 択 肢 ２ ’ , ’ 選 択 肢 ３ ’ )cmb1 . pack ( side = ’ top ’ )#----# ボタン# 内容表示ボタン
def cmdBtn1 ():# ボタンのハンドリング用関数
global lb1
lb1 [ ’ text ’] = ’ Entry : ’+ vEnt1 . get ()+ ’ , Combobox : ’+ vCmb1 . get ()btn1 = tkinter . Button ( frMain , text = ’ ク リ ッ ク ’ , command = cmdBtn1 )btn1 . pack ( side = ’ top ’ )# 終了ボタンdef cmdBtn2 ():# ボタンのハンドリング用関数
print ( ’ 終 了 し ま す ． ’ )root . quit ()# アプリケーションの終了
btn2 = tkinter . Button ( frMain , text = ’ 終 了 ’ , command = cmdBtn2 )btn2 . pack ( side = ’ top ’ )#----# ラベル
lb1 = tkinter . Label ( frMain , width =40)
lb1 . pack ( side = ’ top ’ )# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

C.2.2.1

プログラムの終了

tk04.py の 44 行目にあるように，quit メソッドを実行するとアプリケーションが終了する．
C.2.3

リストボックス

複数の要素を持つリストの中から項目を選択するリストボックスを実現するための Listbox クラスについて説明する．ここでは図 59 に示すようなアプリケーションの作成を例に示す．

373

→
リスト項目を選択してボタンをクリックすると選択内容がエントリに表示される．

複数の項目を選択するリストボックスも実現可能

図 59: リストボックス「クリック」ボタンをクリックすると右端のエ
図 59 に示すアプリケーションは，左端のリストから項目を選択し，ントリに選択した項目を表示するものである．このアプリケーションの実装例を tk05.py に示す．
プログラム：tk05.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# coding : utf -8
import tkinter# Tkinter# - - - G U I の 構 築 --root = tkinter . Tk ()# アプリケーションの最上位ウィジェット
root . title ( ’ tk05 main window ’ )# ウィンドウのタイトル
root . geometry ( ’300 x80 +20+10 ’ ) # ウ ィ ン ド ウ の サ イ ズ と 位 置
frMain = tkinter . Frame ( root )# GUI構築用のコンテナ
frMain . pack ()# frMainをrootに配置# リストボックスvLbx1 = tkinter . StringVar ( value =( ’ 項 目 11 ’ , ’ 項 目 12 ’ , ’ 項 目 13 ’ , ’ 項 目 1 4 ’ ) )lbx1 = tkinter . Listbox ( frMain , listvariable = vLbx1 , height =4 , width =7 ,#selectmode = ’ single ’# 選択：シングル
selectmode = ’ multiple ’# 選択：複数)
lbx1 . pack ( side = ’ left ’ )# ボタン
def cmdBtn1 (): # ク リ ッ ク に よ っ て 起 動 す る 関 数
global vEnt1 , lbx1
msg = ’’
for i in lbx1 . curselection ():msg += lbx1 . get ( i )+ ’ , ’
vEnt1 . set ( msg )btn1 = tkinter . Button ( frMain , text = ’ ク リ ッ ク ’ , command = cmdBtn1 )btn1 . pack ( side = ’ left ’ )# エントリvEnt1 = tkinter . StringVar ()ent1 = tkinter . Entry ( frMain , textvariable = vEnt1 , width =30 )ent1 . pack ( side = ’ left ’ )# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

・リストボックスのコンストラクタ

Listbox(上位ウィジェット, listvariable=状態保持用オブジェクト, width=長さ, height=高さ,
selectmode=選択モード )キーワード引数 ‘listvariable=’ には StringVar オブジェクトを与えるが，それを生成する際のコンストラクタのキー
ワード引数 ‘value=’ に，選択肢の文字列を要素とするタプルを与える．リストボックスには選択モードが設定でき，単374

一の選択肢を選ぶか，複数の選択肢を同時に選ぶかを設定できる．これはキーワード引数 ‘selectmode=’ に ’single’
か ’multiple’ を与えることで設定する．
リストボックスの選択されている項目を取得するには curselection メソッド（24 行目）を使用する．これにより，選択されている項目番号のタプルが得られる．リストボックスの n 番目の項目の値を取り出すには get(n) メソッドを実行する．
（25 行目）C.2.4

テキスト（文字編集領域）とスクロールバー

先に紹介したエントリは，1 行分の入力を想定しているが，テキストは複数行のテキストの編集を可能にするウィジェットである．ここではテキストに加えて，スクロールバーの設置についても説明する．
図 60 のようなアプリケーションの実装について考える．

→
テキストの入力に応じて，上下，左右のスクロールバーが連動する

図 60: スクロールバーと連動するテキスト（文字編集領域）
これは，ウィンドウの編集領域に文字を入力し，「出力」ボタンをクリックすると内容を標準出力に出力するものである．実装例を tk06.py に示す．
プログラム：tk06.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# coding : utf -8
import tkinter# Tkinter# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk06 main window ’ )root . geometry ( ’310 x160 +20+10 ’ )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置

frMain = tkinter . Frame ( root )# GUI構築用のコンテナ
frMain . pack ()# frMainをrootに配置# ボタン
def cmdBtn1 ():global txt
t = txt . get ( ’1.0 ’ , ’ end ’). rstrip ()print ( ’ - - - top - - - ’)print ( t )print ( ’ - - - bottom - - - ’)btn1 = tkinter . Button ( frMain , text = ’ 出 力 ’ , command = cmdBtn1 )btn1 . grid ( row =0 , column =0 )# ボタン

# テキストtxt = tkinter . Text ( frMain , width =40 , height =8 , wrap = ’ none ’ )txt . grid ( row =1 , column =0 )# スクロールバー（縦）scrY = tkinter . Scrollbar ( frMain , orient = ’ vertical ’ , command = txt . yview )txt [ ’ yscrollcommand ’] = scrY . set
scrY . grid ( row =1 , column =1 , sticky =( ’n ’ , ’s ’) )# スクロールバー（横）scrX = tkinter . Scrollbar ( frMain , orient = ’ horizontal ’ , command = txt . xview )txt [ ’ xscrollcommand ’] = scrX . set
scrX . grid ( row =2 , column =0 , sticky =( ’w ’ , ’e ’) )

375

37
38

# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

・テキストのコンストラクタ

Text(上位ウィジェット, width=横幅, height=高さ, wrap=折返し指定 )
折返し指定に ‘none’ を与えると，Text の横幅よりも長い行の折り返し処理をしない．
・スクロールバーのコンストラクタ

Scrollbar(上位ウィジェット, orient=縦横の方向, command=関数名 )縦横の方向に ‘vertical’ を与えると縦，‘horizontal’ を与えると横のスクロールバーとなる．キーワード引数‘command=’ には今回は txt.yview や txt.xview を与えているが，これは Text オブジェクトの表示位置を変更するメソッドの名前である．
（このメソッドに関して詳しいことは Tk のドキュメントを参照のこと）これにより，スクロールバーの位置の変更が，Text オブジェクトの txt の表示位置に反映される．
また，Text オブジェクト txt の内容編集に伴って表示位置の変更が発生した場合は，それをスクロールバーに反映させる必要があるが，それは Text オブジェクトにスライス [’yscrollcommand’]，[’xscrollcommand’] を付けたものに，スクロールバーの位置変更を施すメソッドの名前 ‘set’ を与えている．
（set メソッドに関しても詳しくは Tk のドキュメントを参照のこと）
今回のプログラムでは，スクロールバーを grid メソッドで配置する際に，キーワード引数 ‘sticky=’ を与えて上下あるいは左右いっぱいに広げている，（30,35 行目）‘sticky=’ に与える値に関しては p.380 の図 64 「位置の基準」を参照のこと．このような設定により Text オブジェクト txt の縦横のサイズにスクロールバーのサイズを合わせている．
このアプリケーションの「出力」ボタンをクリックした際の標準出力の例を次に示す．
出力の例— top —
Python はオランダのプログラマであるグイド・ヴァンロッサム（Guido van Rossum）
によって 1991 年に開発されたプログラミング言語であり，言語処理系は基本的にインタプリタである．Python は多目的の高水準言語であり，言語そのものの習得とアプリケーション開発に要する労力が比較的に少ないとされる．しかし，実用的なアプリケーションを開発するために必要とされる多くの機能が提供されており，：（途中省略）：
ものの習得や運用の簡便性と相俟って，情報工学や情報科学とは縁の遠い分野の利用者に対してもアプリケーション開発の敷居を下げている．
— bottom —Text オブジェクトから内容を取り出すには get メソッドを使用する．その際，第 1 引数にテキストの開始位置，第2 引数に終了位置を指定する．プログラムの 15 行目では開始位置として ‘1.0’ を与えているが，これは ‘行番号. 桁’の形で指定する形式であり「第 1 行目のインデックス 0 番目」を意味する．

C.2.5

スケール（スライダ）とプログレスバー

スケールはいわゆる「スライダ」とも呼ばれるウィジェットで，直感的な操作で 1 次元の数値を設定するものである．また，プログレスバーは 1 次元の数値を直感的に図示するウィジェットである．ここでは図 61 に示すようなアプ
リケーションの構築を例に挙げて，スケールとプログレスバーの扱いについて説明する．

→
図 61: スケールにプログレスバーを連動させる試み

376

このアプリケーションは，スケールで設定された値をそのままプログレスバーに反映させるものである．プログラ
ムの例を tk07.py に示す．
プログラム：tk07.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# coding : utf -8
import tkinterfrom tkinter import ttk# Tkinter# tkinter . ttk# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk07 main window ’ )root . geometry ( ’290 x100 +20+10 ’ )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置

frMain = tkinter . Frame ( root )# GUI構築用のコンテナ
frMain . pack ()# frMainをrootに配置# スケールdef traceSc1 ( * arg ):# 値の変更を受けて起動する関数
global vSc1 , pb1
pb1 . configure ( value = vSc1 . get () )# プログレスバーの状態の変更
vSc1 = tkinter . DoubleVar ()vSc1 . set (0)vSc1 . trace ( ’w ’ , traceSc1 )# スケールの値を保持するオブジェクト# 初期値# 値が変更されたときのハンドリング

sc1 = tkinter . Scale ( frMain , variable = vSc1 )sc1 . pack ( side = ’ left ’ )# スケールオブジェクト# プログレスバー
pb1 = ttk . Progressbar ( frMain )pb1 . pack ( side = ’ left ’ )# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

・スケールのコンストラクタ

Scale(上位ウィジェット, variable=状態保持用オブジェクト )今回は状態保持用オブジェクトとして DoubleVar オブジェクト vSc1 を与えている．DoubleVar だけでなく Variable
クラスのオブジェクトには，値の変化を検知した際に呼び出すコールバック関数を設定（20 行目）することができる．

C.2.5.1

Variable クラスのコールバック関数設定

次のように trace メソッドを用いて Variable オブジェクトにコールバック関数を設定することができる．

trace( モード, 関数名 )trace メソッドは，Variable オブジェクトの値に変更などが発生した際に起動するコールバック関数を設定する．モードに ‘w’ を指定すると値の変更（今回の場合はスケールの値の変更）が発生した際にコールバック関数を起動する．
・プログレスバーのコンストラクタ

Progressbar(上位ウィジェット )プログレスバー（tkinter.ttk.Progressbar クラスのオブジェクト）には conﬁgure メソッドを使用（16 行目）することで値を設定することができる．この際，キーワード引数 ‘value=’ に値を与える．
● スケール，プログレスバーの向きと長さ
スケール，プログレスバーのコンストラクタにキーワード引数 ‘orient=’ を与えることで向き（’vertical’:上下方
向，’horizontal’:左右方向）を設定することができる．また長さは，コンストラクタにキーワード引数 ‘length=長さ’ を与えることで設定する．
● ウィジェットの値の範囲
スケールの値の範囲（下限と上限）を設定するには，コンストラクタにキーワード引数 ‘from =下限値’，‘to=上限

377

値’ を与える．
（from のアンダースコアに注意）スライダの向きが上下方向の場合は上端が下限値であり，左右方向の場合は左端が下限値となる．
プログレスバーには上限のみ設定することができる．コンストラクタにキーワード引数 ‘maximum=上限値’ を与えることで上限を設定することができる．

C.3

メニューの構築

ここでは図 62 のようなアプリケーションを例に挙げてメニューの構成方法について説明する．

(a) 起動時→(b) メニュー項目の選択(c) 選択後の動作

図 62: メニュー
このアプリケーションは，ウィンドウ上部に「Menu-1」「Menu-2」という 2 つのメニューを備えたメニューバーを持つ．それぞれのメニューはプルダウンの形でメニュー項目を表示する．メニュー項目を選択すると，その旨を告げるメッセージをラベルに表示する．
「Menu-1」の項目「Quit」を選択することでアプリケーションが終了する．
このアプリケーションの実装例をサンプルプログラム tk08.py に示す．
プログラム：tk08.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# coding : utf -8
import tkinter# Tkinter# - - - G U I の 構 築 --root = tkinter . Tk ()# アプリケーションの最上位ウィジェット
root . title ( ’ tk08 main window ’ )# ウィンドウのタイトル
root . geometry ( ’290 x50 +20+10 ’ ) # ウ ィ ン ド ウ の サ イ ズ と 位 置
frMain = tkinter . Frame ( root )# GUI構築用のコンテナ
frMain . pack ()# frMainをrootに配置#--# メニューの構築
mb1 = tkinter . Menu ( root )root . config ( menu = mb1 )# メニューバーの生成# 最上位ウィジェットへの取り付け# メニュー選択を受けて起動する関数
def cmdMn11 ():lb1 [ ’ text ’] = ’ item -11 が 選 択 さ れ ま し た ． ’
def cmdMn12 ():print ( ’ Quit が 選 択 さ れ ま し た ． 終 了 し ま す ． ’ )root . quit ()def cmdMn21 ():lb1 [ ’ text ’] = ’ item -21 が 選 択 さ れ ま し た ． ’
def cmdMn22 ():lb1 [ ’ text ’] = ’ item -22 が 選 択 さ れ ま し た ． ’# メニュー１
mn1 = tkinter . Menu ( mb1 , tearoff =0 )mn1 . add_command ( label = ’ item -11 ’ , command = cmdMn11 )# メニュー項目の登録
mn1 . add_command ( label = ’ Quit ’ , command = cmdMn12 )# メニュー項目の登録
mb1 . add_cascade ( label = ’ Menu -1 ’ , menu = mn1 )# メニュー１をメニューバーに登録

378

34
35
36
37
38
39
40
41
42
43
44
45
46

# メニュー２
mn2 = tkinter . Menu ( mb1 , tearoff =0 )mn2 . add_command ( label = ’ item -21 ’ , command = cmdMn21 )# メニュー項目の登録
mn2 . add_command ( label = ’ item -22 ’ , command = cmdMn22 )# メニュー項目の登録
mb1 . add_cascade ( label = ’ Menu -2 ’ , menu = mn2 )# メニュー２をメニューバーに登録# ラベル
lb1 = tkinter . Label ( frMain , text = ’ メ ニ ュ ー を 操 作 し て く だ さ い ’ )lb1 . pack ( side = ’ top ’ )# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

解説：

14 行目で Menu オブジェクト mb1 を生成し，15 行目でそれをメニューバーとして最上位ウィジェット root に取り付けている．この処理においては root に対して conﬁg メソッドを使用する．その際，conﬁg メソッドのキーワー
ド引数 ‘menu=’ にメニューバーとなるオブジェクトを与える．
メニューバーにメニューを取り付けるには，各メニューとなる Menu オブジェクトを生成して，メニューバーの配下に登録する．各メニューにメニュー項目を登録するには当該メニューオブジェクトに対して add command メソッドを使用する．このメソッドのキーワード引数 ‘label=’ にはメニュー項目の表示名を与え，‘command=’ には，そのメニュー項目を選択した際に起動する関数の名前を与える．

C.4

Canvas の描画

図形の描画には Canvas オブジェクトを使用する．
・Canvas のコンストラクタ

Canvas(上位ウィジェット, width=横幅, height=高さ, bg=背景色 )背景色には 3 原色（RGB）の配合を 16 進数で，‘#’ で始まる文字列234 として与える．Canvas オブジェクトに対して，以下に示すような各種の描画メソッドを使用して描画する．

C.4.1

描画メソッド（一部）・矩形の描画

create rectangle( x1,y1,x2,y2, width=線幅, outline=線の色, ﬁll=塗りの色 )Canvas オブジェクト上に矩形（長方形）を描画する．矩形の左上の座標を (x1,y1)，右下の座標を (x2,y2) として描く．
・楕円の描画

create oval( x1,y1,x2,y2, width=線幅, outline=線の色, ﬁll=塗りの色 )Canvas オブジェクト上に楕円を描画する．左上の座標を (x1,y1)，右下の座標を (x2,y2) とする矩形に内接する楕円を描く．
・楕円弧の描画

create arc( x1,y1,x2,y2, style=スタイル,
width=線幅, outline=線の色, ﬁll=塗りの色, start=開始角, extent=弧の開き角 )Canvas オブジェクト上に楕円弧を描画する．左上の座標を (x1,y1)，右下の座標を (x2,y2) とする矩形に内接する楕円の一部を描く．スタイルには円弧の形状（図 63 参照）を指定する．角度の単位は度数法235 の「度」で，回転方向は反時計回りである．

234 HTML5 の CSS における色指定と同様．
235 1 周を 360 度とする角度の表現．

379

図 63: 楕円弧のスタイル
・多角形の描画

create polygon( x1,y1,x2,y2,· · ·,xn,yn, width=線幅, outline=線の色, ﬁll=塗りの色 )Canvas オブジェクト上に多角形を描画する．頂点の座標を (x1,y1),(x2,y2),· · ·, (xn,yn) で与える．
・折れ線の描画

create line( x1,y1,x2,y2,· · ·,xn,yn, width=線幅, ﬁll=線の色 )Canvas オブジェクト上に折れ線を描画する．始点 (x1,y1) ではじまり終点 (xn,yn) で終わる頂点の座標の列(x1,y1),(x2,y2),· · ·,(xn,yn) で与える．
・文字列の描画

create text( x,y, text=文字列, font=フォント指定, anchor=位置の基準, ﬁll=色 )Canvas オブジェクト上に文字列を描画する．描画位置を (x,y) で指定する．この際，表示する文字列全体のどの位置を基準にするかを位置の基準（図 64）で指定する．

図 64: 位置の基準（anchor）
フォント指定に文字列を表示するためのフォント名とサイズなどを指定する．

C.4.1.1

使用できるフォントを調べる方法

使用できるフォント名を調べるためのプログラム例 tk font01.py を示す．
プログラム：tk font01.py
1
2
3
4
5
6
7
8
9

# coding : utf -8
import tkinterimport tkinter . font as tkfont
root = tkinter . Tk ()# Tkinter# フォント関連モジュール# アプリケーションのウィジェット

fntL = list ( tkfont . families ( root ) )# フォントリストの取得
for f in fntL :# フォント名の出力
print ( f )この例のように，tkinter.font モジュールの families 関数を使用するとフォント名の列が得られる．

tk font01.py の実行例
C:￥Users￥katsu ＞ py tk font01.py
System@System
Terminal：（途中省略）：
Highlight LET
Odessa LET
Scruﬀ LET

380

・画像の描画

create image( x,y, image=画像オブジェクト, anchor=位置の基準 )Canvas オブジェクト上に画像オブジェクトを描画する．描画位置を (x,y) で指定する．この際，表示する画像オブ
ジェクトのどの位置を基準にするかを位置の基準（図 64）で指定する．

Tkinter で使用できる画像フォーマットの種類は限られており，多くの画像フォーマットを取り扱うには Pillow ラ
イブラリ（画像処理用ライブラリ）を併用するのが良い．具体的には，Pillow の open 関数で画像を読み込み，それを Pillow の PhotoImage 関数によって Tk で使用できる画像オブジェクトに変換236 する．
（後のサンプルプログラム

tk09.py で使用例を示す）
Canvas 上に各種の描画を行うサンプルプログラム tk09.py を次に示す．
プログラム：tk09.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# coding : utf -8
import tkinterimport PIL . Image as PilImage
import PIL . ImageTk as PilImageTk# Tkinter# Pillowのimageモジュール# PillowのImageTkモジュール# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk09 main window ’ )root . geometry ( ’400 x300 +20+10 ’ )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置

frMain = tkinter . Frame ( root )# GUI構築用のコンテナ
frMain . pack ()# frMainをrootに配置# - - - C a n v a s 描 画 --# Canvasの生成と配置
cv1 = tkinter . Canvas ( frMain , bg = ’# ffffff ’ , width =400 , height =300)
cv1 . pack ( side = ’ top ’ )# 楕円
cv1 . create_oval (10 ,10 ,150 ,100 ,outline = ’# ff0000 ’ , width =10 , fill = ’#00 ff00 ’)# 矩形
cv1 . create_rectangle (170 ,10 ,270 ,100 ,outline = ’#0000 ff ’ , width =10 , fill = ’# ffff00 ’)# 多角形
cv1 . create_polygon (290 ,10 ,380 ,10 ,380 ,100 ,335 ,40 ,290 ,100 ,outline = ’#000000 ’ , width =10 , fill = ’# ff00ff ’)# 折れ線
cv1 . create_line (10 ,120 ,380 ,120 ,10 ,150 ,380 ,150 ,width =10 , fill = ’#00 ffff ’)# 文字列
cv1 . create_text (10 ,170 , text = ’ ゴ シ ッ ク ’ ,font = ’ I P A ゴ シ ッ ク 40 ’ , anchor = ’ nw ’ , fill = ’#000000 ’)
cv1 . create_text (10 ,230 , text = ’ 明 朝 ’ ,font = ’ I P A 明 朝 40 ’ , anchor = ’ nw ’ , fill = ’#000000 ’)# 楕円弧
cv1 . create_arc (120 ,230 ,285 ,330 , style = ’ pieslice ’ ,start =60 , extent =120 , outline = ’#000000 ’ , width =5 , fill = ’# ffff00 ’)# 画像（ Pillowオブジェクトとして読み込み，Tkオブジェクトに変換）
im0 = PilImage . open ( ’ Earth2 . jpg ’)# Pillowオブジェクト
im1 = PilImageTk . PhotoImage ( im0 . resize ((130 ,130)) )# Tkオブジェクト
cv1 . create_image (250 ,160 , image = im1 , anchor = ’ nw ’)# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

このプログラムを実行した例を図 65 に示す．
236 注意） Pillow の PhotoImage 関数で生成した画像オブジェクトにはガベージコレクションが予期せぬタイミングで働くことがある．

特に当該オブジェクトを関数内部のローカル変数（局所変数）に格納した場合において画像オブジェクトが予期せず消滅してしまうことがある．このため，当該関数で生成したオブジェクトは，グローバル変数に格納するなどして，予期せぬ消滅を防ぐ必要がある．

381

図 65: Canvas 上での各種描画

C.4.2

図形の管理

Canvas 上に描く図形には，描画メソッドの実行の際にキーワード引数 ‘tag=タグ名’ を指定することでタグ（識別名）を与えることができ，これを指定して Canvas 上での位置の変更や削除などの操作ができる．例えば，Canvas オ
ブジェクト cv1 上の図形 ‘tg01’ を削除するには

cv1.delete(’tg01’)のように delete メソッドを実行する．また，描画位置を変更するには coords メソッドを用いる．
描画した図形を削除する例をサンプルプログラム tk09-2.py に，位置を移動する例をサンプルプログラム tk09-3.pyにそれぞれ示す．
プログラム：tk09-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# coding : utf -8# モジュールの読込み
import tkinter# Tkinter# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk09 -2 main window ’ )root . geometry ( ’400 x200 +20+10 ’ )root . resizable ( False , False )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置# コールバック：図形追加
def cmdGen ():cv1 . create_oval (10 ,10 ,390 ,130 , tag = ’ tg01 ’ ,outline = ’# ff0000 ’ , width =10 , fill = ’#00 ff00 ’)# コールバック：図形削除
def cmdDel ():cv1 . delete ( ’ tg01 ’)
btnGen = tkinter . Button ( root , text = ’ 追 加 ’ , command = cmdGen )btnGen . pack ( fill = ’x ’ )# 追加ボタン

btnDel = tkinter . Button ( root , text = ’ 削 除 ’ , command = cmdDel )btnDel . pack ( fill = ’x ’ )# 削除ボタン# Canvasの生成と配置
cv1 = tkinter . Canvas ( root , bg = ’# ffffff ’)
cv1 . pack ( fill = ’ both ’ )# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

このプログラムでは「追加」ボタンのクリックにより描画を，「削除」ボタンのクリックにより図形の削除を実行す
る．
（図 66）

382

←削除

追加→

図 66: Canvas 上の図形の追加と削除
プログラム：tk09-3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# coding : utf -8
import tkinter# Tkinter# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk09 -3 main window ’ )root . geometry ( ’350 x250 +20+10 ’ )root . resizable ( False , False )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置# コールバック：図形追加
def cmdUp ():# ↑global x1 , y1 , x2 , y2
y1 -= 5;y2 -= 5
cv1 . coords ( ’ tg01 ’ , x1 , y1 , x2 , y2 )def cmdLeft ():# ←global x1 , y1 , x2 , y2
x1 -= 5;x2 -= 5
cv1 . coords ( ’ tg01 ’ , x1 , y1 , x2 , y2 )def cmdRight ():# →global x1 , y1 , x2 , y2
x1 += 5;x2 += 5
cv1 . coords ( ’ tg01 ’ , x1 , y1 , x2 , y2 )def cmdDown ():# ↓global x1 , y1 , x2 , y2
y1 += 5;y2 += 5
cv1 . coords ( ’ tg01 ’ , x1 , y1 , x2 , y2 )btnUp = tkinter . Button ( root , text = ’ ↑ ’ , command = cmdUp )btnUp . grid ( row =0 , column =1 )# ↑ボタン

btnLeft = tkinter . Button ( root , text = ’ ← ’ , command = cmdLeft )btnLeft . grid ( row =1 , column =0 )# ←ボタンbtnRight = tkinter . Button ( root , text = ’ → ’ , command = cmdRight )btnRight . grid ( row =1 , column =2 )# →ボタン

btnDown = tkinter . Button ( root , text = ’ ↓ ’ , command = cmdDown )btnDown . grid ( row =2 , column =1 )# ↓ボタン# Canvasの生成と配置
cv1 = tkinter . Canvas ( root , bg = ’# ffffff ’ , width =300 , height =190)
cv1 . grid ( row =1 , column =1 )x1 = 125;
y1 = 70x2 = 175;
y2 = 120
cv1 . create_oval ( x1 , y1 , x2 , y2 , tag = ’ tg01 ’ ,outline = ’# ff0000 ’ , width =9 , fill = ’#00 ff00 ’)# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

このプログラムでは「↑」「←」「→」「↓」の各ボタンのクリックにより図形の位置を変更する．
（図 67）

383←初期位置ボタンにより移動→

図 67: Canvas 上での図形の移動

C.5

イベントハンドリング

各種のウィジェットには，受信すべきイベントを登録し，それに対して起動する関数（コールバック関数もしくはイベントハンドラ）を設定することができる．これには次に示す bind メソッドを使用する．
・ウィジェットへのイベントハンドリングの実装

bind( イベントシーケンス, コールバック関数の名前 )イベントシーケンスで示すイベントが発生した際にコールバック関数を起動する．イベントシーケンスは ‘< · · · >’でイベント名を括った記述の連鎖237 である．
キーボードとマウスに関するイベントを表 50 に示す．
表 50: イベントの表記（一部）
キーボード

マウス

表記

意味

表記

意味

KeyPress / Key
KeyRelease

キーの押下
キーの解放

ButtonPress / Button
ButtonRelease
Motion

ボタンの押下ボタンの解放マウスの移動これらイベントには各種のモディファイア（装飾）をつけることができる．
（表 51）

表記

表 51: モディファイア（一部）
意味
表記
意味

Control
Alt

CTRL キー
ALT キーShift

SHIFT キー

Button1
Doubleマウスの左ボタン
ダブルクリック

Button3
Tripleマウスの右ボタン
トリプルクリック

テキストウィジェットとラベルウィジェットに対してイベントハンドリングを実装するプログラムの例 tk10.py を示
す．
プログラム：tk10.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# coding : utf -8
import tkinter# Tkinter# - - - G U I の 構 築 --root = tkinter . Tk ()root . title ( ’ tk10 main window ’ )root . geometry ( ’600 x140 +20+10 ’ )# アプリケーションの最上位ウィジェット
# ウィンドウのタイトル# ウィンドウのサイズと位置

frMain = tkinter . Frame ( root )# GUI構築用のコンテナ
frMain . pack ()# frMainをrootに配置# テキストtxt = tkinter . Text ( frMain , width =40 , height =10 , wrap = ’ none ’)
txt . pack ( side = ’ left ’ )# ラベル

237 複雑なイベントの連鎖をハンドリングできる．詳しくは Tkinter の公式ドキュメントを参照のこと．

384

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

lb1 = tkinter . Label ( frMain , width =300 , height =150 , bg = ’# cccccc ’)
lb1 . pack ( side = ’ left ’ )# - - - イ ベ ン ト ハ ン ド リ ン グ --# コールバック関数
def evAltKey ( ev ):msg = ’ ● A L T キ ー :\ t \t ’ + str ( ev . time ) + ’ ,\t ’ + ev . keysym +\’ ,\t ’ + ev . type
print ( msg )def evKey ( ev ):msg = ’ ● キ ー 入 力 : \ t \t ’ + str ( ev . time ) + ’ ,\t ’ + ev . keysym +\’ ,\t ’ + ev . type
print ( msg )def evSClick1 ( ev ):msg = ’ ● 左 シ ン グ ル ク リ ッ ク : \ t ’’ ,\t ’ + ev . type
print ( msg )def evSClick3 ( ev ):msg = ’ ● 右 シ ン グ ル ク リ ッ ク : \ t ’’ ,\t ’ + ev . type
print ( msg )def evDblClick1 ( ev ):msg = ’ ● 左 ダ ブ ル ク リ ッ ク : \ t ’ +’ ,\t ’ + ev . type
print ( msg )def evDblClick3 ( ev ):msg = ’ ● 右 ダ ブ ル ク リ ッ ク : \ t ’ +’ ,\t ’ + ev . type
print ( msg )+ str ( ev . time ) + ’ ,\t ’ + str (( ev .x , ev . y )) +\+ str ( ev . time ) + ’ ,\t ’ + str (( ev .x , ev . y )) +\str ( ev . time ) + ’ ,\t ’ + str (( ev .x , ev . y )) +\str ( ev . time ) + ’ ,\t ’ + str (( ev .x , ev . y )) +\def evDrag1 ( ev ):msg = ’ ● 左 ド ラ ッ グ : \ t \t ’ + str ( ev . time ) + ’ ,\t ’ + str (( ev .x , ev . y )) +\’ ,\t ’ + ev . type
print ( msg )def evDrag3 ( ev ):msg = ’ ● 右 ド ラ ッ グ : \ t \t ’ + str ( ev . time ) + ’ ,\t ’ + str (( ev .x , ev . y )) +\’ ,\t ’ + ev . type
print ( msg )# イベント処理の登録
txt . bind ( ’ < Alt - Key > ’ , evAltKey )txt . bind ( ’ < Key > ’ , evKey )lb1 . bind ( ’ < Button -1 > ’ , evSClick1 )lb1 . bind ( ’ < Button -3 > ’ , evSClick3 )lb1 . bind ( ’ < Double - Button -1 > ’ , evDblClick1 )lb1 . bind ( ’ < Double - Button -3 > ’ , evDblClick3 )lb1 . bind ( ’ < Button1 - Motion > ’ , evDrag1 )lb1 . bind ( ’ < Button3 - Motion > ’ , evDrag3 )# 左ボタンでドラッグ# 右 ボ タ ン で ド ラ ッ グ （ Windows）# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

このプログラムを実行すると，図 68 のようなウィンドウが表示される．59,60 行目でテキストウィジェットオブジェ
クト txt に対してキーボードイベントのハンドリングを設定している．62〜68 行目ではラベルウィジェット lb1 に対してマウスイベントのハンドリングを設定している．
キーボード入力やマウス操作を行うと，それを標準出力に報告する．実行例を次に示す．
実行例● キー入力:● キー入力:● ALT キー:
● 左シングルクリック:● 左ドラッグ:● 左ドラッグ:● 左ドラッグ:

141868953,
141879187,
141879296,
141883453,
141883656,
141883671,
141883687,

a,2
Alt L,
2x,
2(19, 22),
4(20, 23),
6(20, 24),
6(21, 24),6385

図 68: キーボードとマウスに反応するアプリケーション

コールバック関数は引数としてイベントオブジェクトを受け取る．このオブジェクトのプロパティにイベントに関する各種の情報が保持されている．
（表 52）

C.5.1

表 52: イベントオブジェクトのプロパティ（一部）
表記
意味

表記

意味

widgettype

当該ウィジェット
イベントのタイプ

time

時刻

x
x rootウィジェット上でのマウスの x 座標
ウィンドウ上でのマウスの x 座標yy rootウィジェット上でのマウスの y 座標
ウィンドウ上でのマウスの y 座標

keycodeキーコード

keysymキーシンボル

時間を指定した関数の実行指定した時間が経過した後238 でコールバック関数を呼び出すには．after メソッドを使用する．このメソッドはウィジェットオブジェクトに対して実行する．
・タイマー

after( 経過時間, コールバック関数の名前 )経過時間はミリ秒の単位の数値で与える．コールバック関数は引数を取らない．

after メソッドを応用して時計を実現したプログラムの例 tk11.py を示す．
プログラム：tk11.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# coding : utf -8
import tkinterfrom datetime import datetime# Tkinter# datetime# - - - G U I の 構 築 --root = tkinter . Tk ()# アプリケーションの最上位ウィジェット
root . title ( ’ tk11 main window ’ )# ウィンドウのタイトル
root . geometry ( ’280 x60 +20+10 ’ ) # ウ ィ ン ド ウ の サ イ ズ と 位 置
frMain = tkinter . Frame ( root )# GUI構築用のコンテナ
frMain . pack ()# frMainをrootに配置# ラベル
lb1 = tkinter . Label ( frMain , width =300 , height =150 ,bg = ’# dddddd ’ , font = ’ I P A ゴ シ ッ ク 18 ’)
lb1 . pack ( side = ’ top ’ )# - - - イ ベ ン ト ハ ン ド リ ン グ --# コールバック関数
def evFunc1 ( ):d = datetime . now ()msg = str ( d . year ) + ’ 年 ’ + str ( d . month ) + ’ 月 ’ + str ( d . day ) + ’ 日 \ n ’ +\str ( d . hour ) + ’ 時 ’ + str ( d . minute ) + ’ 分 ’ + str ( d . second ) + ’ 秒 ’
lb1 [ ’ text ’] = msg
lb1 . after (1000 , evFunc1 )238 タイマーイベントと呼ばれることが多い

386

28
29
30
31

lb1 . after (500 , evFunc1 )# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

このプログラムを実行すると，図 69 のようなウィンドウが表示されて時刻を知らせる．

図 69: 時計のアプリケーション

C.6

複数のウィンドウの表示

Tk() の実行によりアプリケーションの最上位のウィジェットを生成し，それを当該アプリケーションのメインウィ
ンドウとするが，これとは別のウィンドウを生成するには Toplevel() を実行する．2 つ目のウィンドウを生成して表示するプログラムの例を tk12.py に示す．
プログラム：tk12.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# coding : utf -8
import tkinter# Tkinter# - - - メ イ ン ウ ィ ン ド ウ --root = tkinter . Tk ()root . title ( ’ tk12 main window ’ )root . geometry ( ’280 x60 +20+10 ’ )# メインウィンドウのタイトル# メインウィンドウのサイズと位置

lb1 = tkinter . Label ( root , text = ’ メ イ ン ウ ィ ン ド ウ ’ )lb1 . pack ( fill = ’ both ’ , expand =1 )# - - - サ ブ ウ ィ ン ド ウ --subW = tkinter . Toplevel ()subW . title ( ’ tk12 sub window ’)
subW . geometry ( ’280 x50 +120+110 ’ )# サブウィンドウのタイトル# サブウィンドウのサイズと位置

lb2 = tkinter . Label ( subW , text = ’ サ ブ ウ ィ ン ド ウ ’ )lb2 . pack ( fill = ’ both ’ , expand = True )# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

このプログラムを実行した例を図 70 に示す．

図 70: 複数のウィンドウ
このプログラムはメインウィンドウを閉じると，サブウィンドウ（プログラム中の subW）を含めて全て終了する．

387

C.7

ディスプレイやウィンドウに関する情報の取得

Tk() の実行によって生成したウィンドウ（最上位ウィジェット）からは様々な情報が取得できる．最上位ウィジェッ
ト root がある場合に，それに対して実行するメソッドと得られる値を表 53 に示す．

メソッド

表 53: ディスプレイやウィンドウに関する情報を取得するメソッド
得られる値
メソッド
得られる値

winfo screenwidth()
winfo width()
winfo x()

ディスプレイの横幅
ウィンドウの横幅
ウィンドウの横位置

winfo screenheight()
winfo height()
winfo y()ディスプレイの高さ
ウィンドウの高さ
ウィンドウの縦位置

スクリーンのサイズ，ウィンドウのサイズと位置を取得するサンプルプログラム tk13.py を示す．
プログラム：tk13.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# coding : utf -8
import tkinter# Tkinterの読み込み# - - - コ ー ル バ ッ ク 関 数 --def cmdConfig ( ev ):w = root . winfo_width ()# 横幅の取得
h = root . winfo_height ()# 高さの取得x = root . winfo_x ()# ウィンドウの横位置
y = root . winfo_y ()# ウィンドウの縦位置
msg = str ( w ) + ’x ’ + str ( h ) + ’+ ’ + str ( x ) + ’+ ’ + str ( y )lb1 [ ’ text ’] = msg# - - - G U I の 構 築 --root = tkinter . Tk ()# アプリケーションの最上位ウィジェット
root . title ( ’ tk13 main window ’ )# ウィンドウのタイトル
root . geometry ( ’400 x100 +20+10 ’ )# ウィンドウのサイズと位置
root . bind ( ’ < Configure > ’ , cmdConfig )# 配置テスト用のラベル
lb1 = tkinter . Label ( root , text = ’ ウ ィ ン ド ウ サ イ ズ ’ ,font = ’ I P A ゴ シ ッ ク 18 ’ ,bg = ’#000000 ’ , fg = ’# ffffff ’ )lb1 . pack ( fill = ’ both ’ , expand = True )W = root . winfo_screenwidth ()H = root . win fo _s cr ee nh ei gh t ()print ( ’ 画 面 サ イ ズ ： ’ , W , ’x ’ , H )# スクリーンの幅# スクリーンの高さ# - - - ア プ リ ケ ー シ ョ ン の 起 動 --root . mainloop ()# イベントループ

ウィンドウサイズの変更などはイベント ‘Configure’ としてハンドリング（17 行目）している．
プログラムを実行して，表示されたウィンドウの位置とサイズを変更する様子を図 71 に示す．

図 71: ウィンドウの移動とサイズ変更に伴う情報の取得

388

C.8

メッセージボックス（messagebox）「ダイアログボックス」と呼ばれることの多い UI が Tkinter でもメッセージボックス（messagebox）という形で提供されている．Tkinter のメッセージボックスは tkinter.messagebox モジュール下の関数として提供されている．各種
メッセージボックスを表示するための関数の名称と表示例，ボタン操作の結果得られる関数の戻り値を図 72 に示す．

askyesno「はい/いいえ」→ True/False

askretrycancel「再試行/キャンセル」→ True/False

askokcancel「ＯＫ/キャンセル」→ True/False

showerror「ＯＫ」→’ok’

askquestion「はい/いいえ」→’yes’/’no’showwarning「ＯＫ」→’ok’

ボタン操作に応じて真理値（True/False）や文字列の戻り値が得られる．

showinfo「ＯＫ」→’ok’

図 72: 各種メッセージボックス：

表示するための関数の名称とボタン操作に対する戻り値

図 72 のようなメッセージボックスを表示するサンプルプログラムを tk14.py に示す．
プログラム：tk14.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# coding : utf -8
import tkinterfrom tkinter import messagebox# - - - コ ー ル バ ッ ク 関 数 --def cb_yesno ():r = messagebox . askyesno (title = ’ askyesno ’ , message = ’ こ れ は 好 き で す か ？ ’ )vEnt . set ( str ( r )+ ’ : ’+ str ( type ( r )) )def cb_retrycancel ():r = messagebox . askretrycancel (title = ’ askretrycancel ’ , message = ’ ど う し ま す か ？ ’ )vEnt . set ( str ( r )+ ’ : ’+ str ( type ( r )) )def cb_question ():r = messagebox . askquestion (title = ’ askquestion ’ , message = ’ こ れ は 好 き で す か ？ ’ )vEnt . set ( str ( r )+ ’ : ’+ str ( type ( r )) )def cb_okcancel ():r = messagebox . askokcancel (title = ’ askokcancel ’ , message = ’ 実 行 し て い い で す か ？ ’ )vEnt . set ( str ( r )+ ’ : ’+ str ( type ( r )) )def cb_showerror ():r = messagebox . showerror (title = ’ showerror ’ , message = ’ エ ラ ー が 発 生 し ま し た ！ ’ )vEnt . set ( str ( r )+ ’ : ’+ str ( type ( r )) )

389

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

def cb_showwarning ():r = messagebox . showwarning (title = ’ showwarning ’ , message = ’ 警 告 メ ッ セ ー ジ ！ ’ )vEnt . set ( str ( r )+ ’ : ’+ str ( type ( r )) )def cb_showinfo ():r = messagebox . showinfo (title = ’ showinfo ’ , message = ’ メ ッ セ ー ジ で す ． ’ )vEnt . set ( str ( r )+ ’ : ’+ str ( type ( r )) )def cb_close ():r = messagebox . askokcancel (title = ’ askokcancel ’ , message = ’ 終 了 し よ う と し て い ま す ！ ’ )print ( ’ 戻 り 値 : ’ , r , ’: ’ , type ( r ))if r :
root . destroy ()# - - - ウ ィ ン ド ウ の 構 築 --root = tkinter . Tk ()root . title ( ’ tk14 ’)root . geometry ( ’350 x300 +20+10 ’)# 各種メッセージボックスを表示するボタン
b1 = tkinter . Button ( root , text = ’ a s k y e s n o の テ ス ト ’ , command = cb_yesno )b1 . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )b2 = tkinter . Button ( root , text = ’ a s k r e t r y c a n c e l の テ ス ト ’ , command = cb_retrycancel )b2 . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )b3 = tkinter . Button ( root , text = ’ a s k q u e s t i o n の テ ス ト ’ , command = cb_question )b3 . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )b4 = tkinter . Button ( root , text = ’ a s k o k c a n c e l の テ ス ト ’ , command = cb_okcancel )b4 . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )b5 = tkinter . Button ( root , text = ’ s h o w e r r o r の テ ス ト ’ , command = cb_showerror )b5 . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )b6 = tkinter . Button ( root , text = ’ s h o w w a r n i n g の テ ス ト ’ , command = cb_showwarning )b6 . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )b7 = tkinter . Button ( root , text = ’ s h o w i n f o の テ ス ト ’ , command = cb_showinfo )b7 . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )# エントリvEnt = tkinter . StringVar ()vEnt . set ( ’ こ こ に 戻 り 値 が 表 示 さ れ ま す ’ )e1 = tkinter . Entry ( root , textvariable = vEnt )e1 . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )# ラベル
lb = tkinter . Label ( root , text = ’ ウ ィ ン ド ウ を 閉 じ て み て く だ さ い ． ’ ,font = ’18 ’)
lb . pack ( side = ’ top ’ , fill = ’ both ’ , expand = True )# - - - ウ ィ ン ド ウ を 閉 じ る 際 の コ ー ル バ ッ ク 設 定 --root . protocol ( ’ WM_DELETE_WINDOW ’ , cb_close )# - - - イ ベ ン ト ル ー プ --root . mainloop ()このプログラムを実行すると図 73 のようなウィンドウが表示される．
ウィンドウ内のボタン操作に対するコールバック処理として，各種のメッセージボックスを表示するための関数を呼び出している．メッセージボックスのボタン操作に対する関数の戻り値とそのデータ型をウィンドウ内の Entry（テキストボックス）に表示する．

C.8.1

アプリケーション終了のハンドリング

通常の場合，GUI アプリケーションはウィンドウを閉じると終了するが，ウィンドウを閉じる操作に対するコー
ルバック処理を設定することができる．先のサンプルプログラム tk14.py の 80 行目で，ウィンドウ root に対して

390

図 73: アプリケーションのメインウィンドウ

protocol メソッドを実行しているが，その際にハンドリングのためのコールバック関数 cb close（34〜39 行目で定義）を設定している．これにより，ウィンドウを閉じる操作をするとメッセージボックスを表示して，本当に終了するか否かの選択をユーザに促す．

tk14.py の 39 行目にあるように，ウィンドウに対して destroy メソッドを実行すると当該ウィンドウが閉じられる．

C.9

ウィジェットの親，子を調べる方法

あるウィジェットが属する上位のウィジェット（親ウィジェット）は，当該ウィジェットの master 属性が保持している．また，あるウィジェットが配下に持つウィジェットは，当該ウィジェットに winfo children メソッドを実行することでリストの形で得られる．

tkinter.Tk() で作成した最上位のウィジェットは親ウィジェットを持たず，master 属性を参照すると None（ヌルオ
ブジェクト）となる．また，最下位のウィジェット（配下に子を持たないウィジェット）に対して winfo children メソッ
ドを実行すると空リスト [ ] が得られる．
【サンプルプログラム】
次に示すサンプルプログラムで定義されている関数 dispWtree は，第一引数にウィジェットのリストを，第二引数に 0 を与えて実行するとウィジェットの階層関係を表示する．
プログラム（一部）：これを tk08.py の末尾239 に追加して実行する
1
2
3
4
5
6
7
8

def dispWtree ( wl , n ):# ウ ィ ジ ェ ッ ト リ ス ト wl の 階 層 を 表 示 す る 関 数
fl = ’ ’*( n *4)
for w in wl :print ( fl , type ( w ) , ’: ’ , w )wl2 = w . winfo_children ()dispWtree ( wl2 , n +1)
dispWtree ([ root ] ,0)# 最 上 位 の ウ ィ ジ ェ ッ ト root 以 下 の 階 層 を 調 べ る

これを先に示したプログラム tk08.py（p.378）の末尾に追加して実行すると，メニュー操作「Quit」で終了する際に，次のようにウィジェット階層を表示する．
実行結果の例．
<class ’tkinter.Tk’> : .
<class ’tkinter.Frame’> : .!frame<class ’tkinter.Label’> : .!frame.!label<class ’tkinter.Menu’> : .!menu<class ’tkinter.Menu’> : .!menu.!menu<class ’tkinter.Menu’> : .!menu.!menu2

ウィジェットの種類と共に root 以下の階層関係が表示されている．

239 実行時にエラーが出る場合は，関数 dispWtree の定義の記述の部分を「root.mainloop()」の直前に挿入されたい．

391

D

cursesOS のコマンド操作を行うターミナルウィンドウなどのキャラクタ端末では，キーボードによる文字の入力と，ディ
スプレイへの文字の出力を基本とする CUI 240 （Character User Interface）である．この形式のユーザインターフェー
スでは，文字は左側から右側にかけて順に表示され，改行処理によって次の（下の）行の左端に表示位置が移動し，キーボードからの入力位置もこの順序に従う．標準入出力も基本的にこの形式に従っており，通常の CUI では，ター
ミナルウィンドウ上の指定した任意の位置に文字を出力することはできない．

UNIX 系 OS 241 では，キャラクタ端末における入出力のための curses ライブラリが C 言語のために用意されている．またこのライブラリを応用した，Python 言語上で使える同名のライブラリが標準ライブラリとして提供されている．curses ライブラリを使用することで，通常の CLI の制約を受けない画面入出力が実現できる．例えば次の例

curses01.py の実行の様子について考える．
プログラム：curses01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# coding : utf -8
import curses
import time
stdscr = curses . initscr ()curses . curs_set (0)stdscr . clear ()# 初 期 化 処 理 ： 画 面 を 指 す windowsオブジェクトが得られる．
# カーソル表示を無効化# 画面消去for y in range (9 , -1 , -1):
for x in range (29 , -1 , -1):
stdscr . addch (y , x , ’X ’)
stdscr . refresh ()time . sleep (0.02)
curses . curs_set (1)# 指定された位置（ y行x列）に文字を表示# 画面を更新# 少し待つ# カーソル表示を有効化

stdscr . addstr (11 ,0 , ’ 何 か キ ー を 押 し て く だ さ い ． ’ )stdscr . getch ()# ユーザーの入力を待つ
curses . endwin ()# 終了処理このプログラムをターミナルウィンドウで実行すると，画面の表示# 終了待機メッセージ

すとプログラムが終了し，ターミナルウィンドウは，プログラム開XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

始前の状態に戻る．

何かキーを押してください．

が一旦消去され，右のような表示が刻々と出来上がる．その際，画面の右下から左上にかけて ’X’ が表示されることが確認できる．
最後に「何かキーを押してください．
」と表示され，何かキーを押（プログラムの詳細は後に解説する）

curses01.py を実行したところ

このプログラムの実行で確認できるように，curses の機能によって，指定した任意の画面位置に文字を表示することができる．また，プログラム実行中の画面状態は通常のターミナルウィンドウとは別の状態（curses モード）であり，プログラム終了後は開始前の画面の状態が復元される．
注意）

Windows 環境の Python には curses が標準添付されていないが，サードパーティ242 が，ほぼ同じ機能のライブラ
リを windows-curses と名付けて開発して公開しており，それを pip などで Python 処理系にインストールすると，他のプラットフォームと同様の形で curses を import して利用することができる．

Python の curses ライブラリに関して，本書では最も基本的な使用方法について解説する．詳細に関しては，Pythonの公式インターネットサイトや curses の技術資料などを参照のこと．
240 CLI（Command Line Interface）とも呼ばれる．
241 Linux や Apple 社の macOS などが代表的．
242 https://pypi.org/project/windows-curses/

392

D.1

curses 使用の流れ

curses による画面制御（curses モード）は初期化関数 initscr の実行から始まる．
書き方：

initscr()

この関数は window クラスのオブジェクトを返す．以後そのオブジェクトを用いて画面に対する入出力を行う．

curses モードを終了するには endwin 関数を実行する．
書き方：

endwin()この関数を実行すると，画面は通常の状態に戻る．

wrapper 関数を用いると，curses モードの初期化と終了の処理を自動化できる．
書き方：

wrapper( コールバック関数 )initscr 関数を自動的に実行して，得られた window オブジェクトを「コールバック関数」の引数に渡して実行する．
「コールバック関数」が終了する際に endwin 関数を自動的に実行する．
「コールバック関数」の戻り値は wrapper 関数の戻り値となる．
画面のサイズ（行，列）は，window オブジェクトに対して getmaxyx メソッドを実行することで取得できる．
書き方：

window オブジェクト.getmaxyx()「window オブジェクト」の画面のサイズを，(行, 列) の形式のタプルとして返す．

D.2

画面に対する出力，制御

画面上の指定した位置に 1 つの文字を表示するには，window オブジェクト. に対して addch メソッドを実行する．
書き方：

window オブジェクト.addch( y, x, 文字 )画面の「y」行「x」列の位置に「文字」を表示する．この場合の「文字」は 1 バイトで表現される 1 文字（ASCII 文字など）であり，マルチバイト文字や文字列を表示する場合は次に示す addstr メソッドを使用する．
書き方：

window オブジェクト.addstr( y, x, 文字列 )addch，addstr には 4 番目の引数として色の設定を与えることができる．これに関しては後に解説する．
注意）curses はマルチバイト文字には十分に対応できていないので可能な限り ASCII 文字を使用すること．
注意）画面の最も右下の位置に文字を描画しようとするとエラー（curses.error）が発生する．
（試されたい）D.2.1

色の設定と適用

curses では色ペアという概念で文字に着色する．これは前景色と背景色を組にした情報であり，色ペアは番号を与えて管理する．また curses では色の管理と適用をするにあたり，start color 関数で初期化しておく必要243 がある．
書き方：

start color()

この後，init pair 関数によって，色ペアを設定する．
書き方：

init pair( 番号, 前景色, 背景色 )「番号」を付けて「前景色」と「背景色」の組を登録する．
「番号」は 1〜255 の整数である．
「前景色」，「背景色」に指定する値は curses ライブラリに定数（表 54）として定義されている．
表 54: curses の色の定数（一部）
義
値
色
定

色

定

黒

COLOR BLACK

0

白COLOR WHITE

7

赤COLOR RED

4

シアン

COLOR CYAN

3緑COLOR GREEN

2

マゼンタ

COLOR MAGENTA

5青COLOR BLUE

1

黄COLOR YELLOW

6243 端末環境によってはこの処理が必要ない場合もある．

393

義

値

登録した色ペアは color pair 関数で呼び出す．
書き方：

color pair( 番号 )登録された「番号」の色ペアの情報を取り出し，それが意味する整数値を返す．この値を addch，addstr 関数の第 4引数に与えることで表示する文字に着色することができる．
画面全体の基本的な前景色と背景色を設定するには window オブジェクトに対して bkgd メソッドを実行する．
書き方：

window オブジェクト.bkgd( 背景文字, color pair(番号) )画面の背景を「背景文字」で満たすが，必要ない場合は半角の空白文字（ASCII コード 32）を 1 つを与える．

D.2.2

装飾の適用

表 55 に curses における装飾の定義を示す．

定

義

表 55: curses の文字装飾の定数（一部）
装 飾
定 義
装

飾

A BOLD太字

A UNDERLINE

下線

A REVERSE

反転表示

A BLINK

点滅

A DIM

薄暗い表示

A STANDOUT

強調表示

表 55 の定義と color pair 関数の戻り値とのビット論理和を取ったものを addch，addstr 関数の第 4 引数に与えることで，表示する文字に着色と装飾を施すことができる．

D.2.3

テキストカーソルの設定

文字入力の際に入力位置を示すテキストカーソル244 の状態を設定するには curs set 関数を用いる．
書き方：

curs set( 状態 )「状態」は整数値（下記）で与える．

0: 非表示，D.2.4

1: 通常の（標準的な）カーソル，

2: 強く目立つカーソル

画面の消去，更新

window オブジェクトに対して clear メソッドを実行することで，画面の表示内容を消去できる．
書き方：

window オブジェクト.clear()window オブジェクトに対して refresh メソッドを実行することで，画面の表示内容を更新できる．
書き方：

window オブジェクト.refresh()

この処理は，画面の初期化や，ユーザによる入力処理の後に実行すると良い．また，addch，addstr を多数実行した後に実行すると良い．このメソッドは画面更新の必要に応じて実行する．

D.2.5

警告表現

ﬂash 関数で画面を瞬かせることができる．
書き方：

ﬂash()

beep 関数で警告音を出すことができる．
書き方：

beep()

文字に着色と装飾を施して表示し，終了時に警告表現を出す例を curses02.py に示す．

244 キャレットともいう．

394

プログラム：curses02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# coding : utf -8
import curses# コールバック関数
def cursesMode ( stdscr ):H , W = stdscr . getmaxyx ()curses . curs_set (0)curses . start_color ()# スクリーンサイズの取得# カーソル表示を無効化# 色制御機能を初期化# 色ペアの設定
番号
curses . init_pair ( 1 ,curses . init_pair ( 2 ,curses . init_pair ( 3 ,curses . init_pair ( 4 ,curses . init_pair ( 5 ,curses . init_pair ( 6 ,curses . init_pair ( 7 ,curses . init_pair ( 8 ,前景色curses . COLOR_BLACK ,curses . COLOR_RED ,curses . COLOR_GREEN ,curses . COLOR_BLUE ,curses . COLOR_WHITE ,curses . COLOR_CYAN ,curses . COLOR_MAGENTA ,curses . COLOR_YELLOW ,stdscr . clear ()stdscr . refresh ()# 画面消去# 画面更新（念の為）# 文字列描画（着色）stdscr . addstr ( 1 , 1 ,stdscr . addstr ( 3 , 1 ,stdscr . addstr ( 3 , 9 ,stdscr . addstr ( 3 , 17 ,stdscr . addstr ( 3 , 25 ,stdscr . addstr ( 5 , 1 ,stdscr . addstr ( 5 , 9 ,stdscr . addstr ( 5 , 17 ,stdscr . addstr ( 5 , 25 ,# 文字列描画（装飾）stdscr . addstr ( 7 , 1 ,stdscr . addstr ( 7 , 11 ,stdscr . addstr ( 7 , 21 ,stdscr . addstr ( 9 , 1 ,stdscr . addstr ( 9 , 11 ,stdscr . addstr ( 9 , 21 ,stdscr . refresh ()#背景色
curses . COLOR_WHITE
curses . COLOR_WHITE
curses . COLOR_WHITE
curses . COLOR_WHITE
curses . COLOR_BLACK
curses . COLOR_WHITE
curses . COLOR_WHITE
curses . COLOR_WHITE

f ’ ScreenHeight { H } , S c reenWidth { W } ’ )’ BLACK ’, curses . color_pair (1) )’ RED’, curses . color_pair (2) )’ GREEN ’, curses . color_pair (3) )’ BLUE’, curses . color_pair (4) )’ WHITE ’, curses . color_pair (5) )’ CYAN’, curses . color_pair (6) )’ MAGENTA ’ , curses . color_pair (7) )’ YELLOW ’, curses . color_pair (8) )’ BOLD’, curses . A_BOLD )’ UNDERLINE ’ , curses . A_UNDERLINE )’ REVERSE ’, curses . A_REVERSE )’ BLINK’, curses . A_BLINK )’ DIM’, curses . A_DIM )’ STANDOUT ’, curses . A_STANDOUT )画面更新（念の為）# 終了処理curses . curs_set (2)# カーソル表示を強調
stdscr . addstr ( 11 , 1 , ’ Press any key to end : ’ )stdscr . getch ()# キーの入力待ち
curses . flash ()# 画面を瞬かせる
curses . beep ()# ビープ音curses . wrapper ( cursesMode )# コールバック関数を実行

このプログラムを実行した際のコンソールの表示を図 74 に例示する．

図 74: curses02.py を実行したところ
この後，何かキーを押すと，警告表現を出してプログラムが終了する．
注意）着色や装飾の効果，警告表現は，実行する環境によって異なることに注意すること．

395

)
)
)
)
)
)
)
)

D.3

キーボード入力

window オブジェクトに対して getch メソッドを実行することでキーボードの入力を受け付けることができる．
書き方：

window オブジェクト.getch()

キーが押されるまで待ち，押されたキーのコード（整数値）を返す．このメソッドの動作はデフォルトでは同期入力（ブロッキングモード）であるが，window オブジェクト.nodelay(True)を実行することで非同期入力245 （ノンブロッキングモード）となる．非同期入力の状態で何もキーが押されていな
いとき，getch メソッドは -1 を返す．非同期入力の getch メソッドを同期入力に戻すには，nodelay メソッドの引数に False を渡して実行する．

getch メソッドが返すキーコードは，基本的にはその文字の ASCII コードであるが，カーソルキーやファンクショ
ンキーなどの制御用のキーが押された場合も様々な値を返す．それらの多くは curses の定数として定義されており，その一部を表 56 に示す．詳しくは Python の公式インターネットサイトなどを参照のこと．

定義

表 56: curses のキーコードの定義（一部）
キー
値
定 義
キー

値

KEY HOME

HOME

262

KEY PPAGE

PageUp339

KEY END

END

358

KEY NPAGE

PageDown

338

KEY DOWN↓

258

KEY UP↑

259

KEY LEFT←260

KEY RIGHT→

261

KEY DC

Delete330

KEY IC

Insert331

KEY Fnファンクションキー n．F1〜F12

getch メソッドと同様の機能を持つ getkey メソッドもある．
書き方：

window オブジェクト.getkey()

キーの押下を受け付け，そのキーに対応する値を str 型で返す．

D.3.1

文字列の入力window オブジェクトに対して getstr メソッドを実行することで，文字列の入力を受け付けることができる．このメソッドによる入力は Enter キーで終了する．
書き方：

window オブジェクト.getstr()

入力された文字列を bytes 型で返す．このメソッドには，入力中の編集機能はなく，BackSpace などの入力もそのま
まデータとして戻り値の bytes オブジェクトの中に含まれる．
注意）getstr はマルチバイト文字の入力に完全には対応していないので注意すること．

getstr メソッドの入力中は，押下したキーの文字は画面にはエコー（表示）されない．入力時のエコーを有効（エコーモード）にするには echo 関数を実行する．
書き方：

echo()

エコーモードを解除するには noecho 関数を実行する．
書き方：

D.3.2

noecho()raw モード入力

raw 関数を実行すると，ウィンドウが raw モードになり， CTRL キーと他のキーの組み合わせなどによる制御が無効になる246 ．押下されたキーを純粋に受け取る際に raw モードが有用である．
書き方：

raw()

245 キーが押されているかどうかに関わらず，getch メソッドは値を返して終了することを意味する．
246 無効にならない制御もあるので注意すること．例えば，多くの環境で F11 の機能は無効にならない．

396

raw モードに移行する．この後で通常の状態に戻すには noraw 関数を実行する．
書き方：

noraw()

参考）raw モード以外にも様々な入力モードがある．詳しくは Python の公式インターネットサイトや，curses に関する技術資料を参照のこと．

D.4

ウィンドウのリサイズ

curses モードでプログラムを実行中，ウィンドウサイズが変えられると getch メソッドが KEY RESIZE（整数値:546）
を返す．

getch メソッドを応用したサンプルプログラム curses03.py を示す．このプログラムは，カーソルキー（矢印キー）
や HOME キーで画面に軌跡を描くものである．また，画面のリサイズにも対応している．
プログラム：curses03.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# coding : utf -8
import curses , time
# コールバック関数
def cursesMode ( stdscr ):curses . raw ()H , W = stdscr . getmaxyx ()curses . curs_set (0)curses . start_color ()

#
#
#
#

rawモードに入る
スクリーンサイズの取得
カーソル表示を無効化
色制御機能を初期化# 色ペアの設定
番号
前景色
curses . init_pair ( 1 , curses . COLOR_BLACK ,curses . init_pair ( 2 , curses . COLOR_WHITE ,背景色
curses . COLOR_WHITE )curses . COLOR_BLACK )stdscr . bkgd ( ’ ’, curses . color_pair (1) )stdscr . clear ()# 画面消去stdscr . refresh ()# 画面更新（念の為）# 画面の背景の設定

y = H // 2;
x = W // 2
# 位置をホームに初期化
stdscr . addch ( y , x , ’ ’, curses . color_pair (2))
stdscr . addstr ( H -1 , 1 , f ’({ y } ,{ x }) , Press [ ESC ] key to end ’ )while True :k = stdscr . getch ()if k == 27:# ESC : 終 了
breakelif k == curses . KEY_HOME : # 初 期 位 置 に 戻 る
y = H // 2;
x = W // 2
elif k == curses . KEY_DOWN : # ↓y += 1
if y >= H :curses . flash ();curses . beep ()y = H - 1
elif k == curses . KEY_UP :# ↑y -= 1
if y < 0:curses . flash ();curses . beep ()y = 0
elif k == curses . KEY_RIGHT : # →x += 1
if x >= W :curses . flash ();curses . beep ()x = W - 1
elif k == curses . KEY_LEFT : # ←x -= 1
if x < 0:curses . flash ();curses . beep ()x = 0
elif k == curses . KEY_RESIZE :# 画面リサイズ
stdscr . clear ()H , W = stdscr . getmaxyx ()stdscr . addstr (1 ,1 , f ’ Window size is changing .({ k }) ’)stdscr . addstr (2 ,1 , f ’ Height :{ H } , Width :{ W } ’)stdscr . refresh ()

397

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

y = H // 2;
x = W // 2
if y == H -1 and x == W -1:# 描いてはいけない座標
curses . flash ();curses . beep ();stdscr . addstr ( H -2 , 1 , f ’ That position is untouchable !. ’ )stdscr . refresh ()time . sleep (2)stdscr . clear ();stdscr . refresh ()x = W // 2
y = H // 2;
stdscr . addch ( y , x , ’ ’, curses . color_pair (2))
stdscr . addstr ( H -1 , 1 , f ’({ y } ,{ x }) , Press [ ESC ] key to end ’ )# 終了処理curses . curs_set (1)curses . noraw ()# カーソル表示# rawモード解除

curses . wrapper ( cursesMode )# コールバック関数を実行

このプログラムを起動すると画面が白地になり，中央にスペース（黒）が表示され，それがカーソルキー ↑ , ↓ , ← , →に合わせて移動して軌跡を描く．ウィンドウサイズを変更すると画面がクリアされ，画面左上に変更状況が表示（図75）される．

図 75: curses03.py を実行したところ

getstr メソッドで文字列を bytes 型のデータとして取得する例を curses04.py に示す．
プログラム：curses04.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# coding : utf -8
import curses# コールバック関数
def cursesMode ( stdscr ):curses . echo ()# エコーを有効化
stdscr . clear ()# 画面消去stdscr . refresh ()# 画面更新（念の為）while True :stdscr . addstr (1 ,1 ," Input String ( ’ exit ’ to end ): ")stdscr . clrtoeol ()# 右側をクリアs = stdscr . getstr (). decode ( ’ utf -8 ’)if s == ’ exit ’: # 終 了
breakelse :
stdscr . addstr (2 ,1 , ’ ’);
stdscr . clrtoeol ()# 行をクリアstdscr . addstr (2 ,1 , f " > ’{ s } ’")stdscr . refresh ()curses . noecho () # エ コ ー を 無 効 に す る
curses . wrapper ( cursesMode )# コールバック関数を実行

このプログラム中にある clrtoeol メソッドは，現在位置からスクリーンの右端までの行内容をクリア（消去）するものである．
書き方：

window オブジェクト.clrtoeol()

curses04.py を実行すると，
398

Input String(’exit’ to end):と表示され，文字列入力を受け付ける．これに対して

Input String(’exit’ to end):

Hello! Enterと入力すると，画面の表示がInput String(’exit’ to end):> ’Hello!’となる．また，exit Enter と入力するとプログラムが終了する．

画面の内容の採取

D.5

画面上の指定した位置の 1 文字分の情報を取得するには，window オブジェクトに対して inch メソッドを実行する．
書き方：

window オブジェクト.inch( y, x )「y」行「x」列の位置の 1 文字分の情報を，文字コード，色，装飾などを含んだ属性付き文字データとして返す．これは 32 ビットの整数値であり，下位 8 ビットが文字コード，それより上位が，色や装飾などを表す属性データである．

D.5.1

文字コードや属性情報の採取

属性付き文字データ（inch メソッドの戻り値）から文字コードのみを取得するには属性付き文字データ & 0xFFを算出し，属性データのみを取得するには属性付き文字データ & ˜0xFFを算出する．
上の方法で得られた属性データの中の，色ペア番号の部分を意味するビットマスクとして A COLOR が定義されている．従って，これと属性データの論理積を取った後，右に 24 ビットシフトすると色ペアの番号が得られる．
書き方：(属性データ & curses.A COLOR) >> 24

また，強調，下線，反転の属性部分を意味するビットマスクが A BOLD，A UNDERLINE，A REVERSE として定義されており，次のような記述によって，各種装飾の状態を真理値（True/False）の形で得ることができる．
強調の状態：
下線の状態：
反転の状態：bool(属性データ & curses.A BOLD)
bool(属性データ & curses.A UNDERLINE)bool(属性データ & curses.A REVERSE)

画面上の指定した位置の属性付き文字データを取得して，その内訳を表示するサンプルプログラムを curses05.py に示す．
プログラム：curses05.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# coding : utf -8
import curses# コールバック関数
def cursesMode ( stdscr ):curses . curs_set (0)stdscr . clear ()stdscr . refresh ()curses . start_color ()

#
#
#
#

カーソル表示を無効化
画面消去
画面更新（念の為）
色制御機能を初期化# 色ペアの設定
番号
前景色
curses . init_pair ( 1 , curses . COLOR_RED ,curses . init_pair ( 2 , curses . COLOR_GREEN ,curses . init_pair ( 3 , curses . COLOR_BLUE ,# 目盛り表示
stdscr . addstr (0 ,0 , ’0 - - - -+ - - - -1 ’);

背景色
curses . COLOR_BLACK )curses . COLOR_BLACK )curses . COLOR_BLACK )stdscr . addstr (1 ,0 , ’1 ’)# 色，装飾付き文字出力
stdscr . addch (1 ,2 , ’N ’)
stdscr . addch (1 ,3 , ’R ’ , curses . color_pair (1))

399

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

stdscr . addch (1 ,4 , ’G ’ , curses . color_pair (2))
stdscr . addch (1 ,5 , ’B ’ , curses . color_pair (3))
stdscr . addch (1 ,7 , ’R ’ , curses . color_pair (1) | curses . A_BOLD )stdscr . addch (1 ,8 , ’G ’ , curses . color_pair (2) | curses . A_UNDERLINE )stdscr . addch (1 ,9 , ’B ’ , curses . color_pair (3) | curses . A_STANDOUT )while True :k = stdscr . getch () # 採 取 位 置 の 入 力
if k == 27: break# ESCなら終了
if ord ( ’1 ’) < k < ord ( ’: ’):# ’2 ’ 〜 ’9 ’ の 範 囲 の 場 合
stdscr . addch (0 ,12 , ’ ’);
stdscr . clrtoeol ()# 0行 目 ク リ ア
stdscr . addch (1 ,12 , ’ ’);
stdscr . clrtoeol ()# 1行 目 ク リ ア
stdscr . addch (2 ,0 , ’ ’);
stdscr . clrtoeol ()# 2行 目 ク リ ア
dat = stdscr . inch (1 ,k -48)
# そ の 画 面 位 置 の1 文 字 分 の デ ー タ を 採 取
ch = chr ( dat & 0 xFF )# 文字そのものを取得
attr = dat & ~0 xFF# 属性を取得
cp = ( attr & curses . A_COLOR ) >> 24# 色ペア番号を取得
is_bold = attr & curses . A_BOLD# 強調の状態を取得
is_underline = attr & curses . A_UNDERLINE# 下線の状態を取得
is_reverse = attr & curses . A_REVERSE# 反転の状態を取得# 採取情報の表示
stdscr . addstr (0 ,12 , f ’ row :{ chr ( k )} ’)# 採取位置（横位置）stdscr . addstr (1 ,12 , f ’ char :{ ch } ’)
# 文字
stdscr . addstr (0 ,19 , ’ color_pair ’)stdscr . addstr (1 ,19 , f ’{ cp : -10 d } ’)
# 色ペア番号
stdscr . addstr (0 ,30 , ’ BOLD ’)
stdscr . addstr (1 ,30 , f ’{ bool ( is_bold )} ’)# 強調の状態
stdscr . addstr (0 ,36 , ’ UNDERLINE ’)
stdscr . addstr (1 ,36 , f ’{ bool ( is_underline )} ’) # 下 線 の 状 態
stdscr . addstr (0 ,46 , ’ REVERSE ’)
stdscr . addstr (1 ,46 , f ’{ bool ( is_reverse )} ’)# 反転の状態
stdscr . addch (2 ,k -48 , ’^ ’)# ポインタ表示
curses . curs_set (1)curses . wrapper ( cursesMode )このプログラムの起動直後は# カーソル表示# コールバック関数を実行と表示される．この画面の中の「NRGB RGB」の各文字の位置の情報を取得するには，横（カラム）位置の値 2〜9 のキーを押す．実行例を次に示す．
（試されたい）キー

curses05.py の実行例
表
示

2
3
4
5
7
8
9

D.5.2

画面の中の文字列の採取

window オブジェクトに対して instr メソッドを実行することで，画面の中の指定した位置から右側にある文字列を取得することができる．
書き方：

window オブジェクト.instr( y, x )400

「y」行「x」列の位置から画面右端までの内容を bytes 型で返す．取得する長さを 3 つ目の引数として与えることもできる．

instr メソッドを使用するサンプルプログラムを curses06.py に示す．
プログラム：curses06.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# coding : utf -8
import curses# コールバック関数
def cursesMode ( stdscr ):curses . echo ()stdscr . clear ()stdscr . refresh ()# エコーモード# 画面消去# 画面更新（念の為）# 目盛りと文字列の表示
stdscr . addstr (0 ,0 , ’0 - - - -+ - - - -1 - - - -+ - - - -2 - - - -+ - - - -3 - - - -+ - - - -4 ’);stdscr . addstr (1 ,0 , ’ a b c d e f g h i jklmno pqrstuvw xyzABCDEF GHIJKLMN O ’)
while True :stdscr . addstr (3 ,0 , ’ Input position to pick ( exit to end ): ’)stdscr . clrtoeol ()s = stdscr . getstr (). decode ( ’ utf -8 ’)if s == ’ exit ’: break# 終了
s2 = s . split ( ’ , ’)
p1 = int ( s2 [0] )lngth = None
if len ( s2 ) > 1:
lngth = int ( s2 [1] )if 0 <= p1 <= 40:
if lngth :b = stdscr . instr (1 , p1 , lngth )# 画面上の文字列の採取
else :
b = stdscr . instr (1 , p1 )# 画面上の文字列の採取
stdscr . addch (4 ,0 , ’ ’);
stdscr . clrtoeol ()stdscr . addstr (4 ,0 , f " > ’{ b . decode ( ’ utf -8 ’). rstrip ()} ’")curses . noecho ()curses . wrapper ( cursesMode )# エコーモード解除# コールバック関数を実行

このプログラムを実行すると，画面に0----+----1----+----2----+----3----+----4
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
Input position to pick (exit to end):と表示される．これに対して例えば 26 Enter と入力すると，アルファベットの 26 カラム目以降が採取され，次の行に> ’ABCDEFGHIJKLMNO’と表示される．位置の入力の直後にコンマ「,」で区切って長さを与えることもできる．例えば 26,4 Enter と入力す
ると，次の行に> ’ABCD’と表示される．

401

psutil ライブラリE

psutil はサードパーティ247 が開発して公開するライブラリであり，システムリソース（CPU，メモリ，ディスク，
ネットワーク，プロセスなど）に関する情報を取得する機能を提供する．このライブラリは利用に先立って pip など
でインストールしておく必要がある．
例．pip install psutil
また利用に際しては次のようにしてライブラリを読み込む．

import psutil

E.1

CPU 関連の情報の取得

E.1.1

CPU の構成：cpu count 関数
書き方：

cpu count( )計算機環境の CPU（もしくはそのコア）の個数を返す．引数に ’logical=False’ を与えると物理 CPU（物理コア）の数を返し，’logical=True’ を与えると論理 CPU の数248 を返す．
（デフォルトは True）
例．CPU の個数を調べる>>> psutil.cpu count(logical=False)4←物理コア数Enter←物理コア数を調べる>>> psutil.cpu count(logical=True)8←論理コア数Enter←論理コア数を調べる

E.1.2

CPU のクロック周波数：cpu freq 関数
書き方：

cpu freq( )CPU のクロック周波数に関する情報を scpufreq オブジェクトの形で返す．
例．クロック周波数の情報を調べる（先の例の続き）>>> psutil.cpu freq()
Enter←クロック周波数情報の取得
scpufreq(current=2918.0, min=0.0, max=2918.0)←得られた scpufreq オブジェクト
得られた scpufreq オブジェクトの属性 min，max からはクロック周波数の下限と上限の値が得られる．計算機環境が下限の情報を与えない場合は min の値は 0 となる．また，現在実行中の状態におけるクロック周波数は current 属性から得られる．

cpu freq 関数に引数 ’percpu=True’ を与えると，各論理 CPU に対応する scpufreq オブジェクトがリストの形で返される．
（デフォルトは False）ただし，計算機環境によっては論理 CPU ごとの情報が得られないケースもあり，その場合は 1 個の scpufreq オブジェクトのみを持つリストが返される．

E.1.3

CPU 時間：cpu times 関数
書き方：

cpu times( )システム起動時を起点とする CPU の稼働時間に関する情報を scputimes オブジェクトの形で返す．
例．CPU 稼働時間の情報を調べる（先の例の続き）>>> psutil.cpu times()Enter← CPU 稼働時間情報の取得
scputimes(user=16968.796875, system=12453.015625,←↓得られた scputimes オブジェクト
idle=4276172.390625, interrupt=925.4375, dpc=336.453125)
scputimes オブジェクトの各属性（表 57）の値の単位は秒である．
cpu times 関数に引数 ’percpu=True’ を与えると，各論理 CPU に対応する scputimes オブジェクトがリストの形で返される．
（デフォルトは False）
247 https://github.com/giampaolo/psutil
248 ハイパースレッディング（HT）などの並列処理技術を応用した CPU では，1 つの物理コアで複数の処理を同時に実行することができ，物理コアの総数よりも多くの論理 CPU が存在することになる．

402

表 57: scputimes オブジェクトの属性（一部）
属性

解説

user

ユーザーモードで実行された通常のプロセスが費やした時間

system

カーネルモードで実行されたプロセスが費やした時間

idle

システムがアイドル状態であった時間

interrupt

ハードウェア割り込みを処理するために費やした時間

dpc

遅延プロシージャコール（DPC）を処理するために費やした時間．
（DPC は，標準の割り込みよりも低い優先度で実行される割り込み）

論理 CPU がハイパースレッディングなどの並列処理技術によって実現されている場合，全論理 CPU の時間の合計
は実時間とはならないことに注意すること．また，引数なし（デフォルト）で実行された場合，得られる scputimes
オブジェクトの各属性は全論理 CPU のものの合計となる．

E.1.4

CPU 使用率：cpu percent 関数
書き方：

cpu percent( )直近の CPU 使用率（CPU 時間から算出）を ﬂoat で返す．
例．直近の CPU 使用率を調べる（先の例の続き）>>> psutil.cpu percent()
0.2
← 20%

Enter

←直近の CPU 使用率を調べる

cpu percent 関数に引数 ’interval=秒数’ を与えると「秒数」の間待機して，その前後の CPU 時間から CPU 使用率を算出する．
例．1 秒間の CPU 使用率を調べる（先の例の続き）>>> psutil.cpu percent(interval=1)
0.4
← 40%

← 1 秒間の CPU 使用率を調べる

Enter>>> for in range(3): print(psutil.cpu percent(interval=1))
...
Enter
← for 文の完結
0.6
0.0
← CPU 使用率が 1 秒おきに 3 回出力される
0.6

E.2

メモリ関連の情報の取得

E.2.1

仮想記憶の状況：virtual memory 関数
書き方：

Enter

← 3 回実行virtual memory( )計算機環境の仮想記憶の状況を svmem オブジェクトとして返す．
例．仮想記憶の状況の調査（先の例の続き）>>> psutil.virtual memory()Enter←仮想記憶の状況を調べる
svmem(total=34031902720, available=21871828992, percent=35.7,
used=12160073728, free=21871828992)
svmem オブジェクトの各属性を表 58 に示す．
表 58 の available 属性の値は，実際に使用可能なメモリのサイズを意味しており，free 属性とは異なる．free 属性の値は，調査時点で全く使用されていないメモリの大きさを示している．

E.2.2

スワップ領域の使用状況：swap memory 関数
書き方：swap memory( )仮想記憶におけるスワップ領域249 の使用状況を sswap オブジェクトとして返す．
249 仮想記憶の内容を退避するための，補助記憶装置（ディスクなどのストレージ）上の領域．

403

属性

表 58: svmem オブジェクトの属性（一部）
解説

total

総物理メモリ（単位：バイト）．スワップ領域は含まない．

available

使用可能なメモリ（単位：バイト）．

percent

使用中のメモリの割合（百分率）

used

使用中のメモリ（単位：バイト）

free

空きメモリ（単位：バイト）※上記 available とは異なる．

例．スワップ領域の使用状況の調査（先の例の続き）>>> psutil.swap memory()Enter←スワップ領域の使用状況を調べる
sswap(total=5100273664, used=77336576, free=5022937088, percent=1.5, sin=0, sout=0)
sswap オブジェクトが得られている．このオブジェクトの各属性を表 59 に示す．
表 59: sswap オブジェクトの属性
属性

解説

total

スワップ領域のサイズ（単位：バイト）

used

使用中のスワップ領域のサイズ（単位：バイト）

free

未使用のスワップ領域のサイズ（単位：バイト）

percent

スワップ領域の使用率（百分率）sin

スワップインの量（単位：バイト）．ディスクからメモリへの移動量

sout

スワップアウトの量（単位：バイト）．メモリからディスクへの移動量E.3

ディスク関連の情報の取得

E.3.1

パーティションの構成：disk partitions 関数
書き方：

disk partitions( )計算機環境のディスクのパーティションの構成を sdiskpart オブジェクトのリストとして返す．
例．パーティションの構成の調査（Windows での実行例：先の例の続き）>>> psutil.disk partitions()
Enter←パーティションの構成を調べる[sdiskpart(device=’C:￥￥’, mountpoint=’C:￥￥’, fstype=’NTFS’, opts=’rw,fixed’),sdiskpart(device=’D:￥￥’, mountpoint=’D:￥￥’, fstype=’NTFS’, opts=’rw,fixed’)]sdiskpart オブジェクトのリストが得られている．このオブジェクトの各属性を表 60 に示す．
表 60: sdiskpart オブジェクトの属性
属性

解説

deviceデバイスの名前

mountpoint

パーティションがマウントされている場所

fstypeファイルシステムの種類

opts

パーティションのオプション．コンマ区切りの文字列．

’rw’：読み書き可能．
’ro’：読み取り専用，’ﬁxed’：固定ディスク， ’removable’：リムーバブル，’noexec’：実行不可，
他
disk partitions 関数は，仮想ディスクやリムーバブルディスクは調査の対象にしないことがある，その場合，引数’all=True’ を与えると，それらも含め全てのパーティションの情報を取得する．

404

E.3.2

ディスクの使用状況：disk usage 関数
書き方：

disk usage( パス )「パス」が示すディレクトリが存在するパーティションの使用状況を sdiskusage オブジェクトとして返す．
「パス」には，ファイルではなくディレクトリを示すものを与える．
例．ディスクの使用状況の調査（先の例の続き）>>> psutil.disk usage(’.’)
Enter←パーティションの使用状況を調べる
sdiskusage(total=511085375488, used=456475533312, free=54609842176, percent=89.3)
この例では，カレントディレクトリが属しているパーティションの使用状況を調べ，sdiskusage オブジェクトを得ている．このオブジェクトの total 属性に当該パーティションの総容量，used 属性に使用中の容量，free 属性に未使用の容量，percent 属性にディスクの使用率（百分率）が得られる．

E.3.3

ディスクの I/O 状況：disk io counters 関数
書き方：

disk io counters( )システム起動時からのディスクの I/O の状況（累積）を sdiskio オブジェクトとして返す．
例．ディスクの I/O 状況の調査（先の例の続き）>>> psutil.disk io counters()
Enter←ディスクの I/O 状況を調べる
sdiskio(read count=4101552, write count=8761204, read bytes=156201640448,
write bytes=274797508608, read time=1413, write time=3273)
システム起動時からの，全物理ディスクの統計情報が sdiskio オブジェクトとして得られている．このオブジェクトの各属性を表 61 に示す．

属性

表 61: sdiskio オブジェクトの属性（一部）解説read count

ディスクの読み取り操作の回数

write count

ディスクの書き込み操作の回数

read bytes

読み取られたデータの総量（単位：バイト）

write bytes

書き込まれたデータの総量（単位：バイト）

read time

ディスクの読み取り操作に要した総時間（単位：ミリ秒）

write time

ディスクの書き込み操作に要した総時間（単位：ミリ秒）

disk io counters 関数に引数 ’perdisk=True’（デフォルトは False）を与えると，物理ディスクごとの sdiskio オ
ブジェクトが辞書の形で得られる．
例．物理ディスクごとの I/O 状況の調査（先の例の続き）>>> psutil.disk io counters( perdisk=True )Enter{’PhysicalDrive0’: sdiskio(read count=4031974, write count=8728921,
read bytes=150887646208, write bytes=245865650176,
read time=1151, write time=2548),’PhysicalDrive1’: sdiskio(read count=69678, write count=34687,
read bytes=5316595200, write bytes=28971454464,
read time=262, write time=729)}
この例では，’PhysicalDrive0’，’PhysicalDrive1’ が示す 2 つの物理ディスクの統計情報が得られている．辞書のキーはシステムが適切な形で与える．

E.4

ネットワーク関連の情報の取得

E.4.1

ネットワークの I/O 状況：net io counters 関数
書き方：

net io counters( )システム起動時からのネットワークの I/O 状況（累積）を snetio オブジェクトとして返す．

405

例．ネットワークの I/O 状況の調査（先の例の続き）>>> psutil.net io counters()
Enter←ネットワーク I/O 状況の調査
snetio(bytes sent=3889675079, bytes recv=48781973057, packets sent=19719232,
packets recv=39328744, errin=0, errout=0, dropin=0, dropout=0)
システム起動時からの，ネットワーク I/O の統計情報が snetio オブジェクトとして得られている．このオブジェクトの各属性を表 62 に示す．

属性

表 62: snetio オブジェクトの属性
解説

bytes sent

送信されたデータの総量（単位：バイト）

bytes recv

受信されたデータの総量（単位：バイト）

packets sent

送信されたパケットの総数

packets recv

受信されたパケットの総数

errin

受信エラーの総数

errout

送信エラーの総数

dropin

受信ドロップの総数

dropout

送信ドロップの総数

net io counters 関数に引数 ’pernic=True’（デフォルトは False）を与えると，ネットワークインターフェースごとの snetio オブジェクトが辞書の形で得られる．
例．ネットワークインターフェースごとの I/O 状況の調査（先の例の続き）>>> psutil.net io counters( pernic=True )Enter{’Wi-Fi’: snetio(bytes sent=0, bytes recv=0, packets sent=0, packets recv=0, errin=0,
errout=0, dropin=0, dropout=0),’ ローカル エリア接続* 1’: snetio(bytes sent=0, bytes recv=0, packets sent=0, packets recv=0,
errin=0, errout=0, dropin=0, dropout=0),’ ローカル エリア接続* 2’: snetio(bytes sent=0, bytes recv=0, packets sent=0,
packets recv=0, errin=0, errout=0, dropin=0, dropout=0),’ イーサネット’: snetio(bytes sent=3889877658, bytes recv=48783394042, packets sent=19720289,
packets recv=39330396, errin=0, errout=0, dropin=0, dropout=0),’Loopback Pseudo-Interface 1’: snetio(bytes sent=0, bytes recv=0, packets sent=0,
packets recv=0, errin=0, errout=0, dropin=0, dropout=0)}
E.4.2

現在の通信状況：net connections 関数
書き方：

net connections( )現在のアクティブなネットワーク通信の状況を sconn オブジェクトのリストとして返す．sconn オブジェクトは，当該計算機上で実行中のプロセスの，アクティブな通信ソケット250 に関するものである．
例．現在の通信状況の調査（先の例の続き）>>> psutil.net connections()
Enter←現在の通信状況の調査[sconn(fd=-1, family=<AddressFamily.AF INET: 2>, type=<SocketKind.SOCK DGRAM: 2>,
laddr=addr(ip=’192.168.0.4’, port=1900), raddr=(), status=’NONE’, pid=7216),
sconn(fd=-1, family=<AddressFamily.AF INET: 2>, type=<SocketKind.SOCK STREAM: 1>,
laddr=addr(ip=’0.0.0.0’, port=49667), raddr=(), status=’LISTEN’, pid=2504),…]
複数の sconn オブジェクトのリストが得られている．個々の sconn オブジェクトは，net connections 関数実行時点
におけるアクティブな通信ソケットに対応している．sconn オブジェクトの各属性を表 63 に示す．
net connections 関数には引数 ’kind=’ を与えて，調査対象を選ぶことができる．調査対象の種別を表 65 に挙げる．

250 「5 TCP/IP による通信」（p.326）で詳しく解説している．

406

表 63: sconn オブジェクトの属性
属性

解説

fd

ソケットのファイルディスクリプタ．0 以上の整数値．
-1 の場合は特定のファイルディスクリプタが無いことを意味する．

familyアドレスファミリ．

type

ソケットの種類．

laddr

ローカルアドレス．IPv4 の場合は addr(ip=IP アドレス,port=ポート番号)，IPv6 の場合はaddr(ip=IP アドレス,port=ポート番号,flowinfo=データフロー識別子,scopeid=スコープ識別子)，
UNIX ドメインソケットの場合は addr(path=パス)．

raddr

リモートアドレス．値の形式は laddr と同じ．リモートアドレスがない場合は
空のタプル () となる．

status

接続状態．表 64 の接続状態を参照のこと．

pid

プロセス ID．この接続を所有するプロセスの ID<AddressFamily.AF INET: 2>：IPv4 アドレスファミリ，<AddressFamily.AF INET6:10>：IPv6 アドレスファミリ，<AddressFamily.AF UNIX: 1>：UNIX ドメインソケット<SocketKind.SOCK STREAM: 1>：TCP ソケット，<SocketKind.SOCK DGRAM: 2>：UDP ソケット，<SocketKind.SOCK RAW: 3>：生のソケット

表 64: sconn オブジェクトの接続状態
属性

解説

ESTABLISHEDSYN SENTSYN RECVFIN WAIT1
FIN WAIT2TIME WAIT
CLOSE
CLOSE WAIT
LAST ACK
LISTEN
CLOSING
NONE

接続が確立され，データの送受信が可能な状態
接続要求（SYN パケット）が送信され，応答を待っている状態
接続要求（SYN パケット）が受信され，応答を送信した状態
接続終了要求（FIN パケット）が送信され，応答を待っている状態
接続終了要求（FIN パケット）に対する応答が受信され，接続が終了するのを待っている状態
接続が終了し，一定時間待機している状態
接続が閉じられた状態
リモート側が接続を閉じ，ローカル側がそれに応答するのを待っている状態
接続終了要求（FIN パケット）に対する応答を送信し，最終的な ACK を待っている状態
ソケットが接続要求を待機している状態
両側が接続終了要求（FIN パケット）を送信し，まだ全てのパケットが受信されていない状態
特定の状態がない場合

種別

解

表 65: net connections 関数の引数 kind=種別
説
種別
解

説

’inet’

IPv4 および IPv6 のソケット接続’inet4’

IPv4 のソケット接続’inet6’

IPv6 のソケット接続’tcp’

TCP ソケット接続’tcp4’

IPv4 の TCP ソケット接続’tcp6’

IPv6 の TCP ソケット接続’udp’

UDP ソケット接続’udp4’

IPv4 の UDP ソケット接続’udp6’

IPv6 の UDP ソケット接続’unix’

UNIX ドメインソケット接続’all’

すべての種類のソケット接続

E.5

プロセス関連の情報の取得

E.5.1

実行中のプロセス：pids 関数
書き方：（デフォルトは ’inet）

pids( )

実行中の全てのプロセスのプロセス ID（PID）のリストを返す．
例．実行中のプロセスの調査（先の例の続き）>>> psutil.pids()
Enter←現在実行中のプロセスの調査[0, 4, 156, 556, 608, 640, 668, 756, 776, 848, 948, 968, … ]407← PID のリスト

Process クラス

E.5.2

Process クラスは，実行中のプロセスの情報を取り扱うためのものである．
書き方：

Process( プロセス ID )これは Process クラスのコンストラクタであり，指定した「プロセス ID」（PID）のプロセスに関する情報を保持するインスタンスを生成する．
注意）この Process クラスは multiprocessing モジュールが提供する Process クラスとは別のものである．
psutil ライブラリと multiprocessing モジュールを併用する場合は名前の衝突に注意すること．
実行中の Python 処理系のプロセスを用いる例を挙げて，このクラスについて解説する．
例．実行中の Python 処理系を指す Process オブジェクトの作成>>> import os←必要なモジュールのEnter>>> import psutil←必要なモジュールのEnter>>> p = os.getpid(); print(p)Enter← Python 処理系の PID を取得
20728← PID（システムが設定した値）>>> pr = psutil.Process( p )← Python 処理系を指す Process オブジェクトを作成

Enter>>> prEnter←内容確認
psutil.Process(pid=20728, name=’python.exe’, status=’running’, started=’18:24:07’)
Process インスタンスが得られていることがわかる．このオブジェクトの pid 属性にはプロセス ID が，name 属性にはそのプログラムの名前（この場合は Python 処理系である’python.exe’）が，status 属性には実行状態が，started
属性には開始時刻が保持されている．

Process オブジェクトに対して使える各種メソッドを以下に挙げる．
E.5.2.1

メモリの使用状況の調査：memory info

memory info メソッドを用いると，プロセスのメモリの使用状況を詳細に知ることができる．
書き方：

Process オブジェクト.memory info( )「Process オブジェクト」のメモリ使用状況を示す pmem オブジェクトを返す．
例．プロセスのメモリの使用状況の調査（先の例の続き）>>> pm = pr.memory info()

Enter

←調査実行

>>> pmEnter←結果の確認pmem(rss=100777984, vms=1138958336, shared=26755072, text=2818048, lib=0,
data=247259136, dirty=0)pmem オブジェクトが得られている．このオブジェクトの各属性を表 66 に示す．
表 66: pmem オブジェクトの属性（一部）
属性

解

説

rss

プロセスが実際に使用している物理メモリのサイズ．
（Resident Set Size）

vms

プロセスに割り当てられた仮想メモリの総量．
（Virtual Memory Size）

shared他のプロセスと共有されているメモリのサイズ

text

プロセスの実行可能なコード（テキストセグメント）のサイズ

lib

共有ライブラリのサイズ

data

プロセスのデータセグメントとヒープのサイズ

dirty

変更されたがまだディスクに書き込まれていないメモリのサイズ
メモリサイズの単位はバイト

pmem オブジェクトの属性の種類は，Python 言語処理系を実行している計算機環境によって（OS の種類によって）異なることがあるので，詳細に関しては公式インターネットサイトなどの資料を参照のこと．

pmem オブジェクトの属性のうち，特に重要なものとして rss と vms がある．vms は当該プロセスが確保してい408

る仮想記憶の全サイズ，rss は当該プロセスがアクティブに使用している物理メモリのサイズである．
参考）先の例を Windows 環境で実行すると次のような pmem オブジェクトが得られることがある．

pmem(rss=17948672, vms=11739136, num page faults=4756, peak wset=18313216,
wset=17948672, peak paged pool=129120, paged pool=128944, peak nonpaged pool=11848,
nonpaged pool=11672, pagefile=11739136, peak pagefile=12124160, private=11739136)
通常は，アクティブに使用している物理記憶のサイズは，全仮想記憶のサイズより小さいが，この例では，rss の値がvms の値を上回っている．
■ 応用例

memory info メソッドを応用して，プロセスのメモリ使用状況を調べるツール mstat.py を実装する例を示す．
プログラム：mstat.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# coding : utf -8
import psutil , os

# 必要なモジュールの読み込み# プロセスのメモリの使用状況を調べる関数
def pstat ( pid = None ):if pid == None :# Python処理系のpmemオブジェクト
minf = psutil . Process ( os . getpid () ). memory_info ()else :# pidのプロセスのpmemオブジェクト
minf = psutil . Process ( pid ). memory_info ()return ( minf . rss , minf . vms )# システムの
if __name__ == ’ __main__ ’:m = pstat ()print ( ’ P y t h o n 処 理 系 の メ モ リ : ’)print ( ’ 物 理 メ モ リ ( Bytes ): ’ , m [0])print ( ’ 仮 想 メ モ リ ( Bytes ): ’ , m [1])上記スクリプトに定義されている pstat 関数は，引数に与えた PID のプロセスのメモリ使用状況を調べ，物理記憶のサイズと仮想記憶のサイズのタプルを返す．引数を省略すると，Python 処理系のアクティブな物理記憶のサイズと，仮想記憶の全サイズのタプルを返す．
例．Python 言語処理系のメモリ使用状況を調べる>>> import mstat

Enter←スクリプトをモジュールとして読み込む>>> mstat.pstat()Enter←メモリ使用状況調査(12140544, 19988480)←タプル (物理記憶, 仮想記憶)
このスクリプトを直接実行するとそれらの値を標準出力に出力する．
例．スクリプトを直接実行した際の出力

Python 処理系のメモリ:
物理記憶 (Bytes): 12140544
仮想記憶 (Bytes): 19988480
E.5.2.2

CPU 使用率：cpu percent

cpu percent メソッドを用いると，プロセスの CPU 使用率を知ることができる．
書き方：

Process オブジェクト.cpu percent( )「Process オブジェクト」が示すプロセスの CPU 使用率を返す．これは psutil.cpu percent 関数（p.403 で解説）と同様の考え方で，プロセスを対象に CPU 使用率を算出するものである．
．

409

E.5.2.3

CPU 時間：cpu times

cpu times メソッドを用いると，プロセスの CPU 時間を知ることができる．
書き方：

Process オブジェクト.cpu times( )「Process オブジェクト」が示すプロセスの CPU 時間を示す pcputimes オブジェクトを返す．
例．プロセスの CPU 時間の調査（先の例の続き）>>> pr.cpu times()
Enter
←調査実行
pcputimes(user=0.015625, system=0.0, children user=0.0, children system=0.0)
pcputimes オブジェクトが得られているのがわかる．このオブジェクトの user 属性には当該プロセスのユーザーモー
ドの CPU 時間，system 属性にはカーネルモードの CPU 時間が保持されている．対象プロセスの全ての子プロセスの CPU 時間（合計）も得られており，それは children user 属性（ユーザーモード），children system 属性（カーネ
ルモード）が保持している．

E.5.2.4

開いているファイルの調査：open ﬁlesopen ﬁles メソッドを用いると，プロセスが開いているファイルを調べることができる．
書き方：

Process オブジェクト.open ﬁles( )「Process オブジェクト」が示すプロセスが開いているファイルを，popenﬁle オブジェクトのリストの形で返す．popenﬁleオブジェクトは，指定したプロセスが開いている個々のファイルを表すもので，表 67 に示すような属性を持つ．
表 67: popenﬁle オブジェクトの属性
属性

解

説

path

ファイルの絶対パス

fd

ファイルディスクリプタ（番号）position

ファイル内の現在の位置．
（seek された現在位置）

mode

ファイルのオープンモード．
（’r’，’w’ など）

ﬂags

ファイルのフラグ．C 言語の open 関数（システムコールの 1 つ）の第 2 引数に与えるフラグと同じ形式．

例．プロセスが開いているファイルの調査（Linux での実行例：先の例の続き）>>> f1=open(’dummy1’,’w’); f2=open(’dummy2’,’w’)Enter← 2 つのファイルを開く>>> pr.open files()Enter←ファイルの使用状況を調査[popenfile(path=’/usr/home/katsu/dummy1’, fd=42, position=0, mode=’w’, flags=557057),
popenfile(path=’/usr/home/katsu/dummy2’, fd=43, position=0, mode=’w’, flags=557057)]>>> f1.close(); f2.close()Enter← 2 つのファイルを閉じる

これは，Python 処理系が 2 つのファイル dummy1，dummy2 を開いた（作成した）状態で open ﬁles メソッドを実行した例であり，それらファイルに対応する popenﬁle オブジェクトがリストの形で得られていることがわかる．
注意）psutil は Windows 環境に十分対応できていない部分があり，この例と同じ処理を Windows 環境で実行すると，open ﬁles メソッドの実行結果は[popenfile(path=’C:￥￥dummy2’, fd=-1), popenfile(path=’C:￥￥dummy1’, fd=-1)]などとなり，特定の属性が得られないことがある．

E.5.2.5

プロセスの通信状況：net connections

net connections メソッドを用いると，プロセスの通信状況を調べることができる．
書き方：

Process オブジェクト.net connections( )「Process オブジェクト」が示すプロセスの，アクティブなネットワーク通信の状況を pconn オブジェクトのリストとして返す．pconn オブジェクトは，プロセスのアクティブな通信ソケット251 に関するものである．

251 「5 TCP/IP による通信」（p.326）で詳しく解説している．

410

例．プロセスの通信状況の調査（先の例の続き）>>> pr.net connections()
Enter←通信状況の調査[pconn(fd=21, family=<AddressFamily.AF INET: 2>, type=<SocketKind.SOCK STREAM: 1>,
laddr=addr(ip=’127.0.0.1’, port=39893), raddr=(), status=’LISTEN’),pconn(fd=34, family=<AddressFamily.AF INET: 2>, type=<SocketKind.SOCK STREAM: 1>,
laddr=addr(ip=’127.0.0.1’, port=54812), raddr=addr(ip=’127.0.0.1’, port=58761),
status=’ESTABLISHED’)]
これはプロセスが 2 つのソケット通信をしている場合の例である．通信しているソケットがない場合は空リスト []が返される．

pconn オブジェクトの属性に関しては，先の「現在の通信状況：net connections 関数」（p.406）で解説した sconn
オブジェクトに準ずる．

E.5.2.6

プロセスの終了：terminate

terminate メソッドを用いると，指定したプロセスを終了させることができる．
書き方：

Process オブジェクト.terminate( )「Process オブジェクト」が示すプロセスを終了する．
例．プロセスの終了（先の例の続き）←プロセスの終了>>> pr.terminate()Enter

C:￥Users￥katsu>← OS のプロンプトに戻った（Windows の場合）注意）この例では，Python 言語処理系を terminate メソッドで終了しているが，この目的のためにはexit 関数を使用するべきである．

E.5.3

サンプルプログラム：プロセスの監視

multiprocessing モジュールによるマルチプロセスの実行状態を psutil ライブラリの機能で監視するサンプルを
mproc02.py に示す．このサンプルでは，multiprocessing モジュールが提供する Process クラスのインスタンス p1，
p2，p3 を生成して実行する．各プロセスでは，longTask 関数（時間がかかる計算処理）を実行する．また，それらプロセスの状態を調べるために，psutil が提供する Process クラスのオブジェクト pr1，pr2，pr3 に変換して各種メ
ソッド（先に解説したもの）を実行する．
プログラム：mproc02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# coding : utf -8
import time
import m ul t ip ro c es si n g as mlpr
import psutil# 実行時間がかかる処理
def longTask ():n = 1
for _ in range (500000):n *= 2# 回数は適宜調整すること

if __name__ == ’ __main__ ’:# プロセス作成
p1 = mlpr . Process ( target = longTask , args =())
p2 = mlpr . Process ( target = longTask , args =())
p3 = mlpr . Process ( target = longTask , args =())# プロセス実行
p1 . start ();p2 . start ();p3 . start ()# psutil . P r o c e s s オ ブ ジ ェ ク ト に 変 換
pr1 = psutil . Process ( p1 . pid )pr2 = psutil . Process ( p2 . pid )pr3 = psutil . Process ( p3 . pid )# プ ロ セ ス 監 視 ： 全 プ ロ セ ス が 終 了 す る ま で 監 視 を 繰 り 返 す （1 秒 間 隔 ）t1 = time . time ()while any ( [ p1 . is_alive () , p2 . is_alive () , p3 . is_alive () ] ):# メモリの状態を調べる
mi1 = pr1 . memory_info (); mi2 = pr2 . memory_info (); mi3 = pr3 . memory_info ()# CPU使用率を調べる

411

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

cp1 = pr1 . cpu_percent (); cp2 = pr2 . cpu_percent (); cp3 = pr3 . cpu_percent ();# CPU時間を調べる
ct1 = pr1 . cpu_times ();ct2 = pr2 . cpu_times ();ct3 = pr3 . cpu_times ();# プロセスの状態を出力する
print ( ’\ t \ t[ p1 ]\ t \ t[ p2 ]\ t \ t[ p3 ] ’)print (f ’ memory_info : rss \ t { mi1 . rss :9 d }\ t { mi2 . rss :9 d }\ t { mi3 . rss :9 d } ’)print (f ’ memory_info : vms \ t { mi1 . vms :9 d }\ t { mi2 . vms :9 d }\ t { mi3 . vms :9 d } ’)print (f ’ cpu_percent \ t { cp1 :9.2 f }\ t { cp2 :9.2 f }\ t { cp3 :9.2 f } ’)print (f ’ cpu_times : user \ t { ct1 . user :9.2 f }\ t { ct2 . user :9.2 f }\ t { ct3 . user :9.2 f } ’)print (f ’ cpu_times : sys \ t { ct1 . system :9.2 f }\ t { ct2 . system :9.2 f }\ t { ct3 . system :9.2 f } ’)print ()
time . sleep (1)# 1秒 待 機
t2 = time . time ()p1 . join (); p2 . join (); p3 . join ()# 安全のためprint (f ’ elapsed time \ t { t2 - t1 :9.2 f } ’)

プログラム中の while 文でプロセスの状態監視と出力を繰り返す．繰り返しの間隔は 1 秒で，全プロセスが終了するまで行う．プロセスで実行する関数 longTask 内の反復回数は適宜調整すること．
このサンプルを実行した際の出力例を次に示す．
実行例：mproc02.py を実行した際のコンソールの出力
memory_info : rss
memory_info : vms
cpu_percent
cpu_times : user
cpu_times : sys[ p1 ]
7544832
4190208
0.00
0.02
0.00

[ p2 ]
37150722392064
0.00
0.00
0.00

[ p3 ]
1769472425984
0.00
0.00
0.00

memory_info : rss
memory_info : vms
cpu_percent
cpu_times : user
cpu_times : sys[ p1 ]
18456576
12255232
92.20
0.91
0.03

[ p2 ]
18092032
11874304
89.10
0.89
0.00

[ p3 ]
18329600
12128256
82.80
0.83
0.00

memory_info : rss
memory_info : vms
cpu_percent
cpu_times : user
cpu_times : sys[ p1 ]
18575360
12378112
93.80
1.84
0.03

[ p2 ]
18108416
11874304
84.40
1.73
0.00

[ p3 ]
18370560
12169216
96.90
1.80
0.00

memory_info : rss
memory_info : vms
cpu_percent
cpu_times : user
cpu_times : sys[ p1 ]
18636800
12435456
101.602.86
0.03[ p2 ]
18173952
11935744
95.30
2.69
0.00

[ p3 ]
18444288
12242944
92.20
2.72
0.00

elapsed time

← 状 態 出 力 ：1 回 目← 状 態 出 力 ：2 回 目← 状 態 出 力 ：3 回 目← 状 態 出 力 ：4 回 目←処理全体の経過時間

4.01

412

F

ライブラリの取り扱いについて

F.1

ライブラリの読込みに関することライブラリを読み込むための最も基本的な記述はimport ライブラリ名である．当該ライブラリに含まれるクラスやメソッド，関数などを使用するには，それらの名前の前に‘ライブラリ名.’を付ける．
（接頭辞の付加）例えば math モジュールの sin 関数を呼び出す場合は，

import mathy = math.sin( math.pi/2 )などとする．
パッケージ構成のライブラリの場合は，1 つのパッケージが複数のモジュールから構成されている．例えば「パッケージ 1」というパッケージが「モジュール 1」というモジュールを保持している場合は，次のようにしてそのモジュー
ルを読み込む．

import パッケージ 1. モジュール 1
この後，例えば次のようにして，そこに属する関数やクラスを利用することができる．
パッケージ 1. モジュール 1. 関数 (引数,…)パッケージは，サブパッケージから成る階層構造をとる場合もある．その場合は，import パッケージ 1. サブパッケージ. サブサブパッケージ.…. モジュールのようにして読み込む．ただし，この方法でモジュールを読み込むと，その利用において，接頭辞のドット「.」による連結表記が長くなってしまい，記述の煩わしさが生じる．そのような場合は，モジュールの読み込み時に別名を与えると良い．

F.1.1

ライブラリ読込みにおける別名の付与

先に例示したような，ドット表記の長いパッケージ読込みにおいては，別名を与えて簡潔な記述にすることができる．具体的には，import による読込みの最後に「as 別名」を記述する．

import パッケージ 1. サブパッケージ. サブサブパッケージ.…. モジュール as 別名
この後，例えば次のようにして簡潔な記述ができる．
別名. 関数 (引数,…)「別名」は任意に決めて良い．

F.1.2

接頭辞を省略するためのライブラリの読込み

import でライブラリを読み込む際に from を使ってfrom ライブラリの指定 import 関数やクラスなど
として特定の関数やクラスを指定して読み込むことができる．例えば，math モジュールの sin と pi のみを読み込んで使用するには次のようにする．

from math import sin, pi
これにより，sin と pi の使用に際して接頭辞 ‘math.’ を付ける必要がなくなる．
（次の例）
例．接頭辞を省略するためのモジュール読込み>>> from math import sin, pi>>> sin( pi/2 )1.0 ←結果表示

Enter

Enter

← math モジュールから sin と pi のみ読み込む←接頭辞無しで計算実行

更に，読込み時の関数名やクラス名の代わりにアスタリスク「＊」を指定すると，当該モジュール内のすべてのものが読み込まれ，接頭辞を付ける必要が一切無くなる．
（次の例参照）

413

例．モジュール内のすべてのものを読み込むEnter>>> from math import *>>> acos( sin( 3 * pi / 2 ) )3.141592653589793 ←結果表示← math モジュールから全てを読み込む

Enter←接頭辞無しで計算実行

接頭辞を付けずに math モジュールの acos，sin，pi が使用できることがわかる．

F.1.2.1

接頭辞を省略する際の注意（名前の衝突）ライブラリの読み込みにおいてアスタリスク「＊」を使用する場合は名前の衝突に注意しなければならない．このことは特に複数のライブラリを併用する場合に重要である．
複数の異なるライブラリが同一の関数名やクラス名を使用している場合に名前の衝突が起こる．例えば math モ
ジュールと mpmath ライブラリは同じ名前の関数を多数提供しており，この問題が発生する．具体的な例を挙げると，

sin 関数は両方のライブラリが提供しており，アスタリスクによる読込みによって問題が発生する．
（次の例参照）
例．math モジュールと mpmath の間での名前の衝突

Enter>>> from math import *← math モジュールから全てを読み込む>>> sin(pi/2)
Enter ←接頭辞無しで計算実行
1.0 ← math.sin による結果>>> from mpmath import *Enter← mpmath から全てを読み込む>>> sin(pi/2)
Enter ←接頭辞無しで計算実行
mpf(’1.0’) ← mpmath.sin による結果
これは，後から読み込まれた mpmath によって，先に読み込まれたモジュールの関数が上書きされてしまった例である．接頭辞を省略する形でのライブラリの利用に際しては十分な注意が必要である．長い接頭辞を付けることが煩わしい場合は，別名を付与して名前の衝突に対処するのが良い．

F.1.3

ライブラリのパス：sys.path

Python 処理系が読み込むライブラリのパスは sys.path にリストの形で登録されている．
例．sys.path の内容を調べる>>> import sys>>> sys.path

Enter
Enter

← sys モジュールの読込み← sys.path の内容を参照する[’’, ’C:￥￥Program Files￥￥Python311￥￥python311.zip’, ’C:￥￥Program Files￥￥Python311￥￥DLLs’,…（途中省略）…
’C:￥￥Program Files￥￥Python311￥￥Lib￥￥site-packages’]

この例のように，ライブラリを検索するパスがリストの形で得られる．
利用者が独自に作成したライブラリを Python 処理系で import 可能にするには，当該ライブラリが属するディレ
クトリのパスを sys.path に追加する252 ．

F.1.4

既に読み込まれているライブラリの調査：

sys.modules

Python 処理系に既に読み込まれているライブラリの一覧は sys モジュールの modules から得られる．この値は辞書型であり，要素のキーはモジュール名，それに対する値は module オブジェクト253 である．これを応用して，処理系に読み込まれているモジュールのリストを作成する例を示す．

252 JupyterNotebook など一部の対話環境では，sys.path に変更を加えた後，セッションの再起動が必要となる場合もあるので注意すること．
253 module オブジェクトに関しては，Python の公式ドキュメントを参照のこと．

414

例．処理系に読み込まれているライブラリを確認する>>> import sys

Enter← sys モジュールの読込み>>> for n,x in enumerate(mlst:=list(sys.modules.keys())): Enter...
print(f’{x+",":<36s}’,end=’’);
Enter
...
if n%2: print()
Enter
...
Enter
←ループの記述の終了
sys,frozen importlib,
tokenize,inspect,←モジュール名の出力ループ

builtins,
imp,…（途中省略）…

linecache,rlcompleter,

ライブラリは他のライブラリを用いて（import して）作成されていることも多く，そのようなライブラリを読み込
むと，副次的に読み込んだライブラリの名前も sys.modules に反映される．あるライブラリが，そのスコープ内で読み込んだライブラリはグローバルのスコープにはなく，副次的に読み込まれたライブラリの機能は，通常の形では

Python の対話モードでは使用できない．
sys.modules から得られるライブラリ名の内，グローバルのスコープで利用できるものを探すには globals() 254 の戻り値との共通部分を算出する．
（次の例参照）
例．グローバルのスコープで読み込まれているモジュールの調査（先の例の続き）>>> gmlst = set(mlst).intersection( set(globals()) ) Enter ←モジュール名のセットを取得>>> print( gmlst ){’sys’}

Enter←モジュール名のセットを表示←結果

この例の結果は，sys モジュールがグローバルのスコープで使用できることを示している．

F.1.5

The Zen of Python

import this を実行すると，Python 言語についての基本的な考え方や，Python 言語におけるプログラミングに対する姿勢（Tim Peters 氏による）が出力される．
例．The Zen of Python>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let’s do more of those!

F.2

ライブラリ情報の取得

Python 環境で利用するライブラリの管理は，基本的には PSF の pip コマンドや Anaconda の conda コマンドなどによる255 が，Python のプログラムからライブラリに関する情報（パッケージ情報，モジュール情報）を取得することもできる．
254 「4.19 使用されているシンボルの調査」（p.301）で解説している．
255 付録 A（p.359〜）を参照のこと．

415

pkg resources による方法

F.2.1

setuptools ライブラリ256 に含まれる pkg resources モジュールを使用すると，当該環境で使用できるライブラリの情報が得られる．このモジュールを用いて利用可能なライブラリの一覧を表示するサンプルプログラムを示す．
プログラム：pkglist.py
12
34# coding : utf -8
import pkg_resources# ライブラリの読み込み
for lib in pkg_resources . working_set :print ( lib . project_name , lib . version )解説．

pkg resources ライブラリのオブジェクト working set には当該環境で使用できるライブラリの情報が保持されている．このプログラムでは pkg resources.working set から要素（パッケージ情報）を 1 つずつ取り出して変数 lib に受け取り，それの project name 属性からライブラリ名を，version 属性からバージョン情報を取得している．
このプログラムを実行すると次のように出力される．
実行例．
beautifulsoup4 4.12.3
certifi 2024.2.2
chardet 5.2.0…（途中省略）…
tzdata 2023.4
tzlocal 5.2
urllib3 2.2.0

pkg resources を使用する方法は古いものであり，Python 3.8 以降では次に示す方法（pkgutil，importlib による方法）が推奨される．

F.2.2

pkgutil，importlib による方法

pkgutil はライブラリ（パッケージ，モジュール）の管理に関する機能を提供するものである．pkgutil の iter modules
関数を使用すると，読み込み可能な全てのライブラリの情報を取得することができる．この関数を引数なしで実行す
ると，個々のライブラリの情報を保持する ModuleInfo オブジェクトの並びを表すジェネレータが返される．個々のラ
イブラリの名前は ModuleInfo オブジェクトの name プロパティから得られる．
例．読込み可能なライブラリの名前の一覧表示>>> import pkgutilEnter← pkgutil モジュールの読込み>>> im = pkgutil.iter modules()Enter← ModuleInfo オブジェクトのジェネレータの取得>>> for m in im: Enter←個々の ModuleInfo オブジェクトの...
print(m.name)
Enter
name プロパティを出力
...
Enter
← for 文の記述の終了
asynciobz2
ctypes←ライブラリ一覧の表示（ここから）：（途中省略）：

pywin
start pythonwin
win32ui
win32uiole

ModuleInfo オブジェクトの module ﬁnder プロパティの path プロパティからはそのライブラリが格納されている
パスが得られる．上記の例の for 文のスイートの中に

print(m_module finder.path)
256 setuptools ライブラリがインストールされていない環境もあるので，その場合は手動で（pip などによって）これをインストールする必要がある．

416

の様な記述を追記して試されたい．

pkgutil ではライブラリのバージョン情報が得られないので，それら情報を取得するには次に解説する importlib を使用する．

importlib ライブラリも pkgutil と並んでライブラリ（パッケージ，モジュール）の管理に関する機能を提供するものであり，このライブラリの metadata モジュールが提供するいくつかの関数（下記）を紹介する．

version( ライブラリ名 )requires( ライブラリ名 )ﬁles( ライブラリ名 )：：：ライブラリのバージョン情報を返す．
ライブラリが依存する他のライブラリの情報を返す．
当該ライブラリを構成するファイルのリストを返す．

Python 用の数式処理ライブラリである sympy がインストールされている環境で sympy の情報を調べる例を次に示す．
例．sympy ライブラリの情報を調べる>>> import importlib.metadataEnter>>> importlib.metadata.version(’sympy’)’1.12’←ライブラリの読込みEnter← sympy のバージョン情報の調査>>> importlib.metadata.requires(’sympy’)Enter← sympy を支えるライブラリの調査[’mpmath (>=0.19)’]← 0.19 以上の版の mpmath が必要
例．sympy ライブラリを構成するファイルを調べる（先の例の続き）>>> fList = importlib.metadata.files(’sympy’)Enter← sympy の構成ファイルリストを取得>>> for f in fList: Enter←個々のファイルを...
print(f)
Enter
表示する
...
Enter
← for 文の記述の終了../../Scripts/isympy.exe←構成ファイルの一覧（ここから）../../share/man/man1/isympy.1
pycache /isympy.cpython-311.pyc
isympy.py
sympy-1.12.dist-info/AUTHORS
sympy-1.12.dist-info/INSTALLER：（途中省略）：
sympy/vector/tests/test vector.py
sympy/vector/vector.py
ﬁles 関数が返すリストの要素は PackagePath オブジェクトであることに注意すること．

417

F.3

各種ライブラリの紹介
表 68: 各種ライブラリ
科学技術関連ライブラリ名用途

配布元

matplotlib

グラフ作成／作図

http://matplotlib.org/

NumPy

数値計算（線形代数）

http://www.numpy.org/

SciPy

各種工学のための数値解析

https://www.scipy.org/

SymPy

数式処理

http://www.sympy.org/
データ処理

ライブラリ名用途

配布元

scikit-learn

モデリングと機械学習

http://scikit-learn.org/

pandas

表形式データの処理

http://pandas.pydata.org/

seaborn

統計学に適した可視化ツール

https://seaborn.pydata.org/

画像処理関連ライブラリ名用途

配布元

Pillow

画像処理

https://python-pillow.org/

OpenCV

画像処理, カメラキャプチャ, 画像認識

http://opencv.org/

ニューラルネットワーク関連
ライブラリ名用途

配布元

PyTorch

深層ニューラルネットワーク

https://pytorch.org/

Keras

深層ニューラルネットワーク

https://keras.io/

マルチメディア／ゲーム関連
ライブラリ名用途

配布元

pygameマルチメディアとゲーム

http://www.pygame.org/

プログラムの高速化／共有ライブラリの呼び出しライブラリ名用途

配布元

CythonPython プログラムの高速実行（C 言語変換）

http://cython.org/

Numba

Python プログラムの高速実行（LLVM の応用）

https://numba.pydata.org/

ctypes

共有ライブラリの呼び出し

標準ライブラリ

アプリケーションのビルド
ライブラリ名

用途

配布元

PyInstaller

単独実行可能なアプリケーションの構築

https://www.pyinstaller.org/

418

G

対話モードを使いやすくするための工夫

G.1

警告メッセージの抑止と表示

Python 処理系はプログラムの実行中にエラーや例外が発生するとその処理を中断するが，これとは別に警告メッセージ（warning）を発行して処理を継続することがある．特に，各種ライブラリを使用する際に警告メッセージが時折表示される．これは，当該ライブラリの開発者の利用者に対する注意喚起などといった意図によるものであり，Python の利用者は警告メッセージを読んでプログラミングにおける判断のための参考にするべきである．
しかし，Python 処理系を対話モードで使用する際，あまりにも多くの警告メッセージが表示されると表示内容の視認性が低下するので，一時的に警告メッセージの表示を抑止した方が良い場面もある．

Python 処理系に標準的に添付されているライブラリ warnings を用いると，警告メッセージの表示を抑止する，あるいは独自の警告メッセージを発行することができる．warnings ライブラリを利用する例をプログラム warnings01.pyに示す．
プログラム：warnings01.py
1
2
3
4
5
6
7
8
9
10
11
12

# coding : utf -8
import warnings# ライブラリの読込み# 警告メッセージの抑止# warnings . filterwarnings ( ’ ignore ’)warnings . warn ( ’ こ れ は 警 告 メ ッ セ ー ジ ( a1 ) で す ． ’ )warnings . warn ( ’ こ れ は 警 告 メ ッ セ ー ジ ( a2 ) で す ． ’ )# 警告メッセージの制御を初期状態に戻す# warnings . resetwarnings ()warnings . warn ( ’ こ れ は 警 告 メ ッ セ ー ジ ( b1 ) で す ． ’ )warnings . warn ( ’ こ れ は 警 告 メ ッ セ ー ジ ( b2 ) で す ． ’ )このプログラムの 6〜7 行目と 11〜12 行目は独自の警告メッセージを表示する部分であり，warn を実行すると引数に与えた警告メッセージを発行することができる．このプログラムを実行すると次のように表示される．
C:￥warnings01-test.py:6: UserWarning: これは警告メッセージ (a1) です．
warnings.warn(’ これは警告メッセージ (a1) です．’)
C:￥warnings01-test.py:7: UserWarning: これは警告メッセー ジ (a2) です．
warnings.warn(’ これは警告メッセージ (a2) です．’)
C:￥warnings01-test.py:11: UserWarning: これは警告メッセージ (b1) です．
warnings.warn(’ これは警告メッセージ (b1) です．’)
C:￥warnings01-test.py:12: UserWarning: これは警告メッセージ (b2) です．
warnings.warn(’ これは警告メッセージ (b2) です．’)

プログラムの 5 行目はコメントであるが，先頭の ‘#’ を外すとwarnings.filterwarnings(’ignore’)が有効になり，ﬁlterwarnings の実行によって以降の警告メッセージが表示されなくなる．
（確認されたい）更に 10 行目先頭の ‘#’ を外すとwarnings.resetwarnings()が有効になり，resetwarnings の実行により，それ以後は警告メッセージが再び表示されるようになる．
（次の実行例を参照のこと）
C:￥warnings01-test.py:11: UserWarning: これは警告メッセージ (b1) です．
warnings.warn(’ これは警告メッセージ (b1) です．’)
C:￥warnings01-test.py:12: UserWarning: これは警告メッセージ (b2) です．
warnings.warn(’ これは警告メッセージ (b2) です．’)※ システムが発行する警告メッセージは必ず読み，その内容を把握すること．warnings に関する詳細はPython の公式インターネットサイトなどを参照のこと．

419

G.2

メモリの使用状態の管理

Python 処理系は，対話モードをはじめとする対話的なデータ処理環境257 で用いられることが多い．そのような利用形態では，サイズの大きなデータを Python の各種データ構造として次々と読み込んで使用するが，その際，Python
処理系が使用している主記憶上のメモリのサイズには注意を払う必要がある．具体的には，Python 処理系がデータオ
ブジェクトを保持するために使用するメモリの大きさに注意を払う必要がある．

Python 処理系のメモリの使用量が大きくなると，それらを主記憶（RAM）上に確保できずに仮想記憶のスワップ258が発生することがあり，これが頻発すると Python 処理系の動作が遅くなる．Python 処理系のメモリの使用を最適なものにするために，以下のような点に注意するべきである．
● Python が使用しているメモリの大きさを適宜調査する● 不要になったオブジェクトは廃棄する

p.409 に示したの応用例 mstat.py によって，Python 処理系が使用しているアクティブな物理記憶のサイズと仮想記憶の全サイズを得ることができるが，これとは別に memory-proﬁler 259 を使用すると Python 処理系のメモリの使用状況を調べることができる．これは標準ライブラリではないのでインストール作業260 が必要である．
以下に memory-proﬁler の使用例を示す．
例．memory-proﬁler によるメモリ使用状況の調査>>> from memory profiler import memory usage>>> m = memory usage(proc=-1)

Enter

Enter

← memory proﬁler の読込み261←使用しているメモリサイズを m に取得>>> print( m )Enter ←値の確認[22.3515625] ←約 21MiB 使用している
これは，Python 処理系を起動した直後に memory-proﬁler を読み込み，memory usage を実行して使用メモリサイズを調べた例である．次に，非常に大きなサイズのリストを作成し，その直後の使用メモリサイズを調べる．
例．大きなデータを作成した直後のメモリ使用状況（先の例の続き）>>> a = [float(x) for x in range(10**8)]>>> m = memory usage(proc=-1)

Enter

Enter

←要素数が 108 個のリストを作成←使用しているメモリサイズを m に取得>>> print( m )Enter ←値の確認[3849.20703125] ←約 3.75GiB 程使用している
a に要素数が 108 個のリストが作成されており，Python 処理系のメモリの使用量が約 3.5GB に増加したことがわかる．この a を del 文により削除するとメモリの使用量が削減される．
（次の例参照）
例．大きなデータを削除した直後のメモリ使用状況（先の例の続き）>>> del aEnter←巨大なリスト a を削除>>> m = memory usage(proc=-1)

Enter←使用しているメモリサイズを m に取得>>> print( m )Enter ←値の確認[24.26953125] ←約 24MiB 程度になった
memory-proﬁler に関する詳細は当該ソフトウェアの公式インターネットサイトなどの情報を参照のこと．
G.2.1

オブジェクトのサイズの調査

sys モジュールの getsizeof を用いると，個々のオブジェクトのサイズを調べることができる．

257 IPython，JupyterLab などを含む．これらに関しては他のドキュメントを参照のこと．
258 主記憶と補助記憶の間でのデータの交換．
259 公式インターネットサイト：https://pypi.org/project/memory-proﬁler/
260 「A.4 PIP によるライブラリ管理」（p.363）を参照のこと．
261 ライブラリの名称は memory-proﬁler であるが，読み込み時は memory proﬁler とアンダースコアを用いた表記であることに注意すること．

420

例．変数に与えられているオブジェクトのサイズを調べる

Enter>>> import sys>>> a = 123

Enter←モジュールの読み込み←変数 a に整数型オブジェクトを割り当てる>>> sys.getsizeof( a )Enter←そのサイズを調べる
28←変数 a が持つオブジェクトのサイズ：28 バイト
この例のように，getsizeof は引数に与えられたオブジェクトのサイズをバイト単位で返す．
▲注意▲

getsizeof は調査対象のオブジェクトが参照しているオブジェクトは調査対象としない．
（次の例参照）
例．オブジェクト全体のサイズが得られないケース（先の例の続き）>>> lst = [[float(n+m*100) for n in range(100)] for m in range(100)] Enter ←大きなリスト>>> sys.getsizeof( lst )Enter←そのサイズを調べる
920←全要素を含めたサイズにはなっていない
オブジェクト全体のサイズを調べるには，当該オブジェクトが参照しているオブジェクトに関しても再帰的にサイズを調べて，それらを合計する必要がある．このための方法に関しては Python の公式インターネットサイトの sys.getsizeofの項に例が紹介されている．実際のソースコードも GitHub の下記の URL で公開されている．

https://github.com/ActiveState/recipe-577504-compute-mem-footprint/blob/master/recipe.py
このソースコード ‘recipe.py’ の中に定義されている関数 total size を読み込んで上の例のリストのサイズを調べる例
を示す．
例．total size の実行例>>> from recipe import total size>>> total size( lst )332920

Enter

Enter

←ソースコードをモジュールとして読み込む←リストのサイズを調べる← 300 キロバイト以上ある

421

文書化文字列と関数アノテーション

H

Python には help 関数があり，関数やクラスの説明を出力することができる．次の例は，Python の組み込み関数
print に関する説明文を表示するものである．
例．print 関数の説明を表示する← help 関数による説明文の表示

Enter>>> help(print)

Help on built-in function print in module builtins:←ここから説明文の表示

print(*args, sep=’ ’, end=’￥n’, file=None, flush=False)
Prints the values to a stream, or to sys.stdout by default.
：（以下省略）：
プログラマが作成した関数やクラスにも説明文を与えることができる．例えば，引数に与えた値を 2 倍する関数 dbl
を次のように定義する．
例．値を 2 倍する関数 dbl の定義>>> def dbl(n): Enter←関数 dbl の定義...
return 2*n
Enter
...
Enter
←関数定義の記述の終了>>> dbl(3)6Enter←関数 dbl の評価（実行）←戻り値

この関数には未だ説明文が与えられておらず，help 関数で説明を求めると次のようになる．
例．関数 dbl の説明を求める試み（先の例の続き）← help 関数による説明文の表示を試みると…

Enter>>> help(dbl)

Help on function dbl in module

main :←出力される説明はこれだけ

dbl(n)

関数 dbl に「n を 2 倍する関数」という説明文を与えるには次のような形で関数定義を行う．
例．値を 2 倍する関数 dbl の定義（説明機能つき）←関数 dbl の定義

Enter>>> def dbl(n):...

’n を 2 倍する関数’...

return 2*n...

←定義内容の先頭に説明文の文字列を配置する

Enter

Enter

←関数定義の記述の終了

Enter>>> dbl(3)

Enter

6

←戻り値

>>> help(dbl)←関数 dbl の評価（実行）Enter← help 関数による説明文の表示

Help on function dbl in moduledbl(n)n を 2 倍する関数

main :←説明文が表示されている

このように，関数の定義内容の先頭に説明文の文字列（文書化文字列：docstring ）を記述すると，help による説明表
示の際にそれが出力される．
文書化文字列は複数行に渡ることが一般的であり，そのような説明文を記述する際は「’’’〜’’’」の形式（3 重引用符）で文字列を記述する．
文書化文字列は，その関数の例． docdoc

プロパティに保持されている．

プロパティの参照（先の例の続き）>>> dbl. doc
Enter’n を 2 倍する関数’←文書化文字列を参照
←結果

422

関数アノテーション（Function Annotations）

H.1

関数定義を記述する際，仮引数と戻り値にアノテーション（注釈）を付けることができ，help による説明表示の際にそれを出力することができる．
例．関数アノテーション付きの定義>>> def dbl( n:’ 数値’ ) -> ’ 数値’:...
’n を 2 倍する関数’
Enter
...
return 2*n
Enter
...
Enter
←関数定義の記述の終了>>> help(dbl)

Enter

Enter

←仮引数と戻り値にアノテーションを付けている← help 関数による説明文の表示

Help on function dbl in moduledbl(n: ’ 数値’) -> ’ 数値’
n を 2 倍する関数

main :←アノテーションが表示されている←説明文が表示されている

このように，各仮引数の後ろにコロン「:」を記述し，続けて説明文の文字列を記述する．戻り値に関するアノテーショ
ンは，仮引数の後ろの閉じ括弧「)」の次に「->」を記述し，続けて説明文の文字列を記述する．
関数アノテーションは，その関数の例． annotations

annotations

プロパティに保持されている．

プロパティの参照（先の例の続き）

Enter>>> dbl. annotations←関数アノテーションを参照{’n’: ’ 数値’, ’return’: ’ 数値’}
←辞書の形で得られる
このように， annotations

から辞書の形（キーは仮引数の名前，戻り値のキーは ’return’）で関数アノテーションが得られる．
クラス定義に文書化文字列を与える場合は class 文の直後にそれを記述する．また，メソッドに対しては，関数定義の場合に準じた形で文書化文字列と関数アノテーションを与える．
参考．

Python に標準添付の typing モジュールを用いて関数アノテーションを記述することが推奨されている．ただし本書ではこれに関しては言及しない．
（必要な場合は公式インターネットサイトなどを参照のこと）

423

I

サンプルプログラム

I.1

リスト／セット／辞書のアクセス速度の比較

I.1.1

スライスに整数のインデックスを与える形のアクセス「n 番目の要素」という形で要素にアクセスする場合の速度比較を行うプログラムが spdTest00.py である．このプ
ログラムは長い（106 個の要素を持つ）リスト L，辞書 D を作成し，それらの n 番目の要素にランダムにアクセスするものである．またランダムなアクセスを，その要素の個数と同じ回数（106 回）リスト，辞書それぞれに対して行
い，実行時間を計測する．
プログラム：spdTest00.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# coding : utf -8
import time
import secrets###################################################### 実行速度テスト（インデックスによる）####################################################### - - - イ ン デ ッ ク ス の ラ ン ダ ム ア ク セ ス --def spdTestIdx ( Data ):n = len ( Data )t1 = time . time ()for c in range ( n ):I = secrets . randbelow ( n )Data [ I ] = I
t2 = time . time ()return t2 - t1
def spdTestIdxAvr ( Data , n ):tL = []
for c in range ( n ):t = spdTestIdx ( Data )print ( c +1 , ’ 回 目 : \ t ’ , t , ’ 秒 ’ )tL . append ( t )avr = sum ( tL ) / n
print ( ’ 平 均 : \ t ’ , avr , ’ 秒 ’ )return avr# - - - 実 行 時 間 テ ス ト --N = 1000000
L = list ( range ( N ) )D = { x : x for x in range ( N ) }# データサイズ
# リスト
# 辞書

print ( ’ リ ス ト の 場 合 の テ ス ト ’ )print ( ’ - - - - - - - - - - - - - - - - - - - - ’ )aL = spdTestIdxAvr ( L , 3 )print ( ’\ n 辞 書 の 場 合 の テ ス ト ’ )print ( ’ - - - - - - - - - - - - - - - - - - - - ’ )aD = spdTestIdxAvr ( D , 3 )print ( ’ リ ス ト の 場 合 に 対 す る 速 度 比 : \ t ’ , aL / aD , ’ 倍 ’ )このプログラムの実行例を次に示す．

424

例．spdTest00.py の実行例

C:￥Users￥katsu>py spdTest00.py←コマンドからスクリプトを起動

Enter

リストの場合のテスト-------------------1 回目: 0.5842320919036865 秒
2 回目: 0.5850205421447754 秒
3 回目: 0.57867431640625 秒
平均:
0.5826423168182373 秒
辞書の場合のテスト-------------------1 回目: 0.7023506164550781 秒
2 回目: 0.7070534229278564 秒
3 回目: 0.7088878154754639 秒
平均:
0.7060972849527994 秒
リストの場合に対する速度比:0.8251586987155534 倍※ 実行環境： Python 3.11.2, Intel Corei7-1195G7 2.9GHz, 32GB RAM, Windows11 Pro（評価）
リストの方が辞書に比べて若干早いことがわかる．

I.1.2

メンバシップ検査に要する時間

データ構造の中に特定の要素があるかどうかを調べるのに要する時間を調べるプログラムが spdTest01.py である．
このプログラムでは 30,000 個の要素を持つデータ構造に対して要素の含有検査（メンバシップ検査）を行う．リスト

L，セット S，辞書 D はそれぞれ 0〜29,999 の整数を要素として持ち，発生した整数の乱数がそのデータ構造に含まれるかどうかを検査する．メンバシップ検査は要素の個数と同じ回数繰り返して，その実行に要した時間を計測する．
プログラム：spdTest01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# coding : utf -8
import time
import secrets###################################################### 実 行 速 度 テ ス ト(1)####################################################### - - - メ ン バ シ ッ プ 検 査 の 速 度 テ ス ト --def spdTest ( Data ):n = len ( Data )t1 = time . time ()for c in range ( n ):chk = secrets . randbelow ( n ) in Datat2 = time . time ()return t2 - t1
def spdTestAvr ( Data , n ):tL = []
for c in range ( n ):t = spdTest ( Data )print ( c +1 , ’ 回 目 : \ t ’ , t , ’ 秒 ’ )tL . append ( t )avr = sum ( tL ) / n
print ( ’ 平 均 : \ t ’ , avr , ’ 秒 ’ )return avr# - - - 実 行 時 間 テ ス ト --N = 30000
L= list ( range ( N ) )S= set ( L )D= { x : x for x in range ( N ) }
i = 3

#
#
#
#
#

要素の個数
リスト
セット
辞書
検査実行回数

print ( ’ リ ス ト の 場 合 の テ ス ト ’ )print ( ’ - - - - - - - - - - - - - - - - - - - - ’ )aL = spdTestAvr ( L , i )

425

37
38
39
40
41
42
43
44
45

print ( ’\ n セ ッ ト の 場 合 の テ ス ト ’ )print ( ’ - - - - - - - - - - - - - - - - - - - - ’ )aS = spdTestAvr ( S , i )print ( ’ リ ス ト の 場 合 に 対 す る 速 度 比 : \ t ’ , aL / aS , ’ 倍 ’ )print ( ’\ n 辞 書 の 場 合 の テ ス ト ’ )print ( ’ - - - - - - - - - - - - - - - - - - - - ’ )aD = spdTestAvr ( D , i )print ( ’ リ ス ト の 場 合 に 対 す る 速 度 比 : \ t ’ , aL / aD , ’ 倍 ’ )このプログラムの実行例を次に示す．
例．spdTest01.py の実行例

C:￥Users￥katsu>py spdTest01.py

Enter←コマンドからスクリプトを起動

リストの場合のテスト-------------------1 回目: 1.7754509449005127 秒
2 回目: 1.777921199798584 秒
3 回目: 1.7940375804901123 秒
平均:
1.782469908396403 秒
セットの場合のテスト-------------------1 回目: 0.015633106231689453 秒
2 回目: 0.015620708465576172 秒
3 回目: 0.015627622604370117 秒
平均:
0.015627145767211914 秒
リストの場合に対する速度比:114.06241004907571 倍
辞書の場合のテスト-------------------1 回目: 0.019140958786010742 秒
2 回目: 0.012587308883666992 秒
3 回目: 0.015713214874267578 秒
平均:
0.015813827514648438 秒
リストの場合に対する速度比:112.71590680657742 倍※ 実行環境： Python 3.11.2, Intel Corei7-1195G7 2.9GHz, 32GB RAM, Windows11 Pro（評価）
セットと辞書は共に同等の実行速度であり，リストに比べて100 倍以上早いことがわかる．
次に，spdTest01.py で調べた実行時間が，データの個数が増えるのに対してどのように伸びてゆくかを調べる．次のサンプルプログラム spdTest02.py で調べる．
（グラフ描画に matplotlib を要する）
プログラム：spdTest02.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# coding : utf -8
import time
import secrets
import matplotlib . pyplot as plt###################################################### 実 行 速 度 テ ス ト(2)####################################################### - - - メ ン バ シ ッ プ 検 査 の 速 度 テ ス ト --def spdTest ( Data ):n = len ( Data )t1 = time . time ()for c in range ( n ):chk = secrets . randbelow ( n ) in Datat2 = time . time ()return t2 - t1
def spdTestAvr ( Data , n ):tL = []
for c in range ( n ):t = spdTest ( Data )tL . append ( t )

426

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

avr = sum ( tL ) / n
return avr# - - - 実 行 時 間 テ ス ト --N = 10000
X = range (0 ,N ,100)
A1 = [];
A2 = [];
A3 = []
for n in X :D = list ( range ( n ) )A1 . append ( spdTestAvr ( D , 3
D = set ( D )A2 . append ( spdTestAvr ( D , 3
D = { x : x for x in range ( n )A3 . append ( spdTestAvr ( D , 3# 要素の個数# 実行時間のリスト

) )
) )
}
) )

plt . plot ( list ( X ) , A1 , label = ’ List ’)
plt . plot ( list ( X ) , A2 , label = ’ Set ’)plt . plot ( list ( X ) , A3 , label = ’ Dict ’)plt . legend ()plt . title ( ’ test for List / Set / Dict ’)plt . show ()このプログラムの実行結果の例を図 76 に示す．
（実行環境は先と同じ）

図 76: spdTest02.py の実行結果
横軸はデータの個数，縦軸は実行時間（評価）
データ個数の増加に対してセットと辞書では検査の実行時間の伸びが小さいのに対して，リストでは概ねデータ個数の 2 乗に比例する形で実行時間が大きくなる．リストに対する in 演算子による要素の探索は，線形探索ア
ルゴリズムと同規模の計算時間となることがわかる．

427

I.2

ライブラリ使用の有無における計算速度の比較

ここでは，Python 用の代表的な数値計算ライブラリである NumPy を使用することで大きな計算速度が得られる
例を示す．次に示すプログラム matmult01.py は 800 × 800 の行列同士の積
⎛
⎞
⎛
⎞⎛
b0,0
c0,0
a0,0
c0,1 · · ·c0,799a0,1 · · ·a0,799⎜⎟⎜⎟⎜⎜⎜ c1,0⎜ a1,0c1,1 · · ·c1,799 ⎟a1,1 · · ·a1,799 ⎟⎜⎟⎜⎟ ⎜ b1,0
=
⎜
⎜ .
⎟
⎜
⎟
.
.
.
.
.
..
..
⎜ ..
⎜ ..
..
.. ⎟
..
.. ⎟ ⎜ ...
.
.
⎝
⎠
⎠⎝
⎝
c799,0 c799,1 · · · c799,799
a799,0 a799,1 · · · a799,799
b799,0

b0,1

···

b1,1
..
.

···
..
.

b799,1···b0,799⎞⎟b1,799 ⎟
⎟
.. ⎟
. ⎟
⎠
b799,799を求めるものである．
プログラム：matmult01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# coding : utf -8
import timeW = 800 # 配 列 の サ イ ズ
M1 = [];
M2 = [];
M3 = []# サンプル行列の作成
for i in range ( W ):L1 = [];
L2 = [];
L3 = []
for j in range ( W ):L1 . append ( float ( i + j ))L2 . append ( float (i - j ))L3 . append ( float (0))
M1 . append ( L1 ); M2 . append ( L2 ); M3 . append ( L3 )# 行列の積の計算
t1 = time . time ()print ( ’ start ’)for i in range ( W ):for j in range ( W ):for k in range ( W ):M3 [ i ][ j ] += M1 [ i ][ k ] * M2 [ k ][ j ]t2 = time . time ()print ( ’ stop ’)print ( ’ time ( sec ): ’ , t2 - t1 )# 先頭部分の表示
for i in range (5):for j in range (5):print (f ’{ M3 [ i ][ j ]:.1 f } , ’, end = ’ ’)
print ( ’ ’)

このプログラムではリスト M1, M2, M3 で行列を表現している．はじめに M1, M2 に値を設定（6〜14 行目）し，それらの積を M3 に得る（19〜22 行目）．
このプログラムを実行した様子を次に示す．
start←行列の積の計算開始
stop
←計算終了
time(sec): 132.11081528663635←計算にかかった時間
170346800.0, 170027200.0, 169707600.0, 169388000.0, 169068400.0,
170666400.0, 170346000.0, 170025600.0, 169705200.0, 169384800.0,
170986000.0, 170664800.0, 170343600.0, 170022400.0, 169701200.0,
171305600.0, 170983600.0, 170661600.0, 170339600.0, 170017600.0,
171625200.0, 171302400.0, 170979600.0, 170656800.0, 170334000.0,←計算結果の←最初の 5 × 5 の←部分

このプログラムを Python 3.11.2, Intel Corei7-1195G7 2.9GHz, 32GB RAM, Windows11 Pro の環境で 3 回実行して得られた計算時間の平均値は 134.5376 秒であった．
次に，同様の計算を行うプログラムを NumPy を用いて実装した例が次に示す matmult01 np.py である．

428

プログラム：matmult01 np.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# coding : utf -8
import time
import numpy as np
W = 800 # 配 列 の サ イ ズ
M1 = [];
M2 = [];
M3 = []# サンプル行列の作成
for i in range ( W ):L1 = [];
L2 = [];
L3 = []
for j in range ( W ):L1 . append ( float ( i + j ))L2 . append ( float (i - j ))L3 . append ( float (0))
M1 . append ( L1 ); M2 . append ( L2 ); M3 . append ( L3 )N1 = np . array ( M1 ); N2 = np . array ( M2 )# 行列の積の計算
t1 = time . time ()print ( ’ start ’)
N3 = np . dot ( N1 , N2 )t2 = time . time ()print ( ’ stop ’)print ( ’ time ( sec ): ’ , t2 - t1 )# 先頭部分の表示
for i in range (5):for j in range (5):print (f ’{ N3 [ i ][ j ]:.1 f } , ’, end = ’ ’)
print ( ’ ’)

このプログラムの前半部（M1，M2 の作成）は先の matmult01.py と同じであるが，それらを NumPy 独自の配列オ
ブジェクト N1，N2 に変換し，積を N3 に得ている．また，行列の積を求める部分には NumPy の dot 関数を用いている（21 行目）．
（NumPy に関する詳細は公式インターネットサイトをはじめとする他の資料262 を参照のこと）
このプログラムを実行した様子を次に示す．
start←行列の積の計算開始
stop
←計算終了
time(sec): 0.015180349349975586←計算にかかった時間
170346800.0, 170027200.0, 169707600.0, 169388000.0, 169068400.0,
170666400.0, 170346000.0, 170025600.0, 169705200.0, 169384800.0,
170986000.0, 170664800.0, 170343600.0, 170022400.0, 169701200.0,
171305600.0, 170983600.0, 170661600.0, 170339600.0, 170017600.0,
171625200.0, 171302400.0, 170979600.0, 170656800.0, 170334000.0,←計算結果の←最初の 5 × 5 の←部分

このプログラムを先と同じ環境で 3 回実行して得られた計算時間の平均値は 0.0144 秒であった．この値は先のプログラムと比較すると約 9341 倍である．
参考までに，同じ処理を行うプログラムを C 言語で実装（matmult01.c）して実行した例を次に示す．
プログラム：matmult01.c
1
2
3
4
5
6
7
8
9
10
11

# include < stdio .h ># include < time .h ># define W 800
int main () {int i , j , k ;static double
M1 [ W ][ W ] , M2 [ W ][ W ] , M3 [ W ][ W ];clock_t t1 , t2 ;/* サ ン プ ル 行 列 の 作 成 */262 拙書「Python3 ライブラリブック - 各種ライブラリの基本的な使用方法」でも解説しています．

429

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

for ( i =0; i < W ; i ++ ) {for ( j =0; j < W ; j ++ ) {M1 [ i ][ j ] = ( double ) i + ( double ) j ;M2 [ i ][ j ] = ( double ) i - ( double ) j ;}}/* 行 列 の 積 の 計 算 */printf (" start \ n ");fflush ( stdout );t1 = clock ();for ( i =0; i < W ; i ++ ) {for ( j =0; j < W ; j ++ ) {M3 [ i ][ j ] = 0.0;
for ( k =0; k < W ; k ++ ) {M3 [ i ][ j ] += M1 [ i ][ k ] * M2 [ k ][ j ];}}}t2 = clock ();printf (" stop \ n ");fflush ( stdout );printf (" time ( sec ): %8.4 f \ n " , ( double )( t2 - t1 ) / CLOCKS_PER_SEC );/* 先 頭 部 分 の 表 示 */for ( i =0; i <5; i ++ ) {for ( j =0; j <5; j ++ ) {printf ("%.1 f , " , M3 [ i ][ j ]);}printf ("\ n ");}return 0;}

このプログラムを先と同じ環境の MinGW64 下でコンパイル（gcc 12.2.0，オプション -O3）して実行した様子を次
に示す．
start
←行列の積の計算開始
stop
←計算終了
time(sec):
0.3040←計算にかかった時間
170346800.0, 170027200.0, 169707600.0, 169388000.0, 169068400.0,
170666400.0, 170346000.0, 170025600.0, 169705200.0, 169384800.0,
170986000.0, 170664800.0, 170343600.0, 170022400.0, 169701200.0,
171305600.0, 170983600.0, 170661600.0, 170339600.0, 170017600.0,
171625200.0, 171302400.0, 170979600.0, 170656800.0, 170334000.0,←計算結果の←最初の 5 × 5 の←部分

3 回実行して得られた計算時間の平均値は 0.304 秒であった．これは最初のプログラム matmult01.py と比較すると
約 443 倍の実行速度である．ここに挙げた 3 つのプログラムの実行時間などを表 69 にまとめる．

プログラム

表 69: 実験結果の比較
特徴
実行時間（秒） 速度比（倍）matmult01.py

行列をリストで表現

134.5376（基準）1

matmult01 np.py

NumPy を用いて計算

0.01449341

matmult01.c

C 言語による実装

0.304

443

430

I.3

os.walk 関数の応用例

os モジュールの walk 関数263 を用いると，指定したディレクトリ内の全ての項目（配下のディレクトリ，ファイル）を独自のタプルの形式で列挙することができる．この関数を応用して，指定したディレクトリ内の全ての項目を

1 つずつ取得するジェネレータを実装する例を次の walkdir.py に示す．
プログラム：walkdir.py
1
2
3
4
5
6
7
8
9

# coding : utf -8
import os
def walkdir ( d ):for dpath , dnames , fnames in os . walk ( d ):for fname in fnames :yield os . path . join ( dpath , fname )for dname in dnames :yield os . path . join ( dpath , dname )walkdir.py に定義された walkdir 関数は，引数に与えられたパス（文字列形式）が示すディレクトリ配下の項目をもたらすジェネレータを返す．
例えば，カレントディレクトリに右図のような階層構造（’<…>’ はディレクトリ）を持つディレクトリ exdir（p.106 に例示したものと同じ）がある場合の walkdir 関数の実行例を次に示す．

< exdir >|+ - <emp >|+ - file1 . txt|+ - < subdir >|+ - file2 . txt|+ - file3 . txt|+ - < subsubdir >|+ - file4 . txt

例．walkdir 関数の実行例>>> import walkdir

Enter←上記ファイルをモジュールとして読み込む>>> for x in walkdir.walkdir(’./exdir’): Enter...
print(x)Enter←内容項目の出力...
Enter← for 文の記述の終了←ディレクトリ内容の一覧処理./exdir/file1.txt←↓ディレクトリ内の全項目が列挙される./exdir/emp./exdir/subdir./exdir/subdir/file2.txt./exdir/subdir/file3.txt./exdir/subdir/subsubdir./exdir/subdir/subsubdir/file4.txt
これは，カレントディレクトリにある exdir ディレクトリに含まれる全ての項目（全てのサブディレクトリ，ファイル）を列挙した例である．

263 「2.6.7.4 ディレクトリ内容の一覧 (2)」（p.106）で解説している．

431

I.4

pathlib の応用例

pathlib モジュールの機能を使用したサンプルプログラムを示す．指定したディレクトリ配下に存在するパスのうち，指定したパターンに合致するファイル名（あるいはディレクトリ名）のものを探し出す（サブディレクトリ配下も再帰的に探し出す）プログラムの例を示す．
プログラム：pﬁnd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# coding : utf -8# モジュールの読込みfrom pathlib import Path
# 主な処理を行う関数
def pfind0 ( path , ptn ):r = list ( path . glob ( ptn ) )pall = path . glob ( ’* ’)for m in pall :if m . is_dir ():r += pfind0 ( m , ptn )return r

#
#
#
#
#
#

まずは当該ディレクトリ内で検索
ディレクトリ内の全ての要素を列挙
1つ ず つ 調 べ な が ら
それがディレクトリならば再帰的にサブフォルダを検索リストとして値を返す# 入り口となる関数
def pfind ( p , ptn ):return pfind0 ( Path ( p ) , ptn )このプログラムはモジュールとして使用することができる．ファイル検索のための関数が pﬁnd として定義されており，pﬁnd( 検索対象のディレクトリ, パターン )として呼び出す．パターンは glob メソッドに与える形式の文字列であり，glob 独自の正規表現である．pﬁnd 関数は，パターンに合致したパスのリストを戻り値として返す．
（次の例参照）
例．Windows 環境の ‘/Windows’ ディレクトリから ‘cmd.exe’ を探す>>> from pfind import pfindEnter>>> r = pfind(’/Windows’,’cmd.exe’)>>> for m in r:...

print(m)Enter￥Windows￥System32￥cmd.exe￥Windows￥SysWOW64￥cmd.exe:（以下省略）:

Enter←モジュールの読込み
←検索実行

Enter
←表示処理

（記述ここまで）←ここから結果表示

432

I.5

浮動小数点数と 2 進数の間の変換

浮動小数点数から 2 進数への，あるいはその逆の変換を行うサンプルプログラムを示す．
プログラム：f2bin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# coding : utf -8# float -> 2 進 数
def f2bin (v , n ):# 符号取得if v < 0:s = ’-’
v *= -1
else :
s = ’’
vb = bin ( round ( v *2** n ))[2:]# 左シフトで整数化
l = len ( vb )if l <= n :# 桁の長さ調整
vb = ’0 ’*( n - l +1) + vb
# 2 進 数 を 構 成 後 ， 右 端 の ’0 ’ を 除 去 す る 処 理
r = ( s + vb [: - n ]+ ’. ’+ vb [ - n :])[:: -1]
for i , b in enumerate ( r ):if b != ’0 ’:
r = r [ i :]break
return r [:: -1]# 2 進 数 -> float
def bin2f ( b ):# 符号取得if b [0] == ’ - ’:s = -1b = b [1:]else :s = 1
n = b . index ( ’. ’)# 小数点の位置を取得
r = int ( b [: n ] ,2)# 小数点より左の値を算出# 小数点以下を算出
for i , d in enumerate ( b [ n +1:]):
if d == ’1 ’:
r += 2**( -1*( i +1))
return s * r‘f2bin.py’ は 2 つの関数 f2bin（ﬂoat 型の値を 2 進数表記の文字列に変換する），bin2f（2 進数表記の文字列を ﬂoat型の値に変換する）から成る．
書き方：

f2bin( ﬂoat 型の値, 2 進数に変換した際の小数点以下の桁数 )bin2f( 小数点付き 2 進数の文字列 )上記のファイルをカレントディレクトリに配置してモジュールとして扱う．
例．ﬂoat 型から 2 進数への変換>>> from f2bin import f2bin, bin2f>>> b = f2bin( 0.1, 52 )
>>> b

Enter

Enter

←関数の読み込みEnter← 0.1 を 2 進数に変換（小数点以下 52 ビットで表現）←確認’0.000110011001100110011001100110011001100110011001101’>>> bin2f(b)Enter

0.10000000000000009← 2 進数から ﬂoat 型へ変換
←変換結果注意）変換に伴う誤差に注意すること．

433

←変換結果

I.5.1

mpmath を用いた例

mpmath ライブラリを用いると，浮動小数点数を高い精度で 2 進数に変換することができる．基本的には「【参考】浮動小数点数の 2 進数表現」（p.23）で解説した方法（仮数部と指数部の取り出し）を採用する．
以下に 10 進数表現の 0.1 を 2 進数表現に変換する例を示す．
例．10 進数の 0.1 を mpf オブジェクトとして用意する>>> from mpmath import mp>>> mp.dps = 20

←計算精度の設定：10 進表現で 20 桁

Enter

← mpf オブジェクト形式で 10 進数の 0.1 を生成

Enter>>> n = mp.mpf(’0.1’)>>> print( n )← mpmath の読み込み

Enter

←確認

Enter

0.1
mpf オブジェクトの man，exp プロパティから仮数部と指数部を取り出すことができる．
例．仮数部と指数部の参照（先の例の続き）>>> n.man

Enter←仮数部の参照← 10 進数表現

944473296573929042739←指数部の参照>>> n.exp

Enter

-73

← 10 進数表現

得られた仮数部を bin 関数で 2 進数に変換して表示する例を示す．
例．2 進数表現（先の例の続き）>>> print( f’{bin(n.man)}x2**{n.exp}’ )Enter← 2 進変換と整形表示

0b1100110011001100110011001100110011001100110011001100110011001100110011x2**-73
このように，10 進数表現の 0.1 が 2 進数の近似表現

1100110011001100110011001100110011001100110011001100110011001100110011(2) × 2−73
として得られている．

434

I.6

全ての Unicode 文字の列挙

Unicode はコードポイントの値 0〜1114111（16 進数で 0〜10FFFF）の範囲で定義されている．ただし本書執筆時
点では，この範囲の全てのコードポイントに対しては Unicode 文字は割り当てられていない．

unicodedata モジュールの name 関数を利用して，文字が割り当てられている全ての Unicode 文字を取得するプログラムの例を allunicode.py に示す．
プログラム：allunicode.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# coding : utf -8
import unicodedata
all = {}
# 全 て の Unicodeとその名前の辞書
nochr = set ()# 割 り 当 て ら れ て い な い Unicode
for i in range (1114112):c = chr ( i )n = unicodedata . name (c , None )if n :
all [ c ] = nelse :
nochr . add ( c )# 割 り 当 て ら れ て い る 全 て の Unicode文字のリストを返す関数
def allunicode ():return sorted ( list ( all . keys ()))# テスト実行
if __name__ == ’ __main__ ’:f = open ( ’ allunicode_out . txt ’ , ’ wb ’)
a = allunicode ()for c in a :s = str ( ord ( c ))+ ’\ t ’+ c + ’\t ’+ all [ c ]+ ’\ n ’print ( s , end = ’ ’ )b = s . encode ( ’ utf -8 ’)
f . write ( b )f . close ()このプログラムをスクリプトとして実行すると，文字が割り当てられている全ての Unicode 文字とその属性を表示する．また，モジュールとして読み込んで動作を確認することもできる．
このプログラムをモジュールとして読み込むと，文字が割り当てられている Unicode とその属性が辞書 all に得られる．また，文字が割り当てられていない Unicode のセットが nochr に得られる．
例．上のプログラムをモジュールとして読み込む例>>> import allunicode>>> len( allunicode.all )138552←文字が割り当てられている Unicode の数を調べる

Enter←文字が割り当てられている Unicode の数（執筆時点の値）>>> len( allunicode.nochr )975560←プログラムをモジュールとして読み込む

Enter←文字が割り当てられていない Unicode の数を調べる

Enter←文字が割り当てられていない Unicode の数（執筆時点の値）>>> a = allunicode.allunicode()Enter←文字が割り当てられている全 Unicode 文字のリスト>>> n = a.index(’A’); a[n:n+15]Enter←部分的に表示[’A’,’B’,’C’,’D’,’E’,’F’,’G’,’H’,’I’,’J’,’K’,’L’,’M’,’N’,’O’]>>> n = a.index(’ぁ’); a[n:n+12]Enter←対応する文字のリスト←部分的に表示[’ぁ’,’ あ’,’ぃ’,’ い’,’ぅ’,’ う’,’ぇ’,’ え’,’ぉ’,’ お’,’ か’,’ が’]←対応する文字のリスト

文字が割り当てられている Unicode のキャラクタであってもそのためのフォントが導入されていない計算機環境ではその文字を表示（印字）することができないことに留意すること．

435

J

その他

J.1

演算子の優先順位

各種の演算子や括弧などの結合の強さを表 70 に示す．
表 70: 演算子の優先順位：
演
算子( expressions... ),{ key : value... },[ expressions... ],{ expressions... }x[index], x[index:index],
x.attributex(arguments...),

上の方が結合の優先順位が高い
説
明
結合式または括弧式、リスト表示、
辞書表示、集合表示
添字指定、スライス操作、呼び出し、
属性参照

await x

Await 式

**

べき乗

+x,

-x,

*,

@,

+,

-

<<,

正数、負数、ビット単位 NOT

˜x
/,

//,

乗算、行列乗算、除算、切り捨て除算、剰余%加算および減算
シフト演算

>>

&

ビット単位 ANDˆ

ビット単位 XOR|

ビット単位 ORin,<,

not in, is, is not,<=, >, >=, !=,==所属や同一性のテストを含む比較
値の比較

not x

ブール演算 NOT

and

ブール演算 ANDor

ブール演算 OR

if – else

条件式

lambda

ラムダ式

:=

代入式
公式インターネットサイト（https://docs.python.org/）から引用

436

アスキーコード表J.2

表 71: アスキー（ASCII）コードに対応する文字
10進 16進文字

10進 16進文字

10進 16進文字

10進 16進

文字

0

0x00

NUL(null文字)

32

0x20 SPC(空白)

64

0x40

@

96

0x60

̀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

0x01
0x02
0x03
0x04
0x05
0x06
0x07
0x08
0x09
0x0a
0x0b
0x0c
0x0d
0x0e
0x0f

SOH(ヘッダ開始)
STX(テキスト開始)
ETX(テキスト終了)
EOT(転送終了)
ENQ(照会)
ACK(受信確認)
BEL(警告)BS(後退)
HT(水平タブ)
LF(改行)
VT(垂直タブ)FF(改頁)
CR(復帰)SO(シフトアウト)
SI(シフトイン)

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

0x10
0x11
0x12
0x13
0x14
0x15
0x16
0x17
0x18
0x19
0x1a
0x1b
0x1c
0x1d
0x1e

DLE(データリンクエスケープ)
DC1(装置制御１)
DC2(装置制御２)
DC3(装置制御３)
DC4(装置制御４)
NAK(受信失敗)
SYN(同期)
ETB(転送ブロック終了)
CAN(キャンセル)EM(メディア終了)
SUB(置換)ESC(エスケープ)
FS(フォーム区切り)
GS(グループ区切り)
RS(レコード区切り)

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

0x21
0x22
0x23
0x24
0x25
0x26
0x27
0x28
0x29
0x2a
0x2b
0x2c
0x2d
0x2e
0x2f
0x30
0x31
0x32
0x33
0x34
0x35
0x36
0x37
0x38
0x39
0x3a
0x3b
0x3c
0x3d
0x3e

!
"
#
$
%
&
'
(
)
*
+
,
.
/
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

0x41
0x42
0x43
0x44
0x45
0x46
0x47
0x48
0x49
0x4a
0x4b
0x4c
0x4d
0x4e
0x4f
0x50
0x51
0x52
0x53
0x54
0x55
0x56
0x57
0x58
0x59
0x5a
0x5b
0x5c
0x5d
0x5e

A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

0x61
0x62
0x63
0x64
0x65
0x66
0x67
0x68
0x69
0x6a
0x6b
0x6c
0x6d
0x6e
0x6f
0x70
0x71
0x72
0x73
0x74
0x75
0x76
0x77
0x78
0x79
0x7a
0x7b
0x7c
0x7d
0x7e

a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~

31

0x1f

US(ユニット区切り)

63

0x3f

?

95

0x5f

̲

127

0x7f

DEL(削除)網掛け部分は，制御文字を含む非印字可能文字である．

92(0x5c) に対応する文字は，日本円記号「￥」として表示される場合もある．

437

索引
*, 12, 71, 123, 124bytes , 145**, 12, 124

ceil , 145**=, 12class , 153*=, 12complex , 145+, 12

contains , 147+=, 12del , 136, 137-, 12delitem , 147-*-, 6

divmod , 145–help, 317, 319

doc , 422-=, 12enter , 303-h, 317, 319

eq , 145-＞, 423

exit , 303., 47, 96

ﬁle , 107, 275.., 96

ﬂoat , 145/, 12

ﬂoor , 145//, 12

ﬂoordiv , 145/=, 12

ge , 145:, 46

getitem , 147:=, 164

gt , 145;, 7

iadd , 147<<, 43iand , 147<<=, 44

iﬂoordiv , 147=, 8ilshift , 147==, 84

imatmul , 147！=, 84

imod , 147＞, 84

imul , 147＜, 84

init , 136＜=, 84

init .py, 273, 275＞=, 84

int , 145>>, 43

invert , 145>>=, 44

ior , 147[ ], 46

ipow , 147%, 12

irshift , 147%=, 12

isub , 147&=, 44iter , 148, 9, 15, 73

itruediv , 147

abs , 145

ixor , 147

add , 145

le , 145

aiter , 261

len , 147

and , 145

lshift , 145

anext , 261

lt , 145

annotations , 423

main , 234, 272

bases , 324

matmul , 145bool , 145

mod , 145

builtins , 122

mul , 145iname , 160, 234, 272, 323

0o, 15ne , 145

0x, 15

neg , 145

10 進数, 42, 43

next , 148

16 進数, 15, 43

or , 145

1 の補数, 43, 44

pos , 145

2 進数, 15, 42, 43

pow , 145

32-bit ﬂoating-point の WAV 形式ファイル, 346

pycache , 273

8 進数, 15, 43

radd , 146abs, 16

radd , , 147

abspath, 107, 275

rand , , 147

accept, 327

rdivmod , , 147acos, 18

repr , 144

acosh, 18

rﬂoordiv , , 147

acquire, 231

rlshift , , 147

ActionBar, 199

rmatmul , , 147

ActionButton, 199

rmod , , 147

ActionGroup, 199

rmul , , 147

ActionPrevious, 199

ror , 147

ActionView, 199

round , 145

active, 184

rpow , , 147

active children, 235

rrshift , , 147

add, 59, 177, 187

rshift , 145

add argument, 317, 318

rsub , , 147

add command, 379

rtruediv , , 147

add parser, 321

rxor , , 147

add subparsers, 321

setitem , 147

add widget, 177, 179

str , 144, 145

addch, 393

sub , 145

addstr, 393

subclasses , 324

after, 386

truediv , 145

ainput, 256

trunc , 145

aioconsole, 256

xor , 145

aioﬁles, 261

exit, 322

all, 161–, 59

all tasks, 258｜, 43, 65, 224

Anaconda, 360｜=, 44anchor, 380

˝, 59

AnchorLayout, 171, 185$, 225and, 84&, 43

ANSI エスケープシーケンス, 30’’’, 30

any, 161￥, 7, 29, 30

App, 169

ˆ, 43, 222, 225

append, 47, 288

ˆ=, 44

appendleft, 288@, 306argparse, 317@classmethod, 139

Argument Parser, 317@property, 150

argv, 113

0b, 15ii

Array, 237

build, 169

as, 301, 413

Builder, 196

as completed, 245

Button, 170, 175, 183, 368

as integer ratio, 25

Button1, 384

ASCII, 37, 437

Button3, 384

asctime, 212

ButtonPress, 384

asin, 18

ButtonRelease, 384

asinh, 18

bytearray, 285

assert, 299, 300

bytes, 45, 98, 99

AssertionError, 300
calendar, 211

astimezone, 208

cancel, 197, 258

async, 248

cancel job, 268

AsyncBuﬀeredIOBase, 263

Canvas, 379

AsyncBuﬀeredReader, 263

canvas, 176, 186

asyncio, 248, 342

Canvas グラフィックス, 186

asyncio.CancelledError, 259, 334

capitalize, 35

asyncio.Future , 254

CardTransition, 198

AsyncTextIOWrapper, 263

Carousel, 202

atan, 18

case, 165

atanh, 18

center, 92

atexit, 322

chain, 291

auto, 297

chardet, 100

available timezones, 209

chdir, 105

await, 248, 249

CheckBox, 170, 184

Awaitable, 248

Checkbutton, 370
b64decode, 284

choice, 74b64encode, 284

choices, 74

Base64, 284

chr, 37

BaseException, 301

class, 136, 290

basename, 108

clear, 60, 63, 177, 394

BASIC 認証, 335

clearcolor, 173

Beautiful Soup, 337

CLI, 392

BeautifulSoup, 337

Clock, 197

beep, 394

ClockEvent, 197Bezier, 188close, 97, 240, 257, 314, 327, 332, 342, 346, 353

bin, 43

clrtoeol, 398

bind, 178, 326, 384

cls, 139

bit length, 44

cmath, 19bkgd, 394

coding, 6

bool, 39, 40

collections, 288

BooleanVar, 371

Color, 177, 187

BoxLayout, 170, 171, 175

color, 181

break, 83

color pair, 394

BrokenPipeError, 334

combinations, 294

buf, 240

combine, 204

BuﬀeredReader, 95

Combobox, 372

BuﬀeredWriter, 95

CompletedProcess, 339

iii

complex, 12, 15, 16

cycle, 292

concurrent.futures, 243date, 204

conda, 363

datetime, 204

Conﬁg, 174

day, 207

conﬁg, 379

decode, 98, 99

Conﬁgure, 388

deep copy, 55

conﬁgure, 377

deepcopy, 55

conjugate, 16

def, 122

connect, 327

DEFAULT FONT, 183

ConnectionRefusedError, 334

del, 10, 48, 63, 135

ConnectionResetError, 334

delete, 382

contents, 338

denominator, 25

continue, 83

deque, 288

Control, 384

destroy, 391

cookies, 336

destructuring assignment, 72

coords, 382

detect, 100

copy, 54, 55, 60, 67

dict, 63

copy2, 313

DictReader, 119

copytree, 313

DictWriter, 115cos, 18

diﬀerence, 61

cosh, 18

dir, 153

count, 36, 51, 291

dirname, 107, 108, 275

Counter, 289

discard, 59

cpu count, 402

disk io counters, 405

cpu freq, 402

disk partitions, 404

cpu percent, 403, 409

disk usage, 405

cpu times, 402, 410

divmod, 18

CPU のクロック周波数, 402

do, 268

CPU の構成, 402

docstring, 422

CPU 使用率, 403

Double, 384

CPU 時間, 402

DoubleVar, 371

create arc, 379

down, 185

create image, 381

drain, 332

create line, 380

dump, 279

create oval, 379

dumps, 279

create polygon, 380
create rectangle, 379e, 18create task, 249, 250

echo, 396

create text, 380

elif, 84

CSV, 113

Ellipse, 177, 188

ctime, 206, 211

else, 77, 83, 84, 161

CUI, 392

Emacs, 6

currency, 219

encode, 99

current, 198

encoding, 96, 336

curs set, 394

endswith, 36

curselection, 375

endwin, 393

curses, 392

enter, 264

cwd, 109

Entry, 372
iv

Enum, 295

format, 89

enum, 295

format exc, 299

enumerate, 82, 230

for を使ったデータ構造の生成, 78

enumerate オブジェクト, 82

Fraction, 24

environ, 106, 311, 365

fractions, 24

EOF, 277

Frame, 366

euc-jp, 6

frames per buﬀer, 356

eval, 287

from, 273, 274, 413

Event, 264

from bytes, 45

events, 175

from ﬂoat, 24

except, 51, 299

frozenset, 62

Exception, 301

Function Annotations, 423

exec, 287

functools, 163

exists, 107, 110

Future, 243

exit, 177, 321
gather, 250

exp, 18, 23

gauss, 27

export to png, 190

gcd, 18

extend, 48

geometry, 367

extract, 316

get, 63, 335, 371

extractall, 316

get event loop, 252
f-string, 90

get extra info, 333

factorial, 18

get format from width, 353

FadeTransition, 198

get localzone, 209

FallOutTransition, 198

get localzone name, 209

False, 39

get name, 259

families, 380

get pixel color, 191

FBO, 190

get running loop, 252

FIFO, 49, 288

getattr, 142ﬁles, 417

getch, 396

FILO, 49, 288

getcwd, 105

ﬁlter, 52, 160

getencoding, 219

ﬁlterwarnings, 419

getframerate, 347

ﬁnally, 51

getkey, 396

ﬁnd, 35

getlocale, 217

ﬁnd all, 338

getmaxyx, 393

ﬁnditer, 220

getnchannels, 347

ﬂag, 319

getnframes, 347

ﬂash, 394

getpass, 93

ﬂoat, 12, 14, 40

getpid, 311

ﬂoat info.max, 14

getrecursionlimit, 129

ﬂoat info.min, 14

getsampwidth, 347

FloatLayout, 171

getsize, 107

ﬂoat の値が整数値かどうかを検査する方法, 42

getsizeof, 420

ﬂush, 103

getstate, 27

font name, 181

getstr, 396

font size, 181

GET リクエストの送信, 335

for, 75

GIL, 232v

glob, 110, 432

IPython, 58

global, 128

IP アドレス, 326

globals, 301

is, 41, 87

GMT, 207is None, 87

gmtime, 210

is not None, 87

gnuplot, 341

is active, 356

Graphics, 177

is alive, 229, 234

grid, 368

is dir, 110

GridLayout, 171

is ﬁle, 110

group, 185, 222, 225

is integer, 42

groupby, 292

isabs, 109

guard, 167

isalnum, 34

GUI 構築の形式, 197

isalpha, 34

GUI 構築の考え方, 169

isdecimal, 34
isdir, 107

hasattr, 153

isdisjoint, 61

hashable, 63

isﬁle, 107

headers, 336

isﬁnite, 20

help, 422

isinf, 20hex, 43

isinstance, 41, 88, 153

home, 109

islower, 35

horizontal, 175, 184

isnan, 20hour, 207

iso2022-jp, 6

id, 10, 87

ISO8601, 205, 206, 208

ident, 228

issubclass, 152, 323

id（Kv）, 196

issubset, 61

if, 84, 161

issuperset, 61

imag, 16, 22

isupper, 35

Image, 170, 185, 187

items, 67

immutable, 56

iter, 78, 148

import, 273, 274, 413

iter modules, 416

importlib, 417

iterable, 75

in, 34, 50, 61, 63

itertools, 291

inch, 399

j, 15

index, 36, 50

join, 33, 108, 228, 233

inf, 19

Jupyter Notebook, 58

init pair, 393
initscr, 393

keycode, 386

input, 93

KeyError, 59, 63

insert, 48

KeyPress, 384

instr, 400

keys, 66

int, 12, 40, 42, 94

keysym, 386

int.from bytes, 45

Kivy Designer, 365

IntEnum, 297

Kivy 利用時のトラブル, 365intersection, 61

Kivy 言語, 194

intersection update, 61
IntVar, 371

Label, 169, 170, 181, 368

io モジュール, 93, 94, 104

LabelBase, 183vi

Labelframe, 371

messagebox, 389

lambda, 159, 160

metadata, 417

Layout, 170

microsecond, 207lcm, 18

min, 16len, 31, 52, 60, 66

MinGW, 2limit denominator, 25

minute, 207

Line, 177, 187

mkdir, 112

list, 66, 71

mktime, 211

Listbox, 373, 374

module ﬁnder, 416

listdir, 106

ModuleInfo, 416

listen, 327

month, 207

ljust, 92

most common, 289

load, 279

Motion, 384

load ﬁle, 196

mpc, 22load next, 202

mpf, 21load previous, 202

mpmath, 21, 434

loads, 279

mro, 154

locale, 217

MSYS, 2

locale alias, 218

MULTILINE, 227

locals, 301

Multiple Assignment, 10

localtime, 210

multiprocessing, 233

Lock, 231

mutable, 56

lock, 231, 237
log, 18
log10, 18
log2, 18
loop, 203
lower, 35
lstrip, 37, 97

name, 38, 240, 338, 416
namedtuple, 290, 310
NameError, 10
namelist, 315
Namespace, 239, 318
NamespaceProxy, 239
nan, 19

mainloop, 366

net connections, 406, 410

make archive, 314

net io counters, 405

maketrans, 33

new event loop, 251man, 23

next, 79, 148Manager, 238

nodelay, 396

map, 156

noecho, 396

mappingproxy, 152

None, 40

markup, 181

nonlocal, 132

master, 391

noraw, 397

match, 165, 224

normal, 185

match オブジェクト, 220, 221

not, 84

math, 17

not in, 61

matplotlib, 242

NoTransition, 198max, 16, 184

now, 204max workers, 245

numerator, 25

memory-proﬁler, 420

NumPy, 241

memory info, 408
Menu, 379

object, 323
oct, 43vii

on active, 184

platform.system(), 310

on press, 177

platform.version(), 310

on release, 177pmem, 408

on start, 180

pop, 49, 60, 64, 288

on stop, 180

Popen, 340

on touch down, 174, 177

popenﬁle, 410

on touch move, 174, 177

popleft, 288

on touch up, 174, 177

PortAudio, 353

on value, 184

positional arguments, 317

open, 94, 111, 346, 353

PosixPath, 111

open connection, 332

POST リクエストの送信, 335

open ﬁles, 410

pow, 18

OpenGL, 190, 365

pprint, 309

optional arguments, 317

prettify, 337

or, 84print, 5, 89, 102ord, 37

print help, 319

orientation, 175, 184

ProactorEventLoop, 251

os, 105, 365

Process, 233, 408

os. exit, 322

process time, 214

os.linesep, 96, 97

ProcessPoolExecutor, 243

os.sep, 109

product, 293

OSError, 334

ProgressBar, 170, 184
Progressbar, 377

pack, 281, 368
PackagePath, 417
PageLayout, 171
parse args, 317, 318
Path, 109
path, 95, 416
pathlib, 109

project name, 416
protocol, 391
psutil, 402
PyAudio, 353
Python のインストール, 359
Python のバージョン情報の取得, 310
Python ランチャー, 361

pconn, 410
pcputimes, 410
permutations, 294
pi, 18
pickle, 279
PID, 233, 311, 408
pid, 233
pids, 407
PIP, 363
pip コマンド, 363
pkg resources, 416
pkgutil, 416
platform, 310
platform.architecture(), 310
platform.mac ver(), 310
platform.platform(), 310
platform.processor(), 310
platform.python compiler(), 310

quit, 373
Radiobutton, 371
raise, 300
randbelow, 28
randint, 26
random, 26
randrange, 26
range, 76raw, 396
raw モード, 396
raw 文字列, 30
re, 220
read, 94, 100, 105, 332, 356
read bytes, 112
read text, 111
reader, 117
readframes, 347, 356
viii

readline, 94, 96

sconn, 406

readlines, 101

scpufreq, 402

real, 16, 22

scputimes, 402

Rectangle, 177, 187

Screen, 170, 172, 197, 198

recv, 327

ScreenManager, 172, 197

reduce, 163

screenshot, 189

refresh, 394

Scrollbar, 376

register, 183, 322

ScrollView, 192

RelativeLayout, 171

sdiskio, 405

release, 231

sdiskpart, 404

remove, 49, 107

sdiskusage, 405

remove widget, 179

SDL, 365

repeat, 292

search, 220

replace, 33

second, 207

repr, 40, 144

secrets, 28

requests, 335

seed, 27

requires, 417

seek, 277

resetwarnings, 419

self, 136–138

resizable, 368

send, 327

resource, 182

serve forever, 331

resource add path, 182

Session, 336

result, 243set, 59, 71, 371

return, 122

set defaults, 321

reverse, 54

set event loop, 258

reversed, 54

set int max str digits, 13

rewind, 356

setattr, 142rﬁnd, 36setdefault, 64

RiseInTransition, 198

setframerate, 350

rjust, 92setlocale, 217

rmdir, 107, 113

setnchannels, 350

root（Kv）, 196

setparams, 351

rotate, 288

setrecursionlimit, 130

rstrip, 37, 97

setsampwidth, 350

run, 169, 248, 251, 264, 339

setsockopt, 326

run forever, 257

setstate, 27

run in executor, 254

shallow copy, 55

run pending, 268

shared memory, 240

run until complete, 251

shell, 339

running, 243

Shift, 384
shift-jis, 6

sample, 74

shift jis, 96

Scale, 377

shuﬄe, 73

ScatterLayout, 171

shutdown, 243, 331

sched, 264

shutil, 313

schedule, 267

sign, 23schedule interval, 197

sin, 18

schedule once, 197

sinh, 18

scheduler, 264

size, 173ix

size hint, 172, 177

subprocess, 339

sleep, 215, 249

subprocess.PIPE, 340

slice, 69

suite, 75

Slider, 170, 184sum, 52

SlideTransition, 198

super, 136, 137

snetio, 405

svmem, 403

sock accept, 329

swap memory, 403

sock connect, 330

swapcase, 35

sock recv, 329

SwapTransition, 198

sock sendall, 329

Switch, 170, 184

socket, 326

symmetric diﬀerence, 61sort, 53

SyncManager, 238

sorted, 53, 57

sys, 14, 92, 94, 113, 177, 310

source, 185

sys.exit, 321

span, 220, 221

sys.modules, 414

split, 32, 108, 227

sys.path, 414

splitext, 108

sys.stderr.buﬀer, 105splitlines, 33

sys.stderr のエンコーディング設定, 104spos, 175sys.stdin, 94

sqrt, 18

sys.stdin.buﬀer, 105

sswap, 403

sys.stdin のエンコーディング設定, 94

StackLayout, 171

sys.stdout, 92

start, 228, 233

sys.stdout.buﬀer, 105

start color, 393

sys.stdout のエンコーディング設定, 93

start server, 331

system, 344

start stream, 355

SystemExit, 322

startswith, 36
TabbedPanel, 201

state, 185

TabbedPanelItem, 201

staticmethod, 141tan, 18

status code, 336

tanh, 18

stdin, 342

tar, 313, 314, 316

stop, 257

tarﬁle, 316

stop stream, 353

Task, 248

StopIteration, 79, 148

Tcl/Tk, 366

str, 40, 99

TCP/IP, 326

stream callback, 355

tell, 102

StreamReader, 332

terminate, 235, 353, 411

StreamWriter, 332

Text, 376

strftime, 206, 212

text, 175, 184, 335

string, 39

TextInput, 170, 183

StringVar, 371

TextIOWrapper, 93–95, 105

strip, 37

Texture, 187

strptime, 205, 212

texture, 187

struct, 281, 350

texture size, 185

struct time, 210

the epoch, 210

sub, 226

The Zen of Python, 415

submit, 243

Thread, 228

subn, 226x

thread, 228

Value, 236

thread time, 214value, 184

threading, 228

ValueError, 13, 50

ThreadPoolExecutor, 243

values, 66

time, 204, 210, 386

Variable, 370

timedelta, 205

vars, 152

timegm, 211version, 310, 416, 417

timeit, 216

version info, 310

TimeoutError, 334

vertical, 175, 184timezone, 207

Video, 170

title, 35, 367

view, 66, 67

Tk(), 366

virtual memory, 403

Tkinter, 366
wait, 344

to bytes, 45

wait closed, 332

ToggleButton, 170, 185

walk, 106, 431

Toplevel, 387

warn, 419

trace, 371, 377

warning, 419

traceback, 299

warnings, 419

transition, 172, 197, 198

Wave read, 346, 356

translate, 33

Wave write, 346

Triple, 384

WAV 形式, 346

True, 39

wheel, 364

try, 51, 299

while, 83

tuple, 71

whl, 364

type, 10, 41, 88, 323, 386

Widget, 170, 176, 186

typing モジュール, 423

widget, 386

tzinfo, 207

Window, 173tzlocal, 209

window, 393
Unicode, 30

WindowsPath, 111

unicodedata, 38

winfo children, 391

Unicode の文字符号化モデル, 38

winfo height, 388

unicode もじのけんさく, 224

winfo screenheight, 388

uniform, 26

winfo screenwidth, 388

union, 61

winfo width, 388

UNIX エポック, 210

winfo x, 388

UNIX 時間, 210

winfo y, 388

unlink, 112, 240

WipeTransition, 198

unpack, 72, 282

with, 113, 302

unpack archive, 314

working set, 416

update, 61, 64

wrapper, 393

upper, 34, 35

write, 102, 105, 315, 332, 354

URI, 111

write bytes, 112

UTC, 207

write text, 111

utcnow, 207

writeframes, 350

utf-8, 6, 96

writeframesraw, 350

utf-8-sig, 6writeheader, 116uvloop, 263

writelines, 103

xi

writer, 114

イベントから得られる座標位置, 191

writerow, 114

イベント駆動型, 174

writerows, 114

イベントハンドラ, 174

WWW コンテンツ解析, 335

イベントループ, 248, 251
イミュータブル, 56

x root, 386
XML, 337

色ペア, 393
インスタンス, 136

y root, 386

インスタンスの生成, 136year, 207

インスタンス変数, 138, 152

yield, 270

インスタンスメソッド, 138
インデックス, 46

ZeroDivisionError, 300

インデックスの範囲, 46

ZIP, 313

インデント, 7, 75, 76

zip, 80, 158, 314

ウィジェット, 169, 170, 366

ZIP BZIP2, 314

ウィジェットツリー, 194

ZIP DEFLATED, 314

ウィジェットのサイズ設定, 193

ZIP LZMA, 314

ウィジェットの伸縮, 369

ZIP STORED, 314

ウィジェットの登録と削除, 179

ZipFile, 314

ウィンドウ, 173

zipﬁle, 314

ウィンドウに関する情報, 388

zip オブジェクトの展開, 81

ウィンドウのリサイズ, 397

ZoneInfo, 208

ウェブスクレイピング, 335

アクションバー, 199
アクセサ, 149, 150
浅いコピー, 55
アスキーコード表, 437
アスキー文字, 37
圧縮処理, 313
アプリケーション終了のハンドリング, 390
アプリケーションの開始と終了, 180
アプリケーションの終了, 177
アラインメント, 90
アンダースコア, 9
アンパック, 72
アーカイブ, 313
イコール, 8
イコールの連鎖, 10

1 行のみから成るスイート, 76
位置の基準, 380
位置引数, 123, 317
一括判定, 161
イテラブル, 75
イテラブルの繰り返し, 292
イテラブルの連結, 291
イテレータ, 78
イベント, 174
イベントオブジェクト, 386

エスケープシーケンス, 29
エポック秒, 210
エラー, 51, 300
エラーのハンドリング, 51
エンクロージャ, 133, 134
エンコーディング, 6, 37, 96
エンコーディング情報の取得, 336
エンコーディングの変換処理, 99
演算子の優先順位, 436
演算精度の設定, 21円周率, 18
エントリ, 63, 372
エントリの削除, 63
エントリの順序, 67
応答オブジェクト, 335
大文字／小文字の変換と判定, 34
オブジェクト指向, 47, 136
オブジェクトの繰り返し, 292
オプション引数, 317
折れ線, 187
音声入力デバイス, 356
オーバーライド, 139, 169
改行, 30
改行コード, 96, 97
改行コードの削除, 97
拡張クラス, 136xii拡張子, 110

虚部, 16, 22

加算, 12

キー, 62

仮数部, 14, 23

キーの検査, 63

仮数部の桁数の設定, 21

キーボード入力, 93

仮想記憶の状況, 403

キーワード引数, 123, 124, 175

型, 8

偽, 39

型システム, 323

疑似乱数, 27型の階層, 323

逆順の要素指定, 70型の検査, 41

逆正弦関数, 18型の変換, 40

逆正接関数, 18

カプセル化, 149

逆双曲線正弦関数, 18「空」値, 86

逆双曲線正接関数, 18

空の辞書, 87

逆双曲線余弦関数, 18

空の辞書の作成, 63

逆余弦関数, 18

空のタプル, 87

行頭や行末でのパターンマッチ, 225

空文字列, 87

空集合, 87

空リスト, 46, 87

空白文字の削除, 97

仮引数, 122

空白文字の除去, 35

仮引数の個数, 123

クォート文字を含む CSV ファイル, 120

カレントディレクトリ, 95, 105, 109

国コード, 217

環境変数, 106, 311

組合せ, 294

環境変数の参照, 311

組込み関数, 122関数, 122, 159

クライアント, 326

関数アノテーション, 423

クラス, 136

関数オブジェクト, 159

クラス階層, 323

関数の一斉評価, 156

クラスの継承関係, 152関数の削除, 135

クラス変数, 139, 152

関数名, 159

クラスメソッド, 138, 139

外部プログラムとの連携, 339

繰り返し, 75, 83

外部プログラムの標準入力のクローズ, 342

繰り返しの中断とスキップ, 83

外部プロセスとの同期, 344

繰り返しの表記, 223

ガウス分布, 27

クロージャ, 133, 134

画像, 185

グリニッジ標準時, 207

ガベージコレクション, 11, 136

グループ, 225, 227

基数の指定, 15

グローバル変数, 128, 272

基数の変換, 42

経過時間, 204

規則（Kv）, 196

警告メッセージ, 419

基底クラス, 136

継承, 136

キャラクタ端末, 392

継承関係, 152

キャレット, 394

桁数の指定, 90キュー, 49, 288

ゲッタ, 150, 151

共通集合, 61

厳格な位置引数, 127

協定世界時, 207

厳格なキーワード引数, 127

共役複素数, 16

言語コード, 217

共有メモリ, 236

現在時刻, 204

局所変数, 128

現在のエポック秒の取得, 210

虚数単位, 15

現在の通信状況, 406

巨大な整数値, 13

減算, 12xiii

構造体, 281

指数関数, 18

構造的なパターン, 166

指数表記, 14, 21

構造的パターンマッチング, 165

指数部, 14, 23

コマンドサーチパス, 364

自然対数, 18

コマンドシェル, 339

シャッフル, 73

コマンド引数, 113, 317

集合論, 58, 61

コマンド引数の形式, 317

集合論の操作, 61

コマンドライン, 317

終了コード, 321, 322

コマンドラインオプション, 317

終了ステータス, 321

コメント, 6

終了の待機, 344

コルーチン, 248

出力先のリダイレクト, 104

コルーチンオブジェクト, 248

出力バッファ, 103

コロン, 46

書庫（アーカイブ）の作成, 314

コンストラクタ, 136

書庫（アーカイブ）の展開, 314

コンテナ, 46, 147

書庫ファイル, 313

コンテンツの階層構造, 338

書式設定, 89

コンテンツの取得, 335

処理環境に関する情報の取得, 310

コンボボックス, 372

処理のスケジューリング, 264

コード体系を調べる方法, 100

真, 39

コードポイント, 38

シングルクオート, 30

コールバック, 178

真性乱数, 27

コールバック関数, 354

進捗バー, 184

コールバックモード, 354

真の乱数, 27

合計, 52シンボルの調査, 301

誤差, 17

真理値, 39

再帰代入, 12

ジェネレータ, 78

再帰的定義, 129

ジェネレータ関数, 270

最小公倍数, 18

ジェネレータ式, 271

最小値, 16

時間差, 205

最大公約数, 18

時間によるイベント, 197

最大値, 16

時間の計測, 213

サウンドの再生位置をファイルの先頭に戻す, 356

時刻, 204

サウンド再生の終了の検出, 356

時刻情報の分解, 204

サウンドの繰り返し再生, 356

辞書か否かの判定, 68

サウンドの再生, 353

辞書型, 62

サウンドの入出力, 346

辞書の for 文への応用, 77

サウンドの入力, 353, 356

辞書の結合, 65

サブクラス, 324

辞書の更新, 64

サブコマンド, 320

辞書の整列, 68

サブプロセス, 339

辞書を他の辞書の内部に展開する, 65

参照カウント, 11

実行中のプロセス, 407

算術演算, 12

実引数, 122

サンプリング周波数, 346

実部, 16, 22

サンプリングレート, 346

受信, 327

サーバ, 326

順次アクセス, 277

シェル変数, 339

順序の反転, 54

識別値, 87

順列, 294

四捨五入, 17

上位クラス, 136xiv条件付きカウント, 52

静的メソッド, 155

条件付きのパターンマッチング, 167

セッション情報, 336

条件分岐, 84

セッタ, 150, 151

乗算, 12セット, 58

剰余, 12

セットか否かの判定, 62

除算, 12セットに変換, 71

垂直, 175

セットの生成, 59

垂直タブ, 30セットの複製, 60

垂直配置, 177

遷移の効果, 198

スイッチ, 184

絶対値, 16

水平, 175

絶対パス, 95

水平配置, 177

絶対パスの文字列, 107

スイート, 75

絶対パス／相対パスの判定, 109

数学関数, 17ゼロの充填, 90

スクリプト, 3

全要素の削除（set）, 60

スクリプトの終了, 321

双曲線正弦関数, 18

スクリーン, 172, 197

双曲線正接関数, 18

スクリーンショット, 189

双曲線余弦関数, 18

スクリーンマネジャ, 172

送信, 327

スクロールバー, 192, 375, 376

相対パス, 95

スクロールビュー, 192

添字, 31, 69

スケール, 376, 377

添字の値の省略, 69

スコープ, 128

添字の増分, 70

スタック, 49, 288

ソケット, 326

スタティックメソッド, 141, 155

ソケットオプション, 326

ステレオ音声, 346

ソケットの用意, 326

ステータスの取得, 336

属性付き文字データ, 399

ストリーム, 353

属性の調査, 153

スライス, 31, 46, 69

大域変数, 128, 272

スライスオブジェクト, 69

対数関数, 18

スライダ, 184

タイマー, 197, 386

スライドイン, 198

タイムアウト, 327

スレッド, 228

タイムゾーン, 207, 208

スレッド ID, 228

タイムゾーン ID, 208

スレッド終了の同期, 228

タイムゾーンの変換, 208

スレッドの実行, 228

対話モード, 3

スレッドの生成, 228

タグ, 382

スワイプ, 202

タグの検索, 338

スワップ領域, 403

多重継承, 136

スーパークラス, 136, 324

多重継承におけるメソッドの優先順位, 153

正規表現, 220, 222

タスク, 248, 249

正規分布, 27

タッチ, 174

正規乱数, 27種, 27

正弦関数, 18

多倍長精度の浮動小数点数, 21

整数, 12

多バイト系文字列の変換, 99

整数値の桁数を調べる方法, 14

多バイト文字, 38

整数値のビット長を求める方法, 44

タブ, 30正接関数, 18

タブパネル, 201xv

タプル, 56

特殊なタプル, 57

タプルか否かの判定, 58

トグルボタン, 185

タプルに変換, 71

同一性, 87

第一級オブジェクト, 159

ドット, 47

代入式, 164

内部関数, 131

楕円, 188

内包表記, 78

ダブルクオート, 30

内包表記によるタプルの生成, 78

チェックボタン, 370

長さ, 52

チェックボックス, 184

名前空間, 239

置換, 33, 226

名前空間プロキシ, 239

置換処理, 226

名前の衝突, 204, 414

チャネル数, 346

日本語の変数名, 9

中央揃え, 92

日本語文字列の表示, 181

中央揃え, 90

入出力, 89

長方形, 187

任意の精度, 21

直積集合, 293

ヌルオブジェクト, 40, 87

通信機能, 326

ネイピア数, 18

定数の取り扱い, 296

ネットワークの I/O 状況, 405

テキスト, 375, 376

排他制御, 230, 231, 237

テキストカーソル, 394

排他的論理和, 43

テキスト形式, 95

配置領域の大きさ, 177

テキストデータ, 98

ハイフン, 9

テキスト入力, 183

派生クラス, 136

テキストファイル, 98

ハッシュ可能, 63

テキストボックス, 372

バイエンディアン, 283

テクスチャ, 187

バイトオーダー, 282

ディスクの I/O 状況, 405

バイト値, 99

ディスクの使用状況, 405

バイト列, 98, 279

ディスプレイに関する情報, 388

バイト列の作成方法, 99

ディレクトリ, 105, 109

バイナリ形式, 95, 279

ディレクトリ階層の複製, 313

バイナリデータ, 98, 281, 350

ディレクトリ内容の一覧, 106

バイナリファイル, 98

ディレクトリの削除, 107

バックスペース, 30

ディレクトリの作成, 112

バックスラッシュ, 6

ディレクトリの部分のみを取り出す, 107

バックログ, 327

ディレクトリの要素, 110

パイプ, 339

ディレクトリ名, 110

パス, 95デカルト積, 293

パスオブジェクト, 109

デコレータ, 139, 306

パスの存在の検査, 110

デストラクタ, 136

パスの連結, 111

デフォルト値, 320

パスワードで保護された ZIP 書庫, 316

デフォルトフォント, 183

パスワード入力, 93

データ構造, 46

パターンの検索, 220

データ構造に沿った値の割当て, 72

パターンマッチ, 224

データ構造のシャッフル, 73

パッケージ, 1, 272, 273

データ構造の生成, 78

パーティションの構成, 404

データ構造の選択的な部分抽出, 73

比較演算子, 84

データ構造の変換, 70

比較演算子の連鎖, 85

xvi

引数, 122

深いコピー, 55

引数に暗黙値を設定する, 123

複数行に渡る文字列, 30

引数の個数が不定, 123

複数のウィンドウ, 387

引数パーサ, 317

複製, 54

非数, 20, 22

複素数, 12, 15, 19, 22

ヒストリ, 3複素数のノルム, 16

左寄せ, 90, 92

符号, 23

日付, 204

浮動小数点数, 12

日付，時刻の書式整形, 206

浮動小数点数と 2 進数の間の変換, 433

日付と時刻の生成, 205

フラグ, 319

非同期処理, 248

フレーム, 347

非同期のイテラブル, 260

フレームバッファ, 190

非同期のイテレーション, 260

フレームバッファへの描画, 190

非同期のイテレータ, 261

部分集合, 61

非同期のコンテナ, 260

部分集合の判定, 61

非同期のジェネレータ, 260

部分文字列, 31

標準エラー出力, 103

部分リスト, 46

標準出力, 89

ブロッキングモード, 354

標準入力, 89, 93

分割代入, 72, 80

ビッグエンディアン, 283

分子, 25

ビット演算, 43

文書化文字列, 422

ビュー, 66, 67

分数, 24

描画色, 187

分母, 25

ピクセル値の取り出し, 190, 191

分母の大きさの制限, 25

ファイナライザ, 136

プレースホルダ, 89, 91

ファイルオブジェクト, 94

プログラムの終了, 177, 321, 373

ファイルオブジェクトへの出力, 102

プログラムの実行待ち, 215

ファイルからの入力, 94

プログレスバー, 376, 377

ファイル内でのランダムアクセス, 277

プロセス, 233

ファイルのオープン, 95

プロセス ID, 233, 311, 408

ファイルのクローズ, 97

プロセス終了の同期, 233

ファイルのサイズの取得, 107

プロセスの強制終了, 235

ファイルの削除, 107

プロセスの実行, 233

ファイルのシーク, 277

プロセスの生成, 233

ファイルのパス, 95

プロパティの調査, 153

ファイルの複製, 313

プロンプト, 3, 93

ファイルへの出力, 102

プール, 243

ファイル名, 110

平方根, 18

ファイル，ディレクトリの検査, 107, 110

ヘッダー情報, 336

フェードアウト, 198

変数, 8

フェードイン, 198

変数の値の交換, 73

フォント指定, 181

変数の解放, 10

フォントのサイズ, 181

変数名に関する注意, 9

フォントの登録, 182

冪乗, 12

フォントのパス, 181

ベル, 30フォーマット済み文字列リテラル, 90

ホームディレクトリ, 106, 109, 311

フォームの送信, 335

ホームドライブ, 311

フォームフィード, 30

ボタン, 183

xvii

ポート, 326

要素の書き換え, 47

マルチスレッド, 228

要素の個数のカウント, 51

マルチタッチの無効化, 173

要素の合計, 52

マルチバイト文字, 38

要素の削除, 48, 49

マルチプロセシングマネジャ, 238

要素の削除（set）, 59

マルチプロセス, 233

要素の整列, 53

丸め, 17

要素の挿入, 48

マークアップ, 181

要素の探索, 50

右寄せ, 90, 92

要素の追加, 47

ミドルエンディアン, 283

要素の追加（set）, 59

ミュータブル, 56, 63

余弦関数, 18

無限大, 19, 22

読み込まれているライブラリの調査, 414

無限のカウンタ, 291

予約語, 9

無作為抽出, 74

ライブラリ, 1

メイン部, 274

ライブラリ管理, 363

メソッド, 136

ライブラリのパス, 414

メソッドの定義, 138

ラジオボタン, 370

メソッドの適用, 47

ラベル, 181

メッセージボックス, 389

ラベルフレーム, 371

メニュー, 199, 378

乱数, 26

メニュー項目, 378

ランダムアクセス, 277

メニューバー, 199, 378

ランダムサンプリング, 73, 74

メンバ, 139

リサイズの禁止, 193, 368

メンバシップ検査, 50

リスト, 46

文字コード, 37

リストか否かの判定, 56

文字コード体系, 6, 37

リストに対する検査, 50

文字コードを検索パターンに使用する方法, 223

リストに変換, 71

文字の種別, 38

リストの拡張, 48

文字の置換, 33

リストの繰り返し, 48

文字化け, 98

リストの内部に他のリストを展開する方法, 56

文字符号化スキーム, 39

リストの長さ, 52

文字符号化方式, 39

リストの編集, 47

モジュール, 1, 272

リストの要素の連結, 33

モジュールの作成, 272

リストの要素へのアクセス, 46

モジュールの実行, 274

リストの連結, 48

文字列, 29

リストボックス, 373, 374

文字列の含有検査, 34

リソース, 182

文字列の繰り返し, 32

リテラル, 8, 166

文字列の検索, 35, 220, 221

リトルエンディアン, 283

文字列のシャッフル, 74

量子化ビット数, 346

文字列の置換, 33

両端の文字の除去, 37

文字列の分解, 32, 227

累算代入, 12, 32, 147

文字列の連結, 32

累算代入演算子, 83

文字列リテラル, 29

ルートディレクトリ, 95

戻り値, 122

ルートフォルダ, 95

モノラル音声, 346

レイアウト, 170

ユーザ定義関数, 122

例外, 300

要素でない, 61

例外オブジェクト, 300

xviii

例外処理, 51, 299
列挙型, 295
連結, 48
連続要素のグループ化, 292
ロケール, 217
ロケールのカテゴリ, 217
ロックオブジェクト, 231
論理演算子, 84
論理積, 43
論理和, 43
ローカルタイム, 207
ローカルタイムゾーン, 209
ローカル変数, 128
ワイプ, 198
和集合, 61xix

謝辞
本書の内容に関して，インターネット（電子メール，SNS など）を介して多くの方々から有効な助言やリクエストをいただきました．本書の執筆と維持のために大きな貢献となっております．
本書の内容に関して多くのご指摘とご助言をくださった中西康二様，ここにお礼申し上げます．
本書をご精読くださり，細かな点に至るまでチェックをしてくださいました鈴鹿医療科学大学の梶山純先生，大変感謝しております．ここにお礼申し上げます．
大学，大学院，専門学校での演習授業やゼミにおいて寄せられた相談や質問に端を発する内容が本書の充実に貢献しています．京都情報大学院大学，京都コンピュータ学院，武庫川女子大学の学生諸君に感謝します．また，京都情報大学院大学での教育活動におきまして，今井正治教授（大阪大学名誉教授）との共同活動から新たな知見が得られ，本書の内容の増補に役立ちました．ここにお礼申し上げます．
その他，ご助力くださった多くの方々にもお礼申し上げます．今後もご協力いただけましたら幸いです．また，誤った記述に対する厳しいご指摘は大変にありがたいものです．

「Python3 入門」− Kivy による GUI アプリケーション開発，サウンド入出力，ウェブスクレイピング

IDEJ 出版

ISBN978-4-9910291-3-4 C3004

著者：中村勝則
発行：2019 年 3 月 14 日

第1版

2020 年 3 月 14 日

第 1.3.1 版

2021 年 2 月 24 日

第 1.8.1 版

2021 年 3 月 14 日

第2版

2023 年 2 月 14 日

第 2.8 版

2023 年 3 月 14 日

第3版

2023 年 9 月 14 日

第 3.1 版

2024 年 3 月 14 日

第 3.2 版

2024 年 10 月 11 日

第 3.2.18 版

テキストの最新版と更新情報
本書の最新版と更新情報を，プログラミングに関する情報コミュニティ Qiita で配信しています．
→ https://qiita.com/KatsunoriNakamura/items/b465b0cf05b1b7fd4975

上記 URL の QR コード

本書はフリーソフトウェアです，著作権は保持していますが，印刷と再配布は自由にしていただいて結構です．
（内
容を改変せずにお願いします）
も受け付けています．
● 連絡先

中村勝則

内容に関して不備な点がありましたら，是非ご連絡ください．ご意見，ご要望