🔙
🔝

タプル (tuple)

これがわかるようになればひと皮むけます👍

Chatpter.1 - タプルとは

タプルとは

  • 簡単に言うと、リストの「書き換え禁止版」です。

  • 一度タプルを作ったら、何があっても値を書き換えたり、要素を追加したり、要素を削除したりすることは一切できなくなります。

  • 見た目はすでに何度か見たと思いますが、こんな感じです。

    nums = (1, 2)
    
    titles = ('To TUPる', '魔法少女猫たぷる')
    

    ( ) で囲います。リストの [ ] が ( ) になっただけです。


  • 値を参照することはできます。

    titles = ('To TUPる', '魔法少女猫たぷる')
    print(titles[0])
    
    To TUPる
    タプルを作ってみよう!

  • 値を書き換えようとするとこうなります。

    titles = ('To TUPる', '魔法少女猫たぷる')
    titles[0] = 'Rewrite'
    print(titles)
    
    Traceback (most recent call last):
      File "Main.py", line 2, in <module>
        titles[0] = 'Rewrite'
    TypeError: 'tuple' object does not support item assignment
    

  • 要素を削除しようとするとこうなります。

    titles = ('To TUPる', '魔法少女猫たぷる')
    del titles[0]
    print(titles)
    
    Traceback (most recent call last):
      File "Main.py", line 2, in <module>
        del titles[0]
    TypeError: 'tuple' object doesn't support item deletion
    

  • 要素を追加したり挿入したりする方法は用意されてませんので、試しようがありません。

  • また、こうするとエラーになります。

    nums = (1)
    print(nums[0])
    
    Traceback (most recent call last):
      File "Main.py", line 2, in <module>
        print(nums[0])
    TypeError: 'int' object is not subscriptable
    

    ( ) が省略されて、int1 になってしまうのです。


  • nums = (1)
    print(nums)
    print(type(nums))
    
    1
    <class 'int'>

  • 要素が1つのタプルを作る場合はこうします。

    titles = ('To TUPる',)
    print(titles)
    
    ('To TUPる',)
    実際に見てみてください!

    変なの~。😹

Chatpter.2 - クセの強いタプルの扱い方

クセの強いタプルの扱い方

タプルの使いどころ

タプルの使いどころ

  • 初めのうちはリストを使えば不都合はほとんどありません。

  • しかし zip() の戻り値のように、タプルになって返ってくることがあります。

  • それを扱うためにも、多少はタプルの特性を知っておいた方が、余計なストレスを作らずに済むかもしれません。

  • タプルにはタプルの良さがあるのですが、とりあえずは積極的に使っていくことはしないで、やむをえずタプルを扱わざるを得ない場面に遇った時の対処として簡単に学んでおきましょう。


  • 初めのうちでも使うかもしれない使いどころを2つだけ紹介します。

  • 戻り値がタプルになる

    zip() を例に見てみましょう。

    beasts = ['ケルベロス', 'インキュベーター']
    calleds = ['ケロちゃん', 'キュゥべえ']
    
    print(list(zip(beasts, calleds)))
    
    [('ケルベロス', 'ケロちゃん'), ('インキュベーター', 'キュゥべえ')]

  • 辞書のキーに使う

    「Fizz Buzz」を例に見てみましょう。

    fizzbuzz = {
        (True, True): 'アホイヌ',
        (True, False): 'アホ',
        (False, True): 'イヌ',
    }
    
    for i in range(1, 101):
        aho = (i % 3 == 0)
        inu = (i % 5 == 0)
        fizzbuzz[(False, False)] = i
        
        print(fizzbuzz[(aho, inu)])
    
    (略)
    8
    アホ
    イヌ
    11
    アホ
    13
    14
    アホイヌ
    16
    (略)
戻り値がタプルの時の扱い方

