22: 値を変更・追加・削除できないタプル型を理解する

前回の続きです。

タプル型とは何か

続いてタプル型を見ていきます。タプルはリストとよく似ている型です。

どういうところで登場するかというと、変数への多重代入とかenumerate関数の戻り値ですとか、関数やメソッドで複数の戻り値を返すときにタプルが登場します。(enumerateは後述)

まずリストと同じところは、複数のデータを格納できるとか、中身の方は何でもいいとか、入れ子構造にできる並び順情報を持っているというところです。

違うところはどこかというと、値を追加削除、変更できないところ。それ以外はほとんど一緒です。

つまり、最初にタプルを定義したところから中の値を書き変えることができない、というのがタプルとリストの違いです。

ちなみにこの値を変更できないことをイミュータブルといいます。

リストのように変更できるものをミュータブルと言います。

多重代入はなにかというと、以下のコードの a, b = 10, 100  のように一度に複数の変数に代入することです。

また、 c = 10, 100 では右辺にあるデータ型は実はタプル型です。

a, b = 10, 100
print(a, type(a))  # 10 int型
print(b, type(b))  # 100 int型
c = 10, 100
print(c, type(c))  # (10, 100) tuple型

つまり多重代入の時はタプルを展開してそれぞれその中身を代入していたということになります。

そんなタプルの作り方ですが、大まかに2種類あります。

括弧で囲って値をカンマで区切る。

括弧を書かないでカンマで区切るというやり方です。

タプル型の定義方法

タプルを括弧で囲って値をカンマで区切る

では、まず括弧で区切る方です。

d = (99, 999)

このようにしてタプルを作ることができます。

そして値が一つだけのタプルも作ることができます。

d = (99,)

この場合は(99)するだけではダメで、値の後にカンマも付けなければなりません。

例えば、e = (1)とするとこれはint型になります。一方、e = (1,) のようにカンマをつけた場合はタプルになります。

あまり使い道はないかもしれませんが一応このようなことができます。

タプルを括弧を書かないでカンマで区切る

括弧を省略した場合でもタプルになります。

括弧があるかないかの違いだけです。

こちらも値が一つだけの場合は末尾にカンマを付ける必要があります。

f = 10,

このようにするとタプルになります。

この括弧をつけるつけないの使い分けですが、これは個人的にはまあどっちでもいいかなという気がしています。

括弧をつけたほうがよりタプルと分かる書き方なので、慣れないうちは括弧をつけてタプルと明確にわかるようにしておいたほうがいいかもしれません。

タプルの値の取り出し方はリストと同じです。

タプルを取り出したい場合はa[1]のようにインデックスで指定します。

[1]とやれば100ですし、[2]とやれば1000というようにリストと同じ取り出し方ができます。

値を変更できないことを検証

値を変更できない、ということをやってみます。例えば[2]として、書き換えを試みます。

a[2] = 999

エラーになります。

タイプエラーですね。タプルオブジェクトは項目の割り当てをサポートしていませんと言うことで、書き換えできませんと怒られています。

つまり、タプルは最初に定義した時から値を書き換えることができないという性質を持っています。

enumerate関数をちょっとだけ説明しておきたいと思います。enumerate関数というのは、この後登場するfor文と一緒に組み合わせて使うものです。

for文はリストなどのデータの集まりの値を1つずつ取り出すときに用います。詳しくは後述します。

例えば次のようなコードで試してみます。

langs = ['Python', 'Java', 'C++', 'C#', 'JavaScript', 'PHP', 'Swift']
for lang in langs:
    print(lang)

上記のようなfor文でprintすると、langsの要素を取り出すことができます。

値を1個ずつ取り出して何か処理をできる、というのがfor文ですが、この時にenumerate関数を使用すると、タプルが返ってきます。それをnum と lang という変数で受け取っています。

langs = ['Python', 'Java', 'C++', 'C#', 'JavaScript', 'PHP', 'Swift']
for num, lang in enumerate(langs, start=1):
    print(num, lang)

numerate関数を使うと、このように番号を振ることができます。

引数 start=1 とすることで、0から始まるのではなくて1から数字をはじめられます。今の段階で理解するのは難しいと思いますので、なんとなく「へーそうなんだ」くらいで構いません。

このときenumerate関数が返しているのは一体何かというと、実はタプルです。タプルが数値とリストの要素を返し、それをnumとlangが受け取っています。

このように関数が複数の値を返すパターン、これは多重代入と同じです。番号と中身の要素を返すようになるということですね。このようにタプルが登場してきます。

タプルを使った処理の例

それともう一つ、タプルは関数およびメソッドの戻り値として登場するパターンがあります。

ちょっとフライング気味ですが確認しておきます。

自動販売機にお金を入れると、なぜか2倍になってチャリンと返ってくるというものをイメージしてやってみます。

def foo(money):
    return money * 2
result = foo(100)
print(result)

defというキーワードを使用して関数を定義します。関数名はfooとし、moneyという引数でお金を受けり、return monery *2 とするとお金が2倍になって返ってくるという関数を作ることができます。

関数は詳しくは後述します。現段階ではなんとなくの理解で構いません。

ここでは「関数はタプルを返せる」という事だけ覚えてください。

タプルを返すにはどうするかというと、以下のようにします。

このように、自分で作る関数とかenumerate関数とか多重代入といったところにタプルが登場してきます。(関数の作り方、タプルの返し方は詳しくは後述します)

タプルについてのまとめです。

タプルというのはリストとよく似ているデータ構造です。

ただし、書き換えできないイミュータブルであると言うところが違います。

タプルを作るには、値をカンマで区切ります。

このとき、括弧を使っても使わなくても大丈夫です。

カンマで値を区切るとタプルになります。

タプルからの取り出しはリストと一緒です。

タプルが登場する機会というのはしばしばありますので、どういう性質を持っているか、どうやって値を取り出すかということを覚えていただければと思います。