4. Pythonのデータ型(コレクション編)#
節サブタイトル
データ型をまとめるコレクションの紹介
Pythonのデータ型のうち、複数のデータ型をひとまとめにして扱えるコレクションを紹介します。
4.1. はじめに#
本節では次の4つを扱います。リスト(list
)、タプル(tuple
)、辞書(dict
)と集合(set
)を扱います。
4.2. リスト(list)#
リストはコレクションの1つです。複数の型のデータをひとまとめにできます。
リストを定義するには角括弧([ ]
)を使い、含める要素をカンマ(,
)で区切ります(リスト 4.1)。
>>> ['spam', 'egg', 0.5]
['spam', 'egg', 0.5]
リストも文字列と同様に、結合やスライスが使えます(リスト 4.2)。
>>> ['spam', 'ham'] + ['egg'] # リストの結合
['spam', 'ham', 'egg']
>>> ['spam'] * 5 # リストの繰り返し
['spam', 'spam', 'spam', 'spam', 'spam']
>>> ['spam', 'ham', 'egg'][0] # リストの0番目を取得する
'spam'
>>> ['spam', 'ham', 'egg'][1:] # リストのスライス(1番目以降)
['ham', 'egg']
>>> len(['spam', 'ham', 'egg']) # リストの長さ
3
>>> 'ham' in ['spam', 'ham', 'egg'] # リストに特定の文字列が含まれるか
True
4.2.1. for文#
リストは、 for
文の繰り返し用変数として使えます(リスト 4.3)。
>>> for animal in ['cat', 'dog', 'snake']:
... print(animal)
...
cat
dog
snake
4.2.2. 要素の追加#
リストに要素を追加するには、 .append()
メソッドを使います。
.append()
メソッドはリストの末尾に要素を追加します(リスト 4.4)。
>>> animals = ['cat', 'dog', 'snake']
>>> animals.append('elephant')
>>> animals
['cat', 'dog', 'snake', 'elephant']
リストは変更可能なオブジェクトです。
.append()
メソッドによって、 animals
というリストの内容が変更されます。
4.2.3. リスト内包表記#
リスト内包表記はリストの定義方法の1つです。 比較的複雑なリストの定義を、シンプルに記述できます。
for
文の例として animals
リストから各文字列の長さの一覧を作ります(リスト 4.5)。
>>> ret = []
>>> for animal in animals:
... ret.append(len(animal))
...
>>> ret
[3, 3, 5, 8]
リスト 4.5 をリスト内包表記に置き換えると、 リスト 4.6 のようになります。
>>> [len(animal) for animal in animals]
[3, 3, 5, 8]
3行で記述していたコードが1行になりました。内包表記を使うと簡潔に記述できることがわかったと思います。 最初は見慣れないかもしれませんが、徐々に慣れていくと良いと思います。
リストの定義時に、角括弧([ ]
)の内部に for
を書きます。
for <変数名> in
の部分は通常の for
文と同じです。
for
の左側でひとつひとつ取り出した要素(ここでは animal
)を使い、リストの各要素を作ります。 リスト 4.6 の場合、 len(animal)
の結果が各要素になります。
リスト内包表記は、条件文や複数回のループ処理も記述できます。 複雑にしすぎると、かえって可読性を落としますので、ほどほどに使用することをおすすめします。複雑になりすぎる場合はループ処理で書きましょう。 リスト内包表記の仲間に、辞書(後述)を生成する辞書内包表記や、セット(後述)を生成するセット内包表記やジェネレータ式(本チュートリアルでは取り扱わない)などもあります。 内包表記はPythonの強力な機能の1つなのでぜひ覚えておくとよいでしょう。
他にも役に立つ書き方があるので、Pythonのドキュメントを参考にしてください。
4.2.4. 複数変数への代入#
リストのようなシーケンス型から他のデータ型に値を代入する際、複数の変数への代入を一度に行えます(リスト 4.7)。
>>> dog, cat = ['dog', 'cat']
>>> dog
'dog'
>>> cat
'cat'
複数の変数への代入は、右辺が文字列や後述するタプルの場合でも可能です。
4.3. タプル(tuple)#
タプルはリストと同じコレクションの1つです。
タプルを定義するには括弧(( )
)を使い、含める要素をカンマ(,
)で区切りで並べます(リスト 4.8)。
>>> ('spam', 'ham', 4)
('spam', 'ham', 4)
タプルもリスト、文字列と同様に、結合やスライスが使えます(リスト 4.9)。
>>> ('spam', 'ham') + ('egg',) # タプルの結合
('spam', 'ham', 'egg')
>>> ('spam',) * 5 # タプルの繰り返し
('spam', 'spam', 'spam', 'spam', 'spam')
>>> ('spam', 'ham', 'egg')[0] # タプルの0番目を取得する
'spam'
>>> ('spam', 'ham', 'egg')[1:] # タプルのスライス(1番目以降)
('ham', 'egg')
>>> len(('spam', 'ham', 'egg')) # タプルの長さ
3
>>> 'ham' in ('spam', 'ham', 'egg') # タプルに特定の文字列が含まれるか
True
要素が1つのタプルを定義する際にもカンマが必要な点に注意してください。 これは、処理の優先順位を決める括弧と区別するためです(リスト 4.10)。
>>> ('spam',)
('spam',)
>>> ('spam')
'spam'
また、括弧を省略してタプルを定義できます(リスト 4.11)。
>>> 'dog', 'cat'
('dog', 'cat')
4.3.1. リストとの違いと使いどころ#
リストと違いタプルは不変(immutable)な値です。
リストの .append()
のような破壊的な操作は存在しません。
.append()
のような処理を行いたい場合は、タプルの結合により新しいタプルを作るしかありません。
タプルは、関数の戻り値や不変としたい設定用の値に使います。
関数からタプルを返すと、簡単に複数の値を戻り値として返すことができます。
シーケンス(リスト、タプルや文字列)を受け取り、初めの要素と残りの要素に分割する関数を、 リスト 4.12 に示します。
>>> def head_splitter(seq):
... return seq[0], seq[1:]
...
>>> head, tail = head_splitter(['head', 'body', 'tail'])
>>> head
'head'
>>> tail
['body', 'tail']
戻り値の順番に意味が必要になるため、要素の多いタプルを返すのは避けましょう(リスト 4.13)。
>>> def bad_implementation():
... return 'username', 'user_password', 'user_id', 'user_permission1', 'user_permission2'
...
>>> username, user_password, user_id, user_permission1, user_permission2 = bad_implementation()
要素数の多いタプルを返す関数 のような場合、辞書(後述)、専用のクラスのインスタンス、名前付きタプルなどで返しましょう (クラスの定義方法、名前付きタプルについては、本チュートリアルでは説明しません)。
4.4. 辞書(dict)#
辞書もリスト、タプルと同じコレクションです。
辞書の各要素はキー(key)と、対応する値(value)を持ち、Python 3.7 以降では要素の挿入順が保持されます。
辞書を定義するには波括弧({}
)で各要素を囲み、コロン(:
)でキーと値を書きます(リスト 4.14)。
値と次のキーの間はカンマ(,
)で区切ります。
>>> user_info = {'user_name': 'taro', 'last_name': 'Yamada'}
>>> user_info
{'user_name': 'taro', 'last_name': 'Yamada'}
リスト 4.14 の user_info
から 'user_name'
の値を取り出す処理は、 リスト 4.15 になります。
>>> user_info['user_name']
'taro'
既存の辞書に値を設定するには、 辞書[<キー>]
に直接代入します(リスト 4.16)。
>>> user_info['first_name'] = 'Taro'
>>> user_info
{'user_name': 'taro', 'last_name': 'Yamada', 'first_name': 'Taro'}
4.4.1. in演算子#
辞書内にキーが存在しているかどうかを調べるには、 in
演算子を使います(リスト 4.17)。
>>> 'user_name' in user_info
True
>>> 'bio' in user_info
False
4.4.2. .get()メソッド#
辞書から値を取得するときに、キーが存在しない場合はエラー(KeyError)になります(リスト 4.18)。
>>> user_info['bio']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'bio'
.get()
メソッドで取得すると、キーが存在しない場合には None
が返されます( リスト 4.19)。
>>> user_info.get('user_name')
'taro'
>>> bio = user_info.get('bio')
>>> print(bio)
None
None
は、Pythonの組み込み定数の1つで、何も値がないことを表します。
インタープリタは None
を表示しないので、明示的に print
関数を使っています。
値が存在しないときに None
以外の値を返したい場合には、 .get()
メソッドの第2引数に返したい値を指定します。
'bio'
の値が取れない場合に空文字列(''
)としたい場合は、 リスト 4.20 のように書きます。
>>> user_info.get('bio', '')
''
4.4.3. for文#
辞書を for
文の繰り返し用変数として使用すると、変数にはキーが入ります(リスト 4.21)。
>>> user_info = {'user_name': 'taro', 'last_name': 'Yamada'}
>>> for key in user_info:
... print(key)
... print(user_info[key])
...
user_name
taro
last_name
Yamada
ヒント
4.4.4. .keys()メソッド、.values()メソッド、.items()メソッド#
すべてのキー、値の要素をリストで取得するには、 .keys()
、 .values()
、 .items()
メソッドを使います。
.keys()
: すべてのキーを取得.values()
: すべての値を取得.items()
: すべてのキーと値を、要素が2つのタプルで取得
たとえば、辞書内のすべてのキーと値を取得するには、 リスト 4.22 のようにします。
>>> d = {'foo': 'spam', 'bar': 'ham'}
>>> d.items()
dict_items([('foo', 'spam'), ('bar', 'ham')])
.items()
の結果を for
文に渡せば、辞書内のすべての値を使った繰り返し処理を書けます。
for
文の変数名を2つ指定することで、要素が2つのタプルからキーと値をそれぞれの変数に一度で受け取れます(リスト 4.23)。
>>> d = {'foo': 'spam', 'bar': 'ham'}
>>> for key, value in d.items():
... print(key, value)
...
foo spam
bar ham
各メソッドの戻り値はイテレータブルオブジェクトです。
コラム: イテレータブルオブジェクト
.keys()
、 .values()
、 .items()
の戻り値の型はリストやタプルではなくそれぞれ dict_keys
、 dict_values
、 dict_items
ですが、いずれも for
文でデータを取り出すことができます。Pythonの for
文は、「イテレータブルオブジェクト」という連続したデータ構造を表すオブジェクトであれば扱えるため、このような動きになります。
4.5. 集合(set)#
集合型(set)はコレクション型の1つです。
リストやタプルのように値しか持ちませんが、順序も持ちません。
1つの集合内には同じ値が1つしか存在できません。そのため、一意な値を管理する際に非常に役立ちます。
ただし、辞書のキーと同じように、集合内には不変の値しか持てません。
集合は波括弧({ }
)で囲んだ中に、要素をカンマ(,
)で区切って指定して定義します(リスト 4.24)。
>>> {'spam', 'ham'}
{'spam', 'ham'}
>>> {'spam', 'spam', 'spam'}
{'spam'}
4.5.1. .add()メソッド#
集合に要素を追加するには .add()
メソッドを使います。
追加したい要素を引数に渡して呼び出します(リスト 4.25)。
>>> unique_users = {'dog', 'cat'}
>>> unique_users.add('snake')
>>> unique_users
{'dog', 'cat', 'snake'}
集合の要素数も len()
関数で取得できます(リスト 4.26)。
>>> len(unique_users)
3
>>> unique_users.add('snake')
>>> unique_users.add('snake')
>>> unique_users.add('snake')
>>> len(unique_users)
3
リスト 4.26 で要素が2つの unique_users
という集合を定義し、後に要素を追加しています。
ここで unique_users
の要素数は3です。
リスト 4.26 では、集合内にすでに存在する 'snake'
という要素を .add()
で3 回追加していますが、 len()
関数の結果は変わりません。
このように、集合では一意な値が適切に管理されていることがわかります。
4.5.2. 集合の積と和#
2つの集合から集合の積を取り、両方の集合に存在する要素の集合を取得できます。
この場合、2つの集合に対してAND(&
)演算子を使います(リスト 4.27)。
>>> allowed_permissions = {'edit', 'view'}
>>> requested_permissions = {'view', 'delete'}
>>> allowed_permissions & requested_permissions
{'view'}
リスト 4.27 では、アプリケーションから許可された権限の一覧 allowed_permissions
を使って、ユーザに要求された権限 requested_permissions
のフィルタリングを行う状況を想定しています。
結果としてユーザに許可された権限は 'view'
のみとなりました。
集合の和も取得できます。
両方の集合を合わせた集合を取得できます。
2つの集合に対してOR(¦
)演算子を使います(リスト 4.28)。
>>> editor = {'edit', 'comment'}
>>> reviewer = {'comment', 'approve'}
>>> editor | reviewer
{'comment', 'approve', 'edit'}
リスト 4.28 では、editor
と reviewer
はロール(役割)を想定しています。
この2つのロールを持つユーザは、'edit'
、'comment'
と 'approve'
の権限を持つことを算出しました。
4.6. まとめ#
データ型をひとまとめにして扱えるコレクションを紹介しました。 実現したいことに合わせたコレクションを選択しましょう。