戻り値がタプルの時の扱い方

  • 再び zip() で書いてみます。

    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    
    for ziped_nums in zip(num1, num2):
        print(ziped_nums)
    
    (1, 4)
    (2, 5)
    (3, 6)
    実際に見てみてください!


    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    
    for a, b in zip(num1, num2):
        print(a, b)
    
    1 4
    2 5
    3 6
    実際に見てみてください!

    これらのように、文で使うととても便利です。

  • zip() は、そのまま print() で出力するとこうなります。

    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    print(zip(num1, num2))
    
    <zip object at 0x145f54e4cb40>

  • この状態では、値を直接見ることはできません。

    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    ziped_nums = zip(num1, num2)
    print(ziped_nums[0])
    
    Traceback (most recent call last):
      File "Main.py", line 4, in <module>
        print(ziped_nums[0])
    TypeError: 'zip' object is not subscriptable
    

  • これを list() を使って見える化します。

    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    ziped_nums = list(zip(num1, num2))
    print(ziped_nums)
    
    [(1, 4), (2, 5), (3, 6)]

  • 今度は値を見ることができます。

    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    ziped_nums = list(zip(num1, num2))
    print(ziped_nums[0])
    
    (1, 4)
    コピペして全部試してみよう!
  • さてここからが問題です。

  • タプルの中の値を書き換えたい時にはどうしたらよいでしょうか?

  • 書き換えを前提として nums1 と nums2 をリストにしたのに、zip() にしたら、書き換え不可能なタプルになって返ってきてしまいました。

  • zip してからも書き換えるつもりだったのに・・・という場面はわりとあります。


  • この解決方法として簡単にリストに直せる関数やメソッドが、実は用意されていないのです。

  • 無いものねだりしても始まらないので、次の方法で完全リスト化します。

    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    
    ziped_nums = []
    for z in zip(num1, num2):
        ziped_nums.append([*z])
    print(ziped_nums)
    
    [[1, 4], [2, 5], [3, 6]]
    実際に見てみてください!

    内包表記というものを使って一息で書くとこうなります。

    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    
    ziped_nums = [[*z] for z in zip(num1, num2)]
    print(ziped_nums)
    
    [[1, 4], [2, 5], [3, 6]]
    試しに内包表記で書いてみよう!

    これで要素や値を自由にいじくりまわすことが可能になります。


  • 煩わしい作業ですね。😅

  • ちなみに先ほどの見える化したプログラム、

    num1 = [1, 2, 3]
    num2 = [4, 5, 6]
    ziped_nums = list(zip(num1, num2))
    print(ziped_nums)
    
    [(1, 4), (2, 5), (3, 6)]

    これは外側がリストなので、要素としてタプルまるごとならばいろいろと操作することはできます。


  • 値の変更

    nums = [(1, 4), (2, 5), (3, 6)]
    nums[0] = (7, 8)
    print(nums)
    
    [(7, 8), (2, 5), (3, 6)]

  • 要素の追加

    nums = [(1, 4), (2, 5), (3, 6)]
    nums.append((7, 8))
    print(nums)
    
    [(1, 4), (2, 5), (3, 6), (7, 8)]

  • 要素の削除

    nums = [(1, 4), (2, 5), (3, 6)]
    del nums[0]
    print(nums)
    
    [(2, 5), (3, 6)]

  • 値交換 (スワップ)

    nums = [(1, 4), (2, 5), (3, 6)]
    nums[0], nums[1] = nums[1], nums[0]
    print(nums)
    
    [(2, 5), (1, 4), (3, 6)]


  • もういいかな?😅

  • 要するにリストの中のタプルは「リストの要素」なので、リストの操作ができるわけです。

辞書のキーとしてタプルを使う

