Python PR

【Python】名前からも要素を取得できる名前付きタプルの使い方を解説

記事内に商品プロモーションを含む場合があります

この記事では、Pythonの名前付きタプルの定義の方法を使い方を解説します。

名前付きタプルは、名前からもインデックスからも要素にアクセスできるタプルです。通常のタプルが利用される場所ならどこでも利用できます。

それでは、名前付きタプルの使い方を見ていきましょう!

名前付きタプルを使う

名前付きタプルを定義するには collectionsモジュール の namedtuple()関数 を使います。

namedtuple()関数 は、指定したフィールド名から要素にアクセスできる tuple の新しいサブクラスを生成することができます。

import collections

collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

namedtuple()関数に定義されている引数は以下のとおりです。

typename 新しく生成する名前付きタプルのクラス名。
field_names 属性名。文字列のシーケンス、またはスラッシュ(/)、カンマ(,)、空白で属性名を区切った文字列を指定します。
rename Trueならfiled_namesに不適切な名前があった場合に自動的に位置を示す名前に置き換えられます。
defaults デフォルト値を指定できる。
module 名前付きタプルの __module__ 属性は、指定された値に設定されます。

サンプル

試しに名前付きタプルを生成し、いろんな方法で出力してみます。

from collections import namedtuple

# Member という名前で名前付きタプルのクラスを新しく生成
Member = namedtuple('Member', ('id', 'name', 'age'))

# インスタンス化
m = Member(1, '山田太郎', 20)

# インスタンスを出力
print(m)

# 属性名で出力
print(m.id)
print(m.name)
print(m.age)

# for文で出力
for var in m:
    print(var)

# インデックスで出力
print(m[0])
print(m[1])
print(m[2])

実行結果

# インスタンスを出力
Member(id=1, name='山田太郎', age=20)

# 属性名で出力
1
山田太郎
20

# for文で出力
1
山田太郎
20

# インデックスで出力
1
山田太郎
20

名前付きタプルを使うことで、通常のタプルの機能に加えて属性名から要素にアクセスすることができました。

あくまでタプルなので値を変更することはできない。

from collections import namedtuple

# Member という名前で名前付きタプルのクラスを新しく生成
Member = namedtuple('Member', ('id', 'name', 'age'))

# インスタンス化
m = Member(1, '山田太郎', 20)

# 値を変更(エラー)
m.id = 10

実行結果

Traceback (most recent call last):
  File "/Users/user/Desktop/Python/main.py", line 10, in 
    m.id = 10
AttributeError: can't set attribute

不適切な属性名を自動で書き換える

rename引数をTrueに指定することで属性名が不適切な場合に自動的に位置を示す名前に置き換えられます。予約語や重複した名前が不適切な属性名として扱われます。

from collections import namedtuple

Member = namedtuple('Member', ('if', 'def', 'name', 'name'), rename=True)
print(Member(1, 2, 3, 4))

実行結果

Member(_0=1, _1=2, name=3, _3=4)

デフォルト値を指定する

defaults引数にはデフォルト値のイテラブルを指定できます。デフォルト値は右の変数から適用されます。

from collections import namedtuple

# デフォルト値を3つ指定
Member = namedtuple('Member', ('id', 'name', 'age'), defaults=[-1, '名無しの権兵衛', -1])
m = Member()
print(m)

# デフォルト値を2つ指定
Member = namedtuple('Member', ('id', 'name', 'age'), defaults=['名無しの権兵衛', -1])
m = Member(1)
print(m)

実行結果

Member(id=-1, name='名無しの権兵衛', age=-1)
Member(id=1, name='名無しの権兵衛', age=-1)

追加されたメソッドと属性

名前付きタプルには、tupleから継承したメソッドの他に以下のようなメソッドや属性が追加されています。

インスタンスを生成する[_make(iterable)]

namedtuple()関数で新しく生成したクラスのインスタンスを生成するクラスメソッド。

from collections import namedtuple

Member = namedtuple('Member', ('id', 'name', 'age'))

m = Member._make((1, '山田太郎', 20))
print(m)

実行結果

Member(id=1, name='山田太郎', age=20)

map()関数なんかと組み合わせて使うと便利。

from collections import namedtuple

# Member という名前で名前付きタプルのクラスを新しく生成
Member = namedtuple('Member', ('id', 'name', 'age'))

# メンバーのデータ
members = [[1, '山田太郎', 20], [2, '田中花子', 12], [3, '名無しの権兵衛', 37]]

# for文で回す際に名前付きタプルを使う
for member in map(Member._make, members):
    print(member.id, member.name, member.age)

実行結果

1 山田太郎 20
2 田中花子 12
3 名無しの権兵衛 37

属性名と値を辞書で取得[_asdict()]

属性名と対応した値を辞書として返します。

from collections import namedtuple

Member = namedtuple('Member', ('id', 'name', 'age'))

m = Member(1, '山田太郎', 20)
print(m._asdict())

実行結果

{'id': 1, 'name': '山田太郎', 'age': 20}

要素を書き換えた名前付きタプルを新しく生成[_replace(**kwargs)]

指定した要素の値を書き換えた名前付きタプルを返す。

from collections import namedtuple

Member = namedtuple('Member', ('id', 'name', 'age'))

m = Member(1, '山田太郎', 20)
print(m)

r_m = m._replace(name='田中花子')
print(r_m)

実行結果

Member(id=1, name='山田太郎', age=20)
Member(id=1, name='田中花子', age=20)

フィールド名[_fields]

フィールド名を格納したタプル。

from collections import namedtuple

Member = namedtuple('Member', ('id', 'name', 'age'))

m = Member(1, '山田太郎', 20)
print(m._fields)

実行結果

('id', 'name', 'age')

デフォルト値[_field_defaults]

フィールド名に対応したデフォルト値を格納した辞書。

from collections import namedtuple

Member = namedtuple('Member', ('id', 'name', 'age'), defaults=[-1, '名無しの権兵衛', -1])
print(Member._field_defaults)

実行結果

{'id': -1, 'name': '名無しの権兵衛', 'age': -1}

まとめ

この記事では、名前付きタプルの使い方を解説しました。

collectionsモジュールのnamedtuple()関数を使うことで簡単に名前付きタプルを生成することができました。

名前付きタプルは、属性名から要素を取得することができるので構造体のような使い方ができます。イメージとしては更新できない構造体のような感じです。

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