M.Hiroi's Home Page

Lightweight Language

新・お気楽 Python プログラミング入門

第 1 回 データ型と制御構造

[ PrevPage | Python | NextPage ]

はじめに

Python は 1991 年にグイド・ヴァンロッサム氏によって開発されたオブジェクト指向スクリプト言語です。1994 年に Python 1.0、2000 年に Python 2.0 (Python2)、2008 年に Python 3.0 (Python3) がリリースされました。Python3 には下位互換性がなかったため、10 年以上の間 Python2 と Python3 の二系統が使われてきましたが、2020 年 1 月 1 日をもって Python2 (最終版 Python 2.7.18) のサポートは終了しました。本稿では Python3 を Python と記述することにします。

Python は、リスト、タプル、セット、ディクショナリといった高水準のデータ構造 (データ型) や、オブジェクト指向機能、モジュール機能、例外処理といった高度な機能をサポートしています。そして、ブロック構造を表すのにインデント(字下げ)を用いるのが最大の特徴でしょう。C言語や Perl のように { ... } でブロックを表すのではなく、インデントの深さでブロックを表します。好き嫌いが分かれるところですが、誰が書いても同じようなプログラムになるので、可読性が高くなるという利点があります。

また、Python はスクリプトだけではなく、大規模なソフトウェア開発にも対応できる汎用的なプログラミング言語として使用することができます。多くのライブラリが標準で添付されていますし、便利な外部ライブラリも多数公開されています。複雑な処理でも Python ならばライブラリを使って簡単にプログラムすることができます。特に、数値計算や AI 分野 (機械学習やディープラーニングなど) の外部ライブラリはとても充実しています。

海外では以前から人気が高かった Python ですが、最近の AI ブームにより日本でも注目を集めるようになりました。今後、日本でも Python の普及はますます進んでいくものと思われます。本連載では、簡単なプログラムを作りながら Python の基本からオブジェクト指向機能まで、プログラミング言語としての Python の基本的な機能を一通り説明していきたいと思っております。たいしたことはできませんが、よろしければお付き合いくださいませ。

●Python のインストールと起動

Windows の場合、Python のインストールは以下の公式サイトからインストーラーをダウンロードして実行するだけです。

Python の最新バージョン (2022 年 8 月時点) は 2022 年 8 月 3 日にリリースされた 3.10.6 です。

Unix 系 OS の場合、Python は初めからインストールされていることが多いでしょう。Ubunts 20.04 LTS の場合、シェル で python3 と入力します。

$ python3
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

メッセージとプロンプト '>>>' が表示され、対話モードで Python が起動されます。Windows の場合は PowerShell またはコマンドプロンプトで python と入力します。Python を終了するには Ctrl + D (Windows の場合は Ctrl + Z) を入力してください。

本稿のプログラムは Python 3.8.10, Ubuntu 20.04 (WSL1) を使って動作を確認することにします。

●Python のプログラム

Python は Perl やC言語と同じく、手続き型のプログラミング言語です。Python も同様に、プログラムの実行を制御する「文」、データを格納する「変数」、決められた処理を行う「関数」があります。

C言語や Perl は文の最後をセミコロン ( ; ) で区切りますが、Python はセミコロンを付ける必要はありません。関数は Python にあらかじめ用意されている「組み込み関数」のほかに、私達ユーザが定義することもできます。もちろん「再帰呼び出し」も可能です。

Python にはいろいろなデータが用意されています。データの種類を「データ型」と呼びます。Python の場合、基本的なデータ型には「数」と「文字列」があります。高水準なデータ型として「リスト」、「タプル」、「ディクショナリ」、「セット」があります。

また、Python はオブジェクト指向プログラミング (OOP) に対応しているので、「クラス」、「インスタンス」、「メソッド」、「継承」など OOP 的な機能があります。このほかに「モジュール機能」や「例外処理」といった高度な機能もサポートされています。

Python のプログラムで使用される変数名、関数名などには、英数字とアンダースコア _ が使えます。英大文字と英小文字は区別されるので、FOO と Foo と foo は異なる名前と判断されます。

●Python のデータ型

Python に用意されている基本的なデータ型について簡単に説明します。

●数

Python には整数 (integer)、浮動小数点数 (floating-point number)、複素数 (complex number) という 3 種類の数が用意されてます。簡単な例を示します。

>>> a = 100
>>> a
100
>>> print(a)
100
>>> b = 1.234
>>> b
1.234
>>> c = 2 ** 100
>>> c
1267650600228229401496703205376
>>> d = 1 + 2j + 3 - 4j
>>> d
(4-2j)

Python はC言語と違い、あらかじめ変数やそのデータ型を宣言する必要はありません。変数に値をセットすることを「代入」といいます。代入には = を使います [*1]。これはC言語や Perl と同じです。対話モードで変数名を入力するとその値が表示されます。もしくは関数 print() を使って表示します。print() はカッコの中のデータを画面 (標準出力) へ出力して改行します。

変数 a には整数 100 を代入し、変数 b には実数 1.234 を代入しています。Python の整数には桁数の制限がありません。** はべき乗を計算する演算子で、2 の 100 乗のような大きな値でも計算することができます。算術演算子を表 1 に示します。

表 1 : 算術演算子
操作結果
-x x を負にする
x + y x と y の和
x - y x と y の差
x * y x と y の積
x / y x 割る y の商 (結果は浮動小数点数)
x // y 整数の徐算 (結果も整数)
x % y x 割る y の剰余
x ** y x の y 乗

