夜行月報

“夜更かし”から“新しい”をみつけるためのブログ

Rubyistが学ぶPython ~ タプル編 ~

Rubyistが学ぶPython ~ タプル編 ~ エンジニア歴1年半、メイン言語としてRuby一筋でやってきた自分が、最近Pythonを学び始めたその備忘録です。 今回はPythonのタプルについて勉強してきました。

※以下、Python3についての内容です。

タプルについて

タプルは、配列のように任意の値を集めたシーケンス。 Pythonの配列はミュータブルだけど、タプルはイミュータブル。一度定義すると、後から要素を追加したり削除したり変更したりすることはできない。 Rubyにはないデータ型だったので少し戸惑い。(配列にfreezeかけたりして似たようなことはできるよう)

タプルの生成

()と記述することで、空のタプルを生成できる。

new_tuple = ()
# >>> ()

要素を持つタプルを記述するときには、以下のように記述する

my_tuple = ('foo', 'bar', 'piyo')
# >>> ('foo', 'bar', 'piyo')

なるほど()がタプルを定義するのだな...と思いきや、実は()なしでもいける。

truth_tuple = 'foo', 'bar', 'piyo'
# >>> ('foo', 'bar', 'piyo')

ただ、要素が1つだけのタプルを()無しで定義するには、要素の後ろに(その要素の後ろに何も続かなくでも)カンマを付ける必要がある。

single_tuple = 'foo',
# >>> ('foo',)

タプルをタプルたらしめるのは()でなく,。ここ絶対テストでる。 でも、分かりやすくするために()で囲っておいたほうが無難だと思う。「暗黙よりも明示がいい」。Python公案にもしっかりと書いてある。

また、変換関数のtuple()を用いて、配列など他のものからタプルを作成できる。

array = [1, 2, 3, 4, 5]
tuple_from_ary = tuple(array)
# >>> (1, 2, 3, 4, 5)

# Pythonの辞書からは、そのキーを集めたタプルを作成できる
dictionary = { 'message': 'success!', 'status': 'true'}
tuple_from_dic = tuple(dictionary)
# >>> ('message', 'status')

タプルを用いた変数への一括代入

タプルのアンパックと呼ばれる方法を用いると、タプルに格納された値を複数の変数に一括で代入できる。

tuple = 'foo', 'hoge', 'piyo'
a, b, c = tuple
print(a, b, c)
# >>> foo bar hoge

# 変数の入れ替えも1行で行える
a, b = b, c
print(a, b)
# >>> bar foo

# 列挙可能オブジェクトをタプルの形式で保持しておけば、
# アンパックを用いたシンプルでエレガントなループ処理が書ける
num_pairs = [(1, 1), (1, 2), (1,3), (2, 1), (2, 2), (2, 3)]
for first, second in num_pairs:
    print(first, second)

# >>> 1 1
# >>> 1 2
# >>> 1 3
# >>> 2 1
# >>> 2 2
# >>> 2 3

スポンサーリンク

 

タプルへのアクセス

タプルにアクセスするには、配列と同じように先頭からのオフセットを指定する。 タプルの要素の個数を超える数を指定すると、IndexErrorが起きるので注意。

test_tuple = ('hoge', 'fuga', 'piyo')
print(test_tuple[1])
# >>> fuga

# pythonのスライスを用いると複数取得も
print(test_tuple[0:2])
# >>> ('hoge', 'fuga')

タプル同士の結合、値の変更(?)

タプル同士を+演算子で繋げると、二つのタプルを結合した新しいタプルオブジェクトを作成することができる。 もちろん、この時それぞれの元のタプルに変更は生じない

tuple_1 = (1, 2, 3)
tuple_2 = (4, 5)

tuple_3 = tuple_1 + tuple_2
print(tuple_3)
# >>> (1, 2, 3, 4, 5)
print(tuple_1)
# >>> (1, 2, 3)
print(tuple_2)
# >>> (4, 5)

# 一見タプルのを変更しているように見える以下のコードも
# 実際は新しいオブジェクトを再代入しているだけなので正常に動作する
tuple_1 += tuple_2 # tuple_1 = tuple_1 + tuple_2
print(tuple_1)
# >>> (1, 2, 3, 4, 5)

タプルは要素の追加、削除、変更ができないが、それはタプルが持つ参照を変更する場合であり、例えばタプルの一要素の配列の中身を変更したり削除したりといったことは普通に可能。

contain_ary = ([1, 2, 3], [4, 5, 6])

contain_ary[0].append(4)
contain_ary[1].clear()

print(contain_ary)
# >>> ([1, 2, 3, 4], [])

純粋な意味でタプルの参照を変更したい場合は、list()関数を用いて一度配列オブジェクトに変更してから処理をし、そのあとtuple関数で再びtupleに戻す、という方法も取れる。 しかし、そういった変更を前提とするような処理なら最初からタプルじゃなく配列使えよって感じがする。。。

タプルを用いるメリット

先に述べたとおり、タプルはイミュータブルなデータ型なので、誤って書き換えてしまう心配がない。 また、タプルはPythonの辞書(Rubyでいうハッシュ)のキーとして使うことができるため、何らかの意味を持つデータのペアや組み合わせをキーとした辞書を作ることができる。

dice_pairs = {
  (1, 1): '10点',
  (1, 2): '1点',
  (1, 3): '2点',
    ・
    ・
    ・
  (6, 5): '1点',
  (6, 6): '100点'
}

print(dice_pairs[(1, 2)])
# >>> 1点

はえー、便利。

タプルオブジェクトのメソッド

タプルオブジェクトが呼び出せメソッドは、index()count()のみ。それぞれ、引数に与えた値をタプルの中から探し、その最初のオフセットや個数を返す。

target_tuple = (1, 2, 3, 3, 4, 5)
print(target_tuple.index(5))
# >>> 5

print(target_tuple.count(3))
# >>> 2

その他

Pythonの書式指定("my favorite number is %d and %d" % (1, 4)みたいな。Rubyにもあったよね)など、上記以外でもタプルを用いる場面はたくさんあるので、その性質や扱い方を知っておくことは、Pythonicなエンジニアを目指すなら必須かと思われます。

また、クラス構造をシンプルに表せるという名前付きタプルもあるようですが、そちらについてはまたの機会に。

参考