【Python遊び場】 Listアンパックの基本操作実験記


概要

Pythonリストの要素をiterationする時に基本操作は二つがあり:

  1. 要素そのものを読む
  2. 分解(アンパック)可能な要素をアンパックし、要素の要素を読む

この記事で以下の種類の格納要素に対して、pythonリストのアンパック操作を見ていきます。

-tuple
-set
-dictionary
-list
-string
-integer, float
-(混合list)

【Tuple】

要素の順番が決まっていて、直感的に分解しやすいデータタイプ。

st = [(83000, 8.7), (88000, 8.1),
(48000, 0.7), (76000, 6),
(69000, 6.5), (76000, 7.5),
(60000, 2.5), (83000, 10),
(48000, 1.9), (63000, 4.2)]

Index一つを指定すると、要素そのものを読む:

よって、各Tupleを出力。

これで、Index二つを指定すると、一要素ずつをアンパックする:

これで、リストに格納されている全てのTupleに二つの要素があるため二つのindexで分解できたが、それ以上の数のindexを指定するとどうなりますでしょうか。

あかんでぇ。アンパックするのに(tupleの)要素を増やす必要あると、怒られる。

三つの要素で構成されているTupleで試します。


sl=[(1, 100, 1000), (2, 200, 2000), (3, 300, 3000)]

因みに、printするindexの数は関係ない。「in」の前に列挙するindexの数のみアンパックの可否に関係する。

先ほどは、tupleの要素より多いindexの数を指定するとどうなるか試してみたが、tupleの要素より少ないとどうなる?

これも怒られますね。今回は、指定したindex達でアンパックするのに(tupleの)要素が多すぎる、と。

では、tupleのサイズがバラバラだとどうなるかい?

sv=[(1, 10), (2, 20), (3, 30, 300)]

また、リスト要素として出力可能:

だが、アンパックにおいては:

どっちもだめ!
リストの要素をアンパックするのに、全ての要素が同じサイズである必要があります。

もっと言うと、操作として:
1.Listのアンパックを普通に進める
2.アンパックできなかった要素に遭遇すると、ValueError例外を投げる
3.アンパック処理ストップ

左側の画像では、三番目で処理ストップしたため、最初の二つのtupleをアンパックした結果も表示されます。

【Set】

リストの要素がsetの場合どういう操作になるか見てみます。

sd=[{1, 10}, {2, 20}]

(まず、setでの格納の仕方自体を再確認)

setのリストをアンパック:

setもアンパック可能。
tupleの場合と同じく、setの要素数とアンパックindexの数が一致していないといけない。

【Dictionary】

二つのDictionaryを定義:

ld=[{"id": 0, "double": 00}, {"id": 1, "double": 11}]     #(00 becomes 0)

lde=[{'id0': 0, 'val0': 00}, {'id1': 1, 'val1': 10}]

Dictionaryの格納の仕方を再確認:

(Dictionaryの中のkey-valueペアは定義した時の順番が保たれず、dictionaryの中で順番無く格納されています。print時はinterpreterの設定によりkeyのアルファベット順で表示されることが多いが。)

なお、dictionaryのkey/valueも書き出せる:

で、アンパック試す:

Dictionaryもアンパック可能。
Tuple/setと同じくdictionaryに格納されている要素とアンパック用indexの数が一致していないといけない。

そして要素数がバラバラのDictionaryのリストもtuple/setと同じくアンパックできませぬ :


ldd = [{"id": 0, "name": "thor"}, {"id2": 1}, {"id3": 2, "otherval": 200, "secondotherval": 2000}]

(二番目のdictionaryでしくじった。)

【List】

では、リスト自体もアンパックできますでしょうか。

ll=[[1, 10], [2, 20]]
lm=[[1, 20], [2], [3, 30, 300]]

リストもアンパック可能。
そして上記全部と同じく、listの要素数とアンパックのindex数が一致する必要がある。

【String】

はたして文字列もアンパック可能でしょうか?

lz=['hi', 'no']
lw=['hi', 'awesomeness', 'three']

なんと、stringもアンパック可能です。
(pythonでstringの表現の仕方はcharのリストだと考えると、当然のことですが。)

そして、stringの長さ(リスト容器に入っているchar数)が一致していないと、同じくアンパックできない。

【Integer, Float】

では、数字系の型はどうでしょう?

lj=[24, 36, 59]        #array of integers
lf=[20.3, 60.6, 10.1]  #array of floats

それぞれのアンパックを試す:

この二つはダメですね。
数字系のデータのメモリー上での格納の仕方はリストと根本的に違うためです。それでリストみたいに個別の要素に分解不可能のためint/floatの中身でのiterationも不可能です。

因みに、数字のstringへのキャストが出来るので、

ダメもとで試してみるが:

当然だめです。

(これはアンパックなんやかんや以前の段階で、そもそもx, yというindex変数をキャストしようとしていることになります。indexのデータ型はindexが差しているデータ(リストljに格納されているinteger要素)と関係がないためです。)

【混合 list】

では最後に、リストに入っているデータ型がバラバラの時、どうなるのでしょうか。

lx=[[1, 10], (2, 20), {3, 30}, {"id": 4, "val": 40}]


要素の全部がアンパック・iteration可能なデータ型であればアンパック可能です。

そうではない場合は、

lmx=[[1, 10], (2, 20), {3, 30}, {"id": 4, "val": 40}, 30]

一つでもアンパック・iteration不可能な要素が入っていると、上記と同じく:

1.Listのアンパックを普通に進める
2.アンパックできなかった要素に遭遇すると、TypeError例外を投げる
3.アンパック処理ストップ

の操作になります。

おさらい

この記事では、様々な中身のリストをアンパックしてみました。
それで学んだのは:

1.for [何か] in [リスト名] を指定するときに、
[何か]の数が一つ(x だけなど)の場合は、
リストの要素そのものを返します。

例えば

sd=[{1, 10}, {2, 20}]

for y in sd: print y 

は、

set([1, 10])
set([2, 20])

を返します。

2.for [何か] in [リスト名] を指定するときに、
[何か]の数が二つ以上(x, y など)の場合は、
リストの要素一つ一つを分解(アンパック)しようとします

例えば

sd=[{1, 10}, {2, 20}]

for y, z in sd: print y, z 

は、

1 10
2 20

を返します。

3.リストの要素を全てアンパックできるのに必須条件:

-リストの要素が全て同じ長さであること

-リストの要素が全て分解可能(iterable)なデータ型であること

※なお、指定するindexの数(上記の x, y など)がリストに格納されている要素の長さと一致していないといけないです。

指定するindexが多すぎる(長さ2の要素のリストに、for x, y, z in など)と → ValueError: need more than ○○ value to unpack

指定するindexが少なすぎる(長さ3の要素のリストに、for x, y in など)と → ValueError: too many values to unpack

4.アンパックはiterationの一種であるため、データ型としてiterableなもの以外は分解できません。

アンパック可能型:list, string, dictionary, set, tupleのリスト系型など
アンパック不可能型:integer, float, doubleなどの数字系型など


といった、Pythonの基礎動作の説明でしたが、復習やら参考やらに是非お使いください。