浮動小数点数はC言語の倍精度浮動小数点数 (double) と同じで、範囲は約 1e-307 から 1e+308 までです。複素数は (実数部 + 虚数部) で表します。虚数単位は J または j を使って表します。j だけだと変数と認識されるので、1j と書くことに注意してください。

-- note --------
[*1] 代入は x = y = z = 0 のように、複数の変数に同じ値を代入することができます。

●文字列

文字列 (string) はシングルクオート ' で囲むか、ダブルクオート " で囲んで表します。なお、Python の文字列はユニコード (UTF-8) です。

>>> a = 'hello, world'
>>> a
'hello, world'

変数 a には文字列 'hello, world' を代入しています。文字列には演算子 + と * を適用することができます。

>>> 'abc' + 'def'
'abcdef'
>>> 'abc' * 3
'abcabcabc'

演算子 + は文字列を連結した新しい文字列を作り、演算子 * は文字列を指定した回数だけ繰り返した新しい文字列を作ります。

文字列には「エスケープシーケンス」を含めることができます。これは、画面に表示することができない文字を表すのに用いられる方法です。よく使われる記号に改行を表す \n とタブを表す \t があります。

>>> print('abc\ndef')
abc
def
>>> print('abc\tdef')
abc    def

この例はタブが 4 文字に設定されている場合です。エスケープシーケンスを無効にしたい場合は、文字列の前に r または R を付けます。これを raw string といいます。

>>> print(r'abc\ndef')
abc\ndef
>>> print(r'abc\tdef')
abc\tdef

ver 3.6 から文字列の前に f または F を付けることができるようになりました。これを「フォーマット済み文字列リテラル (f-string)」といいます。

f'... {式} ...' => '... 値 ...'

f-string は文字列の中に {式} を見つけると、{式} の部分を式を評価した値に置き換えた文字列を生成します。これは bash や Perl の変数展開、Ruby の式展開などと同様の機能です。r と f を組み合わせた fr や rf を使うこともできます。

簡単な例を示しましょう。

>>> f'123 + 456 = {123 + 456}'
'123 + 456 = 579'
>>> a = 'ABC'
>>> b = 'DEF'
>>> f'abc {a} def {b} {a * 2} {b * 3}'
'abc ABC def DEF ABCABC DEFDEFDEF'

複数の行にわたって文字列を定義したい場合は継続行を使います。継続行は最後にバックスラッシュ (円記号) を付けます。

>>> b = 'abcdef\n\
... 012345\n\
... ghijkl\n'
>>> b
'abcdef\n012345\nghijkl\n'
>>> print(b)
abcdef
012345
ghijkl

