[Python] namedtuple

namedTuple

各要素に名前がついている tuple を作成できます。
C言語の構造体のように、いくつかの変数を1つのオブジェクトでまとめる目的で使うことができます。

C言語の構造体

struct Rect
{
    int x;
    int y;
    int width;
    int height;
}

普通の tuple も同じ目的で使えますが、各要素に添字でアクセスすることになるため、プログラムの可読性が落ちるという欠点があります。

以下は tuple で2次元空間上の2点を tuple で表し、ユークリッド距離を計算する例です。

>>> import math
>>> pt1 = (1.0, 4.0)
>>> pt2 = (7.0, 6.0)
>>> math.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
6.324555320336759

namedTuple を使うと以下のようになります。
こちらのほうが tuple の各要素に名前でアクセスできるため、コードがよりわかりやすくなったのではないでしょうか。

Point = namedtuple("Point", "x y")
>>> from collections import namedtuple
>>> import math
>>> Point = namedtuple("TEST", "x, y")
>>> pt1 = Point(x=1.0, y=4.0)
>>> pt2 = Point(x=7.0, y=6.0)
>>> math.sqrt((pt1.x - pt2.x) ** 2 + (pt1.y - pt2.y) ** 2)
6.324555320336759

namedTuple の作成

まず namedtuple(typename, field_names) でクラスの定義を作成します。
typename には tuple の名前を指定します。
field_names には tuple が持つ要素をスペース区切りの文字列、カンマ区切りの文字列、または文字列のリストで指定します。
以下はいずれも同じ namedtuple が作成できます。

# スペース区切りの文字
>>> Rect = namedtuple("Rect", "x y width height")
# カンマ区切りの文字列
>>> Rect = namedtuple("Rect", "x, y, width, height")
# 文字列のリスト
>>> Rect = namedtuple("Rect", ["x", "y", "width", "height"])

フィールド名には def、for などの予約語とアンダーバーで始まる名前以外ならなんでも構いません。

# 予約後はNG
>>> Rect = namedtuple("Rect", "for def")
ValueError: Type names and field names cannot be a keyword: 'for'
# アンダーバーで始まる名前もNG
>>> Rect = namedtuple("Rect", "_hoge")
alueError: Field names cannot start with an underscore: '_hoge'

インスタンスの生成

Rect(x, y, width, height) という関数を呼び出して作成します。
以下、Python の引数の渡し方3通り。

>>> Rect = namedtuple("Rect", "x y width height")
# 名前付き引数で初期化
>>> rect = Rect(x=0, y=0, width=100, height=200)
# 通常の渡し方で初期化
>>> rect = Rect(0, 0, 100, 200)
# ** 演算子
>>> args = {"x": 0, "y": 0, "width": 100, "height": 200}
>>> rect = Rect(**args)

_make(iterable) を使うと、リストなど iterable なオブジェクトで初期化できます。
namedTuple のフィールドの数と iterable の要素数は一致している必要があります。

# _make() で初期化
>>> rect = Rect._make([0, 0, 100, 200])

namedTuple の参照

通常の tuple と同じ使い方ができます。

>>> Rect = namedtuple("Rect", "x y width height")
>>> rect = Rect(x=0, y=0, width=100, height=200)
# 通常の tuple と同じように展開できる。
>>> x, y, width, height = rect
# 通常の tuple と同じように添字アクセスもできる。
>>> rect[3]
200

フィールド名によるアクセスもできます。

>>> Rect = namedtuple("Rect", "x y width height")
>>> rect = Rect(x=0, y=0, width=100, height=200)
>>> rect.width
100

作成済みの namedtuple のフィールドは変更できません。
代わりに指定したフィールドを新しい値で置き換えた namedtuple を返す _replace(kwargs) を使います。

>>> Rect = namedtuple("Rect", "x y width height")
>>> rect = Rect(x=0, y=0, width=100, height=200)
>>> rect
Rect(x=0, y=0, width=100, height=200)
# 代入はNG
>>> rect.x = 100
AttributeError: can't set attribute
# _replace() を使う
>>> rect = rect._replace(x=20, y=20)
>>> rect
Rect(x=20, y=20, width=100, height=200)

フィールド一覧の取得

>>> Rect = namedtuple("Rect", "x y width height")
>>> rect = Rect(x=0, y=0, width=100, height=200)
>>> rect._fields
('x', 'y', 'width', 'height')

コメントを残す

メールアドレスが公開されることはありません。