辞書のキーとしてタプルを使う

  • 辞書のキーは、値の変更が不可能な型(不変の型)でなければなりません。

  • タプルも不変の型(イミュータブル)の1つです。

  • なので、リストはダメでもタプルにすれば使えるようになります。

  • もう一度「Fizz Buzz」のプログラムを書いてみます。

    fizzbuzz = {
        (True, True): 'アホイヌ',
        (True, False): 'アホ',
        (False, True): 'イヌ'
    }
    
    for i in range(1, 101):
        aho = (i % 3 == 0)  # 3 の倍数で True
        inu = (i % 5 == 0)  # 5 の倍数で True
        fizzbuzz[(False, False)] = i
        
        print(fizzbuzz[(aho, inu)])
    
    (結果は👇👇👇にて)
    右上の Open in New Window を押して試してください!
  • 今回は文を使った条件分岐ではなく、辞書を使った書き方をしました。

  • この書き方にすると判定が辞書の中のキーによって行なわれる上に、順不同にもなります。

  • もうアホイヌに逃げられる心配もなくなります。

  • 注目すべきは、辞書のキーです。

  • ここにタプルが使われています。

  • タプルの部分をリストに変えて動かしてみます。

    fizzbuzz = {[True, True]: 'アホイヌ',
        [True, False]: 'アホ',
        [False, True]: 'イヌ'
    }
    
    for i in range(1, 101):
        aho = (i % 3 == 0)  # 3 の倍数で True
        inu = (i % 5 == 0)  # 5 の倍数で True
        fizzbuzz[[False, False]] = i
        
        print(fizzbuzz[[aho, inu]])
    

    ※ エラー表示をわかりやすくするために一行目と二行目を繋げました。

    Traceback (most recent call last):
      File "Main.py", line 1, in <module>
        fizzbuzz = {[True, True]: 'アホイヌ',
    TypeError: unhashable type: 'list'
    
  • エラーメッセージから説明をするのは今はまだ難しいのですが、要するに「キーにリスト型は使えません」ということです。

  • 「アンハッシャブル・タイプ」→「ハッシュに使えない(一意ではない)型」→「不変の型ではない」→「キーに使う型として不適切」といった感じでしょうか。

  • 「じゃあ具体的にどの型なら使えるの?」の説明をこの次の Chatpter.3 でします。

Chatpter.3 - 可変(mutable)と不変(immutable)

可変(mutable)と不変(immutable)

  • もうなんとなく大体の意味はわかってきていると思われます。😅

  • 可変・・・値が変更できる
    不変・・・値が変更できない

  • ここで言うとは、「タプル」そのもののことです。

  • タプルは、そのものが不変なので、その中の要素を操作することもできません。

  • 絶対に開かない箱の中身をどうすることもできないのと同じです。(透明の箱なので中身は見える)

  • 可変のことを「ミュータブル (mutable)」、
    不変のことを「イミュータブル (immutable)」と言います。

  • 実は可変と不変はコピーのところですでに触れています。

  • 変数2 = 変数1

    このやり方を「コピー(copy)」または「値のコピー」と言います。(三度目)

  • 変数のまま 変数2変数1 を代入する(コピーする)ことが、

    出来る! 出来ない!
    str list
    int dict
    tuple set

    ※ まだ学んでいない型は細字になっていますって残りあと1つ!

  • この「出来る!」がすべて「不変 (イミュータブル)」となっているのです。

  • 出来る!」ほうは、辞書のキーとして使えます。

  • 「え・・・strint は書き換えられるじゃん?」
    → 書き換えられません。上書きして値を更新してるだけです。

  • 文字列は一部を直接書き換えることはできませんでしたよね?

    name = '天使のぼる'
    name[3] = 'え'  # 'ぼ' を 'え' に書き換える
    print(name)
    
    Traceback (most recent call last):
      File "Main.py", line 2, in <module>
        name[3] = 'え'  # 'ぼ' を 'え' に書き換える
    TypeError: 'str' object does not support item assignment
    

    str はしっかり 不変 (イミュータブル) となっています。

  • int のほうも数値の一部を書き換え・・・一部を書き換え・・・数値の一部を書き換える!?なにそれ意味わからん。改竄かいざんか!?

  • int も値を更新する以外できないですね。

  • なので int もしっかり 不変 (イミュータブル) です。

Chatpter.4 - tuple()とその他機能

tuple()

  • tuple()list() と同じ使い方です。

  • リストがタプルになっただけです。

  • 意識してタプルに変換したい時にはこの tuple() を使って変換します。

  • 他に特筆すべき点はありません。

  • 今はただ、辞書のキーに使いたい時にリストからタプルに変換する為に使うくらいでしょう。

  • なので、この場での説明はこれにて終了!

タプルで使えるメソッド

  • 主に使えるのは .index().count() の2つだけです。

  • 使い方はリストと全く同じです。

タプルで使える関数

  • 関数は引数がタプルの場合でも、引数がリストの場合と同じように処理できるよう関数の中で巧いことやってくれているので、リストで使える関数はタプルでも使えます。

  • たとえ引数の型が何であろうと、戻り値は決まった型で返ってきます。

  • 例えば sorted() は戻り値がリストで返ってきますし、sum() は戻り値が int で返ってきます。

  • 使い方もリストと全く同じです。

in と not in

  • innot in も、リストとまったく同じ使い方です。

  • タプルならではの制限とかもありません。

  • innot in も、値があるかどうかを調べるだけの機能なので可変不変は不問です。