もうひとつ、三重のクオート """ または ''' で囲む方法 [*2] があります。簡単な例を示しましょう。

>>> c = '''abcdef
... 012345
... ghijkl
... '''
>>> c
'abcdef\n012345\nghijkl\n'
>>> print(c)
abcdef
012345
ghijkl

''' で囲まれた入力データがそのまま文字列になります。改行文字も含まれるので、継続行のように \n を付加する必要はありません。

-- note --------
[*2] Perl や UNIX 系のシェルにあるヒアドキュメント (here-document) という機能とよく似ている方法です。

●リスト

Python のリスト (list) [*3] はデータを一列に並べたもので、Perl の配列やC言語の 1 次元配列と同様のデータ構造です。リストに格納されたデータを「要素」といいます。リストの要素は整数値で指定します。これを「添字 (subscripts)」といいます。Python の場合、C言語と同じく添字は 0 から始まります。リストは角カッコ '[' と ']' で囲み、要素をカンマ ( , ) で区切って表します。[ ] は要素が一つもない空リストになります。

簡単な例を示します。

>>> list1 = [10, 20, 30, 40, 50]
>>> a = list1[0]
>>> a
10
>>> list1[4] = 100
>>> list1
[10, 20, 30, 40, 100]
>>> list1[-1]
100
>>> list1[-2]
40

C言語は配列の大きさを宣言する必要がありますが、Python のリストは大きさを宣言する必要はありません。リストの大きさは Python が自動的に調整してくれます。大きさを自由に変えることができる配列を「可変長配列」といいます。他のスクリプト言語、たとえば Perl でも可変長配列をサポートしています。

リストの要素は角カッコ [ ] を使ってアクセスします。これはC言語や Perl と同じです。リストの要素を取り出して変数に代入することも、リストの要素を書き換えることもできます。添字に負の整数を指定すると、リストの後ろから数えます。list1[-1] は最後尾の要素 100 になり、list1[-2] は後ろから 2 番目の要素 40 になります。

リストの要素には、いろいろなデータ型が混在していてもかまいません。また、要素に式を書くこともできます。

>>> list2 = ['a', 10, 'b', 20, 'c', 30]
>>> list2[2]
'b'
>>> list2[3]
20
>>> [1 + 2, 3 - 4, 5 * 6]
[3, -1, 30]

list2 のリストは、0, 2, 4 番目の要素が文字列で、1, 3, 5 番目の要素が整数になっています。要素に式を書くと、その式の評価結果が要素になります。

リストは入れ子にすることができます。つまり、リストの要素にリストを入れてもかまいません。これで多次元配列を表すことができます。

>>> list3 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> list3[0]
[1, 2, 3]
>>> list3[0][1]
2

list3 のように、リストの中にリストを入れることで 2 次元配列を表すことができます。list3 の 0 番目の要素はリスト [1, 2, 3] で、そのリストの 1 番目の要素は 2 です。この要素は角カッコを 2 つ使って list3[0][1] とアクセスすることができます。list3[0] で 0 番目のリストを取り出し、そのリストの 1 番目の要素を [1] で取り出します。

-- note --------
[*3] リスト操作が得意なプログラミング言語では Lisp が有名です。Lisp のリストは連結リスト (linked list) のことですが、Python のリストは可変長配列として実装されています。

●タプル

タプル (tuple) は更新不能 (immutable) なリストのことです。リストは要素の値を書き換えることができますが、タプルはできません。タプルは丸カッコ '(' と ')' で囲み、要素をカンマ ( , ) で区切ります。( ) は空タプルを表します。リストと同様に、要素はいろいろなデータ型が混在してもかまいません。

簡単な例を示します。

>>> a = (1, 2, 3, 4)
>>> a
(1, 2, 3, 4)
>>> b = (5, 6, 7, 8)
>>> b
(5, 6, 7, 8)
>>> a[0]
1
>>> b[1]
6
>>> a + b
(1, 2, 3, 4, 5, 6, 7, 8)
>>> b * 2
(5, 6, 7, 8, 5, 6, 7, 8)

タプルを生成して変数 a と b にセットします。タプルはリストと同じく角カッコ [ ] で要素を取り出すことができます。ただし、a[0] = 10 のような代入操作はできません。

タプルは、丸カッコを省略しても生成できる場合があります。

>>> c = 1, 2, 3
>>> c
(1, 2, 3)
>>> d = [1, 2, (3, 4, 5)]
>>> d
[1, 2, (3, 4, 5)]

このように、カンマで区切られたデータはタプルに格納されます。ただし、リストやタプルの中にタプルを入れる場合などでは、丸カッコで囲む必要があります。

また、タプルを使って複数の変数に値を代入することができます。

>>> a = 1, 2, 3
>>> a
(1, 2, 3)
>>> x, y, z = a
>>> x
1
>>> y
2
>>> z
3

変数 x にはタプルの 0 番目の要素、y には 1 番目の要素、z には 2 番目の要素が代入されます。なお、リストを使っても変数に値を代入することができます。

>>> a = [10, 20, 30]
>>> a
[10, 20, 30]
>>> x, y, z = a
>>> x
10
>>> y
20
>>> z
30

x, y, z はタプル (x, y, z) ですが、リスト [x, y, z] にしても動作します。

>>> [x, y, z] = [100, 200, 300]
>>> x
100
>>> y
200
>>> z
300

要素が一つのタプルは、要素の後ろにカンマを付ける必要があります。次の例を見てください。

>>> a = 1,
>>> a
(1,)

演算の順序を指定するための丸カッコと区別するため、要素の後ろにカンマを付けます。要素が一つのタプルを生成する場合も、a = 1, のようにカンマを付けます。

●シーケンス

リスト、タプル、文字列はデータを一列に並べたデータ構造という共通点があります。このようなデータ型を「シーケンス (sequence)」といいます。Python にはシーケンスに適用できる共通の操作があり、角カッコ [ ] は文字列にも適用できます。

>>> s = 'abcdef'
>>> s[0]
'a'

Python には「文字」を表すデータ型がないので、s[0] の値は文字列 'a' になります。また、Python の文字列は immutable なので、値を書き換えることはできません。s[0] = 'A' のように代入操作を行うとエラーになります。

スライスはシーケンスの部分列を取り出す操作です。表 2 にスライス操作を示します。

表 2 : スライス操作
操作意味
S[start:end] start から end - 1 まで
S[start:] start から最後尾まで
S[:end] 先頭から end - 1 まで
S[:] 先頭から最後尾まで

S はシーケンスを表します。スライスによって取り出された部分列は元のシーケンスをコピーしたものです。start と end に部分列を指定します。start の位置の要素が部分列の先頭になり、end - 1 の要素が最後尾になります。start が省略されると先頭 (0) に、end が省略されるとシーケンスの要素数に設定されます。どちらも省略するとシーケンスをコピーすることになります。

また、次のように step を指定すると step 刻みで部分列をコピーすることができます。

start:end:step
start::step
:end:step
::step

簡単な例を示します。

>>> s = [0, 1, 2, 3, 4, 5, 6, 7]
>>> s[2:6]
[2, 3, 4, 5]
>>> s[2:]
[2, 3, 4, 5, 6, 7]
>>> s[:6]
[0, 1, 2, 3, 4, 5]
>>> s[::2]
[0, 2, 4, 6]
>>> s[:6:2]
[0, 2, 4]
>>> s[1::2]
[1, 3, 5, 7]
>>> s[1:6:2]
[1, 3, 5]

演算子 + と * はリストやタプルにも適用することができます。次の例を見てください。

>>> [1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]
>>> [0] * 8
[0, 0, 0, 0, 0, 0, 0, 0]

シーケンスに格納されている要素数は関数 len() で求めることができます。len() は length のことで、シーケンスの要素数を「長さ」といいます。

>>> len([1, 2, 3])
3
>>> len('abcde')
5

関数 list() はシーケンスをリストに変換します。次の例を見てください。

>>> list([1, 2, 3])
[1, 2, 3]
>>> list((10, 20, 30))
[10, 20, 30]
>>> list('abcd')
['a', 'b', 'c', 'd']
>>> list()
[]

list() の引数にリストを与えると、そのリストをコピーした新しいリストを返します。文字列の場合は、1 文字ずつ分解してリストに格納します。引数がない場合は空リストを返します。このほかに、シーケンスをタプルに変換する関数 tuple() もあります。

●リストだけに適用できる操作

リストは文字列やタプルと違って値を更新できるので、リストにだけ適用できる操作が用意されています。主な操作を表 3 に示します。

表 3 : リストに適用できる主な操作
操作意味
L.append(x) 最後尾に要素を追加する
L.index(x) 要素 x を探して位置を返す
L.insert(i,x) i 番目に要素 x を挿入する
L.pop() 最後尾から要素を削除する
L.remove(x) 要素 x を削除する
del L[i] i 番目の要素を削除する
L[s:e] = List スライスへの代入

L はリストを表します。リストの操作はメソッド (method) として定義されています。メソッドは次の形式で呼び出します。

object.method(args, ...)

object はデータのことで、その後ろにドット ( . ) を付けて、メソッド名と引数を続けて書きます。Python はオブジェクト指向プログラミング言語なので、すべてのデータをオブジェクトとして扱うことができます。メソッドはオブジェクトを操作する関数のことで、Python では多くの操作がメソッドとして定義されています。オブジェクト指向機能はあとで詳しく説明します。

これらの操作は要素の探索を除いて、リストをコピーせずに直接書き換えることに注意してください。このような操作を「リストを破壊的に修正する」とか「破壊的な操作」といいます。簡単な例を示します。

>>> list1 = [1, 2, 3]
>>> list1.append(4)
>>> list1
[1, 2, 3, 4]
>>> list1.pop()
4
>>> list1
[1, 2, 3]
>>> list1.insert(0, 10)
>>> list1
[10, 1, 2, 3]
>>> list1.remove(2)
>>> list1
[10, 1, 3]
>>> list1.index(1)
1

このように、リストを破壊的に修正するので、変数 list1 の値は書き換えられたリストになります。

スライスへの代入は強力な操作です。指定した部分列を削除し、その部分に右辺のリストを挿入します。簡単な例を示します。

>>> list1 = [1, 2, 3, 4, 5]
>>> list1[2:3]
[3]
>>> list1[2:3] = [100, 200]
>>> list1
[1, 2, 100, 200, 4, 5]
>>> list1[2:2]
[]
>>> list1[2:2] = [10, 20]
>>> list1
[1, 2, 10, 20, 100, 200, 4, 5]
>>> list1[2:6]
[10, 20, 100, 200]
>>> list1[2:6] = []
[1, 2, 4, 5]

list1[2:3] は [3] になりますが、そこに [100, 200] を代入すると、3 が削除されて 100 と 200 が挿入されます。list1[2:2] は空リストになりますが、そこに [10, 20] を挿入すると、要素 2 の後ろに 10 と 20 が挿入されます。スライスに空リストを代入すると、要素を削除することができます。

●ディクショナリ

辞書 (ディクショナリ : dictionary) は「連想配列」のことで、Perl ではハッシュ [*4] と呼ばれています。リストが整数値を使って要素を指定するのに対し、ディクショナリはキー (key) というデータを使って要素を指定します。一般に、連想配列のキーには文字列が用いられますが、Python では immutable なデータ型 (数値、文字列、タプル) であれば、キーとして使用することができます。

ディクショナリは中カッコ '{' と '}' で囲み、要素をカンマで区切って表します。要素は「キー: データ」で指定します。{ } は空のディクショナリを表します。

簡単な例を示します。

>>> d = {'foo': 10, 'bar': 20}
>>> d['foo']
10
>>> d['foo'] = 100
>>> d['foo']
100
>>> d['baz'] = 30
>>> d
{'foo': 100, 'bar': 20, 'baz': 30}

ディクショナリのアクセスはリストと同様に角カッコ [ ] を使います。ディクショナリを生成して変数 d にセットします。d['foo'] でキー 'foo' のデータを取り出したり、そこにデータを代入すれば、d['foo'] の値を書き換えることができます。また、新しいキー 'baz' を追加する場合は、d['baz'] に値を代入すると、ディクショナリに 'baz' とその値が追加されます。

このほかにも、Python にはディクショナリを操作する関数やメソッドが用意されています。表 4 に主な関数とメソッドを示します。

表 4 : ディクショナリの操作
名前機能
dict() ディクショナリを生成する
del D[key] キーと値を削除する
len(D) ディクショナリの要素数を返す
D.clear() ディクショナリを空にする
D.keys() ディクショナリ内のキーを取り出す iterable を返す
D.values() ディクショナリ内の値を取り出す iterable を返す
D.items() ディクショナリ内のキーと値を取り出す iterable を返す
D1.update(D2)ディクショナリ D1 に D2 の要素を追加する

D はディクショナリを表します。iterable はリストのように要素を順番に取り出すことができるオブジェクトのことです。関数 list() の引数はシーケンスだけではなく iterable でも受け付けます。

簡単な使用例を示しましょう。

>>> d1 = dict()
>>> d1
{}
>>> d2 = dict([('foo', 10), ('bar', 20), ('baz', 30)])
>>> d2
{'foo': 10, 'bar': 20, 'baz': 30}
>>> d1.update(d2)
>>> d1
{'foo': 10, 'bar': 20, 'baz': 30}
>>> d1.update([('abc', 40)])
>>> d1
{'foo': 10, 'bar': 20, 'baz': 30, 'abc': 40}
>>> len(d1)
4

関数 dict() はディクショナリを生成します。dict() は引数がないと空のディクショナリを返します。キーと値をタプルにセットし、それを要素とするリストを引数に渡すこともできます。このようなリストを連想リスト (association list) といいます。

メソッド update() はディクショナリ D2 の要素をディクショナリ D1 に追加します。要素の追加はディクショナリだけではなく、連想リストを渡すこともできます。関数 len() を使うとディクショナリに登録されている要素数を求めることができます。

>>> d1.keys()
dict_keys(['foo', 'bar', 'baz', 'abc'])
>>> d1.values()
dict_values([10, 20, 30, 40])
>>> d1.items()
dict_items([('foo', 10), ('bar', 20), ('baz', 30), ('abc', 40)])

Python 3.7 から keys(), values(), items() は辞書に登録された順番でデータを取り出すことができるようになりました。

-- note --------
[*4] Perl で連想配列をハッシュと呼ぶのは、連想配列を実現するアルゴリズムに「ハッシュ法 (hashing)」が用いられているからです。Python のディクショナリもハッシュ法を使って実装されています。

●セット

セット (set) はリストやディクショナリのように要素を格納するデータ型です。複数の要素を格納するデータ型を「コンテナ (container)」とか「コレクション (collection)」と呼びます。これまでに説明したリスト、タプル、文字列、ディクショナリがコレクションになります。セットもコレクションですが、リストと違って要素に順番はなく、重複した要素を含まないところが特徴です。

セットはデータの集合を表すのに便利なデータ型です。集合は要素の順番に意味はありません。たとえば集合 {1, 3, 5, 7} は {7, 5, 3, 1} や {5, 3, 1, 7} と表すこともできます。このように、要素は適当に並べてもかまわないのですが、ある規則で要素を整列させておくと便利な場合もあります。

セットは中カッコ '{' と '}' で囲み、要素をカンマで区切って表します。要素を「キー: データ」で指定するとディクショナリになります。{ } は空のディクショナリを表すので、空のセットは set() で表します。

簡単な例を示します。

>>> a = {1, 2, 3, 4}
>>> a
{1, 2, 3, 4}
>>> b = {1.1, 2.2, 3.3, 4.4}
>>> b
{1.1, 2.2, 3.3, 4.4}
>>> c = {'abc', 'def', 'ghi'}
>>> c
{'abc', 'ghi', 'def'}
>>> d = set()
>>> d
set()
>>> e = {1, 2, 3, 1, 2, 3}
>>> e
{1, 2, 3}

セットを生成するとき、重複した要素は取り除かれ、ユニークな要素だけがセットに格納されます。

セットの基本的な操作関数とメソッドを表 5 に示します。

表 5 : セットの基本操作
名前機能
set() セットを生成する
len(S) セットの要素数を返す
S.add(x) 要素 x を追加する
S.remove(x) 要素 x を削除する
S.clear() セットを空にする
S.update(xs)コレクション xs の要素を追加する

S はセットを表します。簡単な例を示しましょう。

>>> a = set([1, 2, 3])
>>> a
{1, 2, 3}
>>> b = [1, 2, 3, 1, 2]
>>> c = set(b)
>>> c
{1, 2, 3}
>>> d = {'abc':10, 'def':20, 'ghi':30}
>>> e = set(d)
>>> e
{'abc', 'ghi', 'def'}
>>> len(e)
3

set() の引数にコレクションを渡すと、その要素をセットに格納します。このときも、ユニークな要素だけがセットに格納されます。ディクショナリを渡すと、キーがセットに格納されます。また、関数 len() を使うとセットに格納されている要素数を求めることができます。

要素の追加と削除はメソッド add() と remove() を使います。メソッド clear() はセットを空にします。コレクションの要素をまとめて追加したい場合はメソッド update() を使います。簡単な例を示します。

>>> a = set()
>>> a
set()
>>> a.add(1)
>>> a.add(2)
>>> a
{1, 2}
>>> a.remove(1)
>>> a
{2}
>>> a.clear()
>>> a
set()
>>> a.update([1,2,3])
>>> a
{1, 2, 3}

セットは集合を扱うメソッドや演算子が用意されています。主なメソッドを表 6 に示します。

表 6 : セットの集合演算
メソッド機能
s1.issubset(s2)s1 が s2 の部分集合であれば真を返す
s1.issuperset(s2)s2 が s1 の部分集合であれば真を返す
s1.intersection(s2)s1 と s2 の積を求める (s1 & s2)
s1.union(s2) s1 と s2 の和を求める (s1 | s2)
s1.difference(s2) s2 に現れない s1 の要素を求める (s1 - s2)
s1.symmetric_difference(s2)s1 と s2 の両方にちょうど 1 つだけ現れる要素を求める (s1 ^ s2)

簡単な例を示しましょう。

>>> a = {1, 2, 3, 4}
>>> b = {1, 2, 5, 6}
>>> a
{1, 2, 3, 4}
>>> b
{1, 2, 5, 6}
>>> a | b
{1, 2, 3, 4, 5, 6}
>>> a & b
{1, 2}
>>> a - b
{3, 4}
>>> b - a
{5, 6}
>>> a ^ b
{3, 4, 5, 6}
>>> c = {3, 4}
>>> c
{3, 4}
>>> c.issubset(a)
True
>>> c.issubset(b)
False

セットには immutable な frozenset が用意されています。frozenset の場合、セットを更新するメソッド add(), remove(), clear(), update() は使うことができません。

●Python の制御構造

Python の制御構造はとてもシンプルで、プログラムの実行を制御する基本的な操作は、if 文、while 文、for 文の 3 種類しかありません。最初に if 文から説明します。

●if 文

if 文は「条件分岐」を行います。簡単にいうと「もしも~~ならば○○をせよ」という動作です。図 1 を見てください。


              図 1 : if 文の動作

図 1 (1) では、「もしも条件を満たすならば、処理 A を実行する」となります。この場合、条件が成立しない場合は何も処理を実行しませんが、図 1 (2) のように、条件が成立しない場合でも処理を実行させることができます。(2) の場合では、「もしも条件を満たすならば、処理 A を実行し、そうでなければ処理 B を実行する」となります。すなわち、条件によって処理 A か処理 B のどちらかが実行されることになります。

一般に、プログラミング言語では、条件が成立することを「真 (true)」といい、条件が不成立のことを「偽 (false)」といいます。実際のプログラムでは真偽を表すデータが必要になります。Python の場合、真偽を表すデータ型 bool が用意されていて、True と False で真と偽を表します。

このほかにも、数値 0 や 0.0 は偽を表し、それ以外の数値は真となります。文字列の場合、空文字列 '' は偽を表し、それ以外の文字列は真と判断されます。また、空のコレクション、[], (), {}, set() や None というデータ型も偽を表します。

図 2 に if 文の構文を示します。

#
# if test: then節 else: else節
#
if test:
    処理A
    処理B
    処理C
else:
    処理D
    処理E
    処理F

図 2 : if の構文 (1)

Python は Perl と同様に # から改行までが注釈文(コメント)になります。Python の文字コード方式はデフォルトで UTF-8 です。ソースファイルを UTF-8 で記述すれば、そのまま日本語を使用することができます。

if のあとに条件部 test を書き、その後ろにコロンをつけます。このあとインデントを行って、真のときに実行する処理を書きます。処理は一つだけではなく、複数の処理を記述することができます。複数の処理をまとめたものをブロック (block) といいます。ブロックは定義された処理を順番に実行します。なお、条件部が真のときに実行されるブロックを then 節、偽のときに実行されるブロックを else 節と呼ぶ場合があります。

Python はインデントが等しい処理を同じブロックとして扱います。インデントが変化した時点でブロックの定義は終了します。C言語や Perl のように { ... } でブロックを表すのではなく、インデントの深さでブロックを表します。図 2 では 4 文字でインデントを行っていて、処理 A から処理 C は同じインデントなので、同じブロックとして扱われます。したがって、test が真の場合は処理 A から C までを実行し、else 節の処理 D から F は実行されません。

test の結果が偽であれば、else 節に記述されている処理 D から F までを順番に実行します。else の後ろにもコロンをつけることを忘れないでください。なお、else 節は省略することができます。

if 文は図 3 と図 4 のように入れ子(ネスト)にすることができます。

#
# if の入れ子
#
if test_a:
    処理A
else:
    if test_b:
        処理B
    else:
        処理C

図 3 : if 文の入れ子

           図 4 : if 文の入れ子の動作

test_a が偽の場合は else 節を実行します。else 節は if 文なので、条件 test_b を実行します。この結果が真であれば処理 B を実行します。そうでなければ、else 節の処理 C を実行します。この処理は図 5 のように書き換えることができます。

#
# if - elif - else
#
if test_a:
    処理A
elif test_b:
    処理B
else:
    処理C

図 5 : if の構文 (2)

C言語は eles if を使いますが、Python では elif を使って if 文を連結することができます。test_a が偽の場合は、次の elif の条件 test_b を実行します。この結果が真であれば処理 B を実行します。そうでなければ、else 節の処理 C を実行します。なお、elif はいくつでも繋げることができます。

●条件式

Python には if 文のほかに条件式も用意されています。

then式 if test式 else else式

条件式は test式 を評価して結果が真の場合、then式 の評価結果を返します。偽の場合は else式 の評価結果を返します。他のプログラミング言語の三項演算子と同様に使用することができます。

簡単な例を示します。

>>> 1 if True else 2
1
>>> 1 if False else 2
2
>>> a = 1 if True else 2
>>> a
1
>>> a = 1 if False else 2
>>> a
2

条件式の返り値を変数に代入することもできます。

●比較演算子と論理演算子

Python には表 7 に示す比較演算子が用意されています。

表 7 : 比較演算子
演算子意味
== 等しい
!= , <> 等しくない
< より小さい
> より大きい
<= より小さいか等しい
>= より大きいか等しい

C言語の比較演算子とほぼ同じですが、Python は != のかわりに <> を使うことができます。これらの比較演算子は数値だけではなく、文字列や他のデータ型にも用いることができます。また、C言語とは違って、x < y < z のように比較演算子をつなげて書くことができます。

簡単な例を示しましょう。

>>> 1 < 2
True
>>> 1 <= 1 < 2
True
>>> "abc" > "def"
False
>>> "abc" < "def" < "ghi"
True
>>> [1, 2, 3] > [1, 2, 4]
False

Python には表 8 に示す論理演算子があります。

表 8 : 論理演算子
操作意味
not x x の否定(真偽の反転)
x and y x が真かつ y が真ならば真
x or y x が真まはた y が真ならば真

簡単な使用例を示しましょう。

>>> not True
False
>>> not False
True
>>> True and True
True
>>> True and False
False
>>> False or True
True
>>> False or False
False

and は、左項が偽ならば右項を評価せずに偽を返します。or は左項が真ならば右項を評価せずに真を返します。

●in と not in

演算子 in と not in はコレクションの中に要素が含まれているか調べる演算子です。in は要素 x がコレクションに含まれていれば True を返し、そうでなければ False を返します。逆に、not in は要素 x がコレクションに含まれていなければ True を返し、そうでなければ False を返します。

簡単な例を示しましょう。

>>> 5 in [1, 2, 3, 4, 5]
True
>>> 10 in [1, 2, 3, 4, 5]
False
>>> 5 not in [1, 2, 3, 4, 5]
False
>>> 10 not in [1, 2, 3, 4, 5]
True

ディクショナリの場合はキーの有無を調べます。

>>> dic = { 'foo': 10, 'bar': 20 }
>>> 'foo' in d
True
>>> 'baz' in d
False
>>> 'foo' not in d
False
>>> 'baz' not in d
True

●while 文による繰り返し

繰り返しは同じ処理を何度も実行することです。まずは簡単な繰り返しから紹介しましょう。while 文は条件が真のあいだ、ブロックに書かれている処理を繰り返し実行します。

#
# while test: block
#
while test:
    処理A
    処理B
    処理C
else:
    処理Z

図 6 : while 文の構文

図 6, 7 を見ればおわかりのように、while 文はいたって単純です。C言語とは違い、Python の while 文は else 節を定義することができます。else 節は while ループが終了したあとに実行されます。

簡単な例を示しましょう。hello, world を 10 回表示するプログラムをリスト 1 に示します。

リスト 1 : hello. wolrd の表示

n = 0
while n < 10:
    print('hello, world')
    n += 1

変数 n を 0 に初期化し、n の値が 10 よりも小さいあいだ処理を繰り返します。C言語と同様に、n += i は n = n + i と同じ意味です。このほかに、-=, *=, /= も使うことができます。n の値はブロックを実行するたびに +1 されていくので、n が 10 になった時点で繰り返しを終了します。

●for 文による繰り返し

Python にはもう一つ繰り返しを行う for 文があります。for 文はコレクションから順番に要素 (ディクショナリの場合はキー) を取り出して変数に代入し、ブロックに書かれている処理を繰り返し実行します。Python の for 文は Perl の foreach と同じです。C言語の for 文とは違うことに注意してください。for 文の構文を図 8 に、動作を図 9 に示します。

#
# for var in collection:
#     block
#
for 変数名 in コレクション:
    処理A
    処理B
    処理C
else:
    処理Z

図 8 : for文 の構文

for 文の構文は、for と in の間にコレクションの要素を格納する変数を指定し、in の後ろにコレクションを指定します。このあと、コロンを書いてインデントでブロックの範囲を指定します。また、for 文は while 文と同様に else 節を定義することができます。簡単な例を示しましょう。

>>> a = [1, 2, 3]
>>> for x in a:
...     print(x)
...
1
2
3
>>> for x in d:
...     print(x)
...
foo
bar
baz

シーケンスの場合、for 文は先頭から順番に要素を取り出します。ディクショナリの場合、キーを取り出す順番はディクショナリに登録した順番になります。

for 文で使用する変数は、タプルで複数個指定することができます。簡単な例を示します。

>>> for a, b in [[1, 2], [3, 4], [5, 6]]:
...     print(a * b)
...
2
12
30

リストの要素数が変数の個数と一致しないとエラーになります。ご注意ください。

●繰り返しの制御

while 文や for 文は break 文によって繰り返しを脱出することができます。この場合、else 節が定義されていも実行されません。contiune 文は繰り返しの先頭に戻ります。break 文と continue 文の動作を図 10 に示します。

test_b が真で continue 文が実行されると、それ以降の処理を実行せずに条件部のチェックが行われます。つまり、処理 B, test_c, 処理 C は実行されません。for 文で continue 文が実行されると、それ以降の処理は実行されずに次の要素を取り出す処理が行われます。

test_c が真で break 文が実行されると、それ以降の処理を実行せずに while 文や for 文の繰り返しを脱出します。このとき、else 節が定義されていても実行されません。図 10 では、break 文で while 文の繰り返しを脱出すると、while 文の次の処理 E が実行されます。else 節の処理 D は実行されないことに注意してください。

●range() によるリストの生成

for 文を使う場合、要素が数値の iterable を生成する関数 range() を使うと便利です。

range(end)
range(start, end)
range(start, end, step)

関数 range() の引数 start と end はスライス操作と同じ指定方法です。引数が一つで start が省略された場合、iterable の要素は 0 から始まり、値を +1 しながら end - 1 までの数値を生成します。引数が 2 つの場合は start から end - 1 までの数値を生成します。引数が 3 つの場合は、start から end 未満までの数値を step 分加算しながら生成します。

簡単な例を示します。

>>> range(8)
range(0, 8)
>>> for i in range(8): print(i)
...
0
1
2
3
4
5
6
7
>>> range(2, 8)
range(2, 8)
>>> for i in range(2, 8): print(i)
...
2
3
4
5
6
7
>>> range(10, 100, 20)
range(10, 100, 20)
>>> for i in range(10, 100, 20): print(i)
...
10
30
50
70
90

range() を使うと、hello, world を 10 回表示するプログラムは、リスト 2 のようになります。

リスト 2 : hello, world の表示

for i in range(10):
    print('hello, world')

while 文を使うよりも簡単です。1 から 1000 までを加算するプログラムはリスト 3 のようになります。

リスト 3 : 1 から 1000 までの合計値

total = 0
for i in range(1, 1001):
    total += i
print(total)

変数 i には 1 から 1000 までの数が順番にセットされ、変数 total に加算されます。答えは 500500 になります。

●内包表記

Ptyhon は [ ] や { } の中に for 文を書いて、リスト、ディクショナリ、セットを生成することができます。これを「内包表記」といいます。基本的な構文を次に示します。

[式 for 変数, ... in コレクション] => リスト
{式 for 変数, ... in コレクション} => セット
{式k: 式v for 変数, ... in コレクション} => ディクショナリ

最初に要素の値を計算する式を書き、次に for 文を書きます。この後ろに for 文または if 文を続けることができます。辞書の場合、コレクションから取り出した要素の値を使ってキーと値を生成します。式k がキーを生成する式、式v が値を生成する式になります。

簡単な例を示します。

>>> list1 = [1, 2, 3, 4, 5]
>>> [x * x for x in list1]
[1, 4, 9, 16, 25]
>>> [(x, x * x) for x in list1]
[(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
>>> [x * x for x in list1 if x % 2 == 0]
[4, 16]
>>> [x + y for x in range(3) for y in range(10, 13)]
[10, 11, 12, 11, 12, 13, 12, 13, 14]

>>> dic = {'foo': 10, 'bar': 20, 'baz': 30}
>>> {k: v * 2 for k, v in dic.items()}
{'foo': 20, 'bar': 40, 'baz': 60}
>>> {k: v for k, v in dic.items() if k[0] == 'b'}
{'bar': 20, 'baz': 30}

for 文の後ろに if 文を続けると、条件部が真のときに式を評価してリストを生成します。上の例では、x が偶数のときに式が評価されて要素 4 と 16 のリストが生成されます。for 文の後ろに for 文を続けると二重ループになります。上の例では、リストには 9 個の要素が格納されます。

辞書の場合、items() でキーと値を取り出し、それらを使って新しい辞書を生成します。最初の例は値を 2 倍にした辞書を生成し、次の例は b から始まるキーだけを取り出した辞書を生成します。

●for 文と組み合わせて使うと便利な関数

range() のほかにも、for 文は関数 enumerate() や zip() と組み合わせて使うと便利です。

関数 enumerate() は要素の位置が必要なときに使います。

>>> for n, m in enumerate(['abc', 'def', 'ghi']):
...     print(n, m)
...
0 abc
1 def
2 ghi

print() で複数のデータを表示する場合は、カッコの中のデータをカンマで区切ります。データとデータの間には空白が挿入されます。

最初の変数 n に要素の位置 (添字) がセットされ、2 番目の変数 m に要素がセットされます。これはリスト 4 に示す処理と同じです。

リスト 4 : enumerate と同じ処理

n = 0
for m in ['abc', 'def', 'ghi']:
    print(n, m)
    n += 1

変数 n を 0 に初期化する処理と 1 を加算する処理が不要になる分だけ、enumerate() を使ったほうが簡単になります。

zip() は引数に複数のリストを受け取り、各リストの要素をタプルに詰め込み、それを格納した iterable を返します。複数のリストを操作する場合、zip() はとても便利です。

>>> zip(['a', 'b', 'c'], [1, 2, 3])
<zip object at 0x7f2e80c92580>
>>> for x in zip(['a', 'b', 'c'], [1, 2, 3]):
...     print(x)
...
('a', 1)
('b', 2)
('c', 3)
>>> for x, y in zip([1, 2, 3], [10, 20, 30]):
...     print(x + y)
...
11
22
33

●素数を求める

最後に簡単な例題として、素数を求めるプログラムを作ってみましょう。いちばん簡単な方法は、奇数 3, 5, 7, 9, ...をそれまでに見つかった素数で割ってみることです。見つかった素数はリストに格納しておけばいいでしょう。プログラムをリスト 5 に示します。

リスト 5 : 素数を求める(1)

prime_list = [2]

for x in range(3, 100, 2):
    for y in prime_list:
        if x % y == 0: break
    else:
        prime_list.append(x)

print(prime_list)

変数 prime_list は素数のリストで [2] に初期化します。奇数の生成は range を使うと簡単です。最初の for 文で奇数を取り出して変数 x にセットします。次の for 文で prime_list から素数を取り出して変数 y にセットします。

x % y が 0 であれば、x は素数 y で割り切れたので x は素数ではありません。break 文で for ループを脱出します。このとき else 節は実行されないので、x が prime_list に追加されることはありません。

for が最後まで終了すれば x は素数です。この場合は else 節が実行されるので、素数 x は append で prime_list に追加されます。最後に print() で prime_list を表示します。

それでは実行してみましょう。プログラムを prime.py に保存して、シェルで python3 prime.py を実行してください。

$ python3 prime.py
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

100 以下の素数は全部で 25 個あります。

ところで、この方法には無駄があります。x が素数か判別するため、x より小さい素数で割り切れるか調べていますが、実は√x より小さい素数を調べるだけでいいのです。リスト 5 をむりやり改造すると、リスト 6 のようになります。

リスト 6 : 素数を求める(2)

prime_list = [2]

for x in range(3, 100, 2):
    a = False
    for y in prime_list:
        if y * y > x:
            a = True
            break
        if x % y == 0: break
    if a:
        prime_list.append(x)

print(prime_list)

変数 a の使い方がポイントです。x が素数の場合は a をTrue にセットします。最初に a を False に初期化しておきます。y > √y のかわりに y * y > x をチェックし、真であれば a に True をセットして break します。x % y が 0 ならば、a は False のままで break します。そして、for ループが終了した後、変数 a をチェックして True であれば x を prime_list に追加します。

これでリスト 5 よりも高速に素数を求めることができますが、リスト 6 のプログラムはちょっとわかりにくいのが欠点です。この場合、関数を使うとわかりやすいプログラムを作ることができます。関数は次回で詳しく説明します。

●おわりに

Python の基本的なデータ型とデータ構造と制御構造について説明しました。Python はオブジェクト指向言語ですが、無理にオブジェクト指向機能を使わなくても、いろいろなプログラムを作ることができます。特に Python の関数は柔軟性があり、関数を使いこなすとちょっと複雑なプログラムでも簡単に作ることができます。次回は関数とファイル入出力について説明します。


初版 2006 年 2 月 24 日
新版 2022 年 8 月 27 日

Copyright (C) 2006-2022 Makoto Hiroi
All rights reserved.

[ PrevPage | Python | NextPage ]