web-dev-qa-db-ja.com

Pythonの「名前付きタプル」とは何ですか?

Python 3.1 での変更点を読むと、何かが見つかりました...予期しない:

Sys.version_info Tupleは、 Tuple という名前になりました。

名前付きタプルについてはこれまで一度も聞いたことがありませんでしたが、要素は数字で(タプルやリストのように)、またはキーで索引付け(dictsのように)できると思いました。それらが両方向で索引付けされるとは思わなかった。

したがって、私の質問は次のとおりです。

  • タプルとは何ですか?
  • 使い方は?
  • 通常のタプルの代わりに名前付きタプルを使用すべきなのはなぜですか?
  • なぜ、いつ、私は名前付きタプルの代わりに通常のタプルを使用すべきですか?
  • 「名前付きリスト」(名前付きTupleの可変バージョン)はありますか?
784

名前付きタプルは、基本的に作成が簡単な軽量のオブジェクト型です。名前付きタプルインスタンスは、オブジェクトのような変数の逆参照または標準のタプル構文を使用して参照できます。これらは、不変であることを除き、structまたは他の一般的なレコードタイプと同様に使用できます。これらはPython 2.6およびPython 3.0で追加されましたが、 Python 2.4での実装のレシピ があります。

たとえば、ポイントをTuple (x, y)として表すのが一般的です。これにより、次のようなコードになります。

pt1 = (1.0, 5.0)
pt2 = (2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)

名前付きタプルを使用すると、より読みやすくなります。

from collections import namedtuple
Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)

ただし、名前付きタプルは通常のタプルと下位互換性があるため、次のように機能します。

Point = namedtuple('Point', 'x y')
pt1 = Point(1.0, 5.0)
pt2 = Point(2.5, 1.5)

from math import sqrt
# use index referencing
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)
 # use Tuple unpacking
x1, y1 = pt1

したがって、オブジェクト表記法によりコードがよりPython的で読みやすくなると思われる場合は、タプルの代わりに名前付きタプルを使用する必要があります。私は個人的に、特に関数にパラメーターとして渡すときに、非常に単純な値型を表すためにそれらを使用し始めました。 Tupleパッキングのコンテキストを見ることなく、関数をより読みやすくします。

さらに、関数を持たない通常のimmutableクラス、フィールドのみを置き換えることもできます。名前付きTuple型を基本クラスとして使用することもできます。

class Point(namedtuple('Point', 'x y')):
    [...]

ただし、タプルと同様に、名前付きタプルの属性は不変です。

>>> Point = namedtuple('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
AttributeError: can't set attribute

値を変更できるようにするには、別のタイプが必要です。 mutable recordtypes には便利なレシピがあり、属性に新しい値を設定できます。

>>> from rcdtype import *
>>> Point = recordtype('Point', 'x y')
>>> pt1 = Point(1.0, 5.0)
>>> pt1 = Point(1.0, 5.0)
>>> pt1.x = 2.0
>>> print(pt1[0])
    2.0

ただし、新しいフィールドを追加できる「名前付きリスト」の形式は知りません。この状況で辞書を使用したい場合があります。名前付きタプルは、{'x': 1.0, 'y': 5.0}を返すpt1._asdict()を使用して辞書に変換でき、通常のすべての辞書関数で操作できます。

すでに述べたように、これらの例が作成された詳細については、 ドキュメントを確認 する必要があります。

1074
fmark

namedtuple はTupleクラスを作るための ファクトリ関数 です。そのクラスを使えば、名前でも呼び出せるタプルを作ることができます。

import collections

#Create a namedtuple class with names "a" "b" "c"
Row = collections.namedtuple("Row", ["a", "b", "c"], verbose=False, rename=False)   

row = Row(a=1,b=2,c=3) #Make a namedtuple from the Row class we created

print row    #Prints: Row(a=1, b=2, c=3)
print row.a  #Prints: 1
print row[0] #Prints: 1

row = Row._make([2, 3, 4]) #Make a namedtuple from a list of values

print row   #Prints: Row(a=2, b=3, c=4)
89
The Demz

タプルとは何ですか?

名前付きタプルはタプルです。

それはタプルができるすべてのことをします。

しかしそれは単なるタプル以上のものです。

これはTupleの特定のサブクラスで、名前付きフィールドと固定長で、プログラム的にあなたの仕様に合わせて作成されています。

たとえば、これはTupleのサブクラスを作成し、固定長(この場合は3)であることを除けば、Tupleが使用されている場所ならどこでも使用できます。これはLiskovの代用性として知られています。

>>> from collections import namedtuple
>>> class_name = 'ANamedTuple'
>>> fields = 'foo bar baz'
>>> ANamedTuple = namedtuple(class_name, fields)

これによりインスタンス化されます。

>>> ant = ANamedTuple(1, 'bar', [])

それを調べてその属性を使うことができます。

>>> ant
ANamedTuple(foo=1, bar='bar', baz=[])
>>> ant.foo
1
>>> ant.bar
'bar'
>>> ant.baz.append('anything')
>>> ant.baz
['anything']

より深い説明

名前付きタプルを理解するには、最初にタプルとは何かを知る必要があります。 Tupleは本質的に不変の(メモリ内でその場で変更することはできません)リストです。

これが通常のTupleの使い方です。

>>> student_Tuple = 'Lisa', 'Simpson', 'A'
>>> student_Tuple
('Lisa', 'Simpson', 'A')
>>> student_Tuple[0]
'Lisa'
>>> student_Tuple[1]
'Simpson'
>>> student_Tuple[2]
'A'

繰り返し解凍してTupleを拡張できます。

>>> first, last, grade = student_Tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'

名前付きタプルは、要素をインデックスだけでなく名前でアクセスできるようにするタプルです。

あなたはこのような名前のついた組を作ります:

>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])

名前をスペースで区切った単一の文字列を使用することもできます。これは、APIを少し読みやすくするためのものです。

>>> Student = namedtuple('Student', 'first last grade')

使い方は?

あなたはタプルができることすべてをやることができます(上を見てください)そして、以下をすること:

>>> named_student_Tuple = Student('Lisa', 'Simpson', 'A')
>>> named_student_Tuple.first
'Lisa'
>>> named_student_Tuple.last
'Simpson'
>>> named_student_Tuple.grade
'A'
>>> named_student_Tuple._asdict()
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> vars(named_student_Tuple)
OrderedDict([('first', 'Lisa'), ('last', 'Simpson'), ('grade', 'A')])
>>> new_named_student_Tuple = named_student_Tuple._replace(first='Bart', grade='C')
>>> new_named_student_Tuple
Student(first='Bart', last='Simpson', grade='C')

コメンターは尋ねました:

大規模なスクリプトやプログラムでは、通常、名前付きタプルをどこで定義しますか。

namedtupleで作成した型は基本的に簡単な速記で作成できるクラスです。彼らをクラスのように扱いなさい。 pickleや他のユーザがそれらを見つけることができるように、それらをモジュールレベルで定義してください。

グローバルモジュールレベルでの実用的な例:

>>> from collections import namedtuple
>>> NT = namedtuple('NT', 'foo bar')
>>> nt = NT('foo', 'bar')
>>> import pickle
>>> pickle.loads(pickle.dumps(nt))
NT(foo='foo', bar='bar')

そしてこれは定義を検索できなかったことを示しています。

>>> def foo():
...     LocalNT = namedtuple('LocalNT', 'foo bar')
...     return LocalNT('foo', 'bar')
... 
>>> pickle.loads(pickle.dumps(foo()))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <class '__main__.LocalNT'>: attribute lookup LocalNT on __main__ failed

通常のタプルの代わりに名前付きタプルを使用すべきなのはなぜですか?

コード内でTuple要素のセマンティクスを表現するようにコードを改善するときに使用してください。変更しないデータ属性を持ち、機能を持たないオブジェクトを使用する場合は、オブジェクトの代わりにそれらを使用できます。 サブクラス化して機能を追加することもできます。例えば

class Point(namedtuple('Point', 'x y')):
    """adding functionality to a named Tuple"""
        __slots__ = ()
        @property
        def hypot(self):
            return (self.x ** 2 + self.y ** 2) ** 0.5
        def __str__(self):
            return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

なぜ、いつ、私は名前付きタプルの代わりに通常のタプルを使用すべきですか?

名前付きタプルの使用からタプルへの切り替えは、おそらく回帰です。追加のコードによるコストが、Tupleを使用した場合の読みやすさの向上に見合うだけの価値があるかどうかを中心に、設計の最前線で決定します。

名前付きタプルとタプルで使用される追加のメモリはありません。

「名前付きリスト」(名前付きTupleの可変バージョン)はありますか?

静的サイズのリストのすべての機能を実装するスロット付きオブジェクト、または名前付きTupleのように機能するサブクラス化リストを探しています(そしてリストのサイズ変更をブロックしています)。

最初の例は今拡張された、そしておそらくLiskovでも代用可能です。

from collections import Sequence

class MutableTuple(Sequence): 
    """Abstract Base Class for objects that work like mutable
    namedtuples. Subclass and define your named fields with 
    __slots__ and away you go.
    """
    __slots__ = ()
    def __init__(self, *args):
        for slot, arg in Zip(self.__slots__, args):
            setattr(self, slot, arg)
    def __repr__(self):
        return type(self).__+ repr(Tuple(self))
    # more direct __iter__ than Sequence's
    def __iter__(self): 
        for name in self.__slots__:
            yield getattr(self, name)
    # Sequence requires __getitem__ & __len__:
    def __getitem__(self, index):
        return getattr(self, self.__slots__[index])
    def __len__(self):
        return len(self.__slots__)

そして使用するには、__slots__をサブクラス化して定義するだけです。

class Student(MutableTuple):
    __slots__ = 'first', 'last', 'grade' # customize 


>>> student = Student('Lisa', 'Simpson', 'A')
>>> student
Student('Lisa', 'Simpson', 'A')
>>> first, last, grade = student
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
>>> student[0]
'Lisa'
>>> student[2]
'A'
>>> len(student)
3
>>> 'Lisa' in student
True
>>> 'Bart' in student
False
>>> student.first = 'Bart'
>>> for i in student: print(i)
... 
Bart
Simpson
A
64
Aaron Hall

namedtuplesは素晴らしい機能です、彼らはデータのための完全なコンテナです。データを「保存」する必要がある場合は、次のようにタプルまたは辞書を使用します。

user = dict(name="John", age=20)

または

user = ("John", 20)

辞書はミュータブルでタプルより遅いので、辞書によるアプローチは圧倒的です。一方、タプルは不変かつ軽量ですが、データフィールド内の多数のエントリに対する読みやすさに欠けます。

namedtuplesは、2つのアプローチ、優れた読みやすさ、軽量さ、および不変性を兼ね備えた完璧な妥協策です(さらに、それらは多態性です)。

39
pygabriel

名前付きタプルは、このようなバージョンをチェックするコードとの下位互換性を可能にします。

>>> sys.version_info[0:2]
(3, 1)

この構文を使用して将来のコードをより明確にすることができます。

>>> sys.version_info.major
3
>>> sys.version_info.minor
1
28
John La Rooy

namedtuple

コードを整理して読みやすくするための最も簡単な方法の1つです。タプルで起こっていることを自己文書化します。 Namedtuplesインスタンスは、インスタンスごとの辞書がないため、通常のタプルと同じくらいメモリ効率がよく、辞書よりも高速になります。

from collections import namedtuple

Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])

 p = Color(170, 0.1, 0.6)
 if p.saturation >= 0.5:
     print "Whew, that is bright!"
 if p.luminosity >= 0.5:
     print "Wow, that is light"

Tupleの各要素に名前を付けないと、次のようになります。

p = (170, 0.1, 0.6)
if p[1] >= 0.5:
    print "Whew, that is bright!"
if p[2]>= 0.5:
   print "Wow, that is light"

最初の例で何が起こっているのかを理解するのはもっと難しいです。名前付きタプルを使用すると、各フィールドに名前が付きます。そしてあなたは位置やインデックスではなく名前でそれにアクセスします。 p[1]の代わりに、p.saturationと呼ぶことができます。理解しやすいです。そしてそれはきれいに見えます。

Namedtupleのインスタンスを作成する方が辞書を作成するよりも簡単です。

# dictionary
>>>p = dict(hue = 170, saturation = 0.1, luminosity = 0.6)
>>>p['hue']
170

#nametuple
>>>from collections import namedtuple
>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)
>>>p.hue
170

Namedtupleを使用する場合

  1. ちょうど述べたように、namedtupleはタプルを理解することをずっと容易にします。そのため、Tupleの項目を参照する必要がある場合は、それらをnamedtuplesとして作成しても意味がありません。
  2. 辞書より軽量であることに加えて、namedtupleは辞書とは異なり順序を保持します。
  3. 上記の例のように、dictionaryよりnamedtupleのインスタンスを作成する方が簡単です。そして、Tupleという名前の項目を参照すると、辞書よりもきれいに見えます。 p.hueではなくp['hue']

構文

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
  • namedtupleはコレクションライブラリにあります。
  • typename:これは新しいTupleサブクラスの名前です。
  • field_names:各フィールドの名前のシーケンス。これは、リスト['x', 'y', 'z']、文字列x y z(コンマなし、空白のみ)、またはx, y, zのようなシーケンスにすることができます。
  • 名前の変更:名前の変更がTrueの場合、無効なフィールド名は自動的に定位置名に置き換えられます。たとえば、['abc', 'def', 'ghi','abc']['abc', '_1', 'ghi', '_3']に変換され、キーワード'def'(これは関数を定義するための予約語です)と重複するフィールド名'abc'を削除します。
  • verbose:verboseがTrueの場合、クラス定義は構築される直前に表示されます。

必要に応じて、名前付きタプルにその位置からアクセスできます。 p[1] == p.saturation。それはまだ通常のタプルのように開梱します。

方法

通常のTupleメソッド がすべてサポートされています。例:min()、max()、len()、in、not in、連結(+)、インデックス、スライスなど。そして、namedtupleにはいくつか追加のものがあります。注:これらはすべてアンダースコアで始まります。 _replace_make_asdict

_replace指定されたフィールドを新しい値で置き換えた、名前付きTupleの新しいインスタンスを返します。

構文

somenamedtuple._replace(kwargs)

>>>from collections import namedtuple

>>>Color = namedtuple('Color', ['hue', 'saturation', 'luminosity'])
>>>p = Color(170, 0.1, 0.6)

>>>p._replace(hue=87)
Color(87, 0.1, 0.6)

>>>p._replace(hue=87, saturation=0.2)
Color(87, 0.2, 0.6)

注意 :フィールド名は引用符で囲まないでください。それらはここのキーワードです。 覚えておいてください :タプルはtupleという名前で_replaceメソッドを持っていても不変です。 _replacenewインスタンスを生成します。元の値を変更したり古い値を置き換えたりすることはありません。もちろん、新しい結果を変数に保存することもできます。 p = p._replace(hue=169)

_make

既存のシーケンスから新しいインスタンスを作成するか、反復可能にします。

構文

somenamedtuple._make(iterable)

 >>>data = (170, 0.1, 0.6)
 >>>Color._make(data)
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make([170, 0.1, 0.6])  #the list is an iterable
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make((170, 0.1, 0.6))  #the Tuple is an iterable
Color(hue=170, saturation=0.1, luminosity=0.6)

>>>Color._make(170, 0.1, 0.6) 
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<string>", line 15, in _make
TypeError: 'float' object is not callable

最後のもので何が起こりましたか?括弧内の項目は反復可能であるべきです。そのため、かっこ内のリストまたはTupleは機能しますが、反復可能変数として囲むことなく値のシーケンスを実行するとエラーが返されます。

_asdict

フィールド名を対応する値にマッピングする新しい OrderedDict を返します。

構文

somenamedtuple._asdict()

 >>>p._asdict()
OrderedDict([('hue', 169), ('saturation', 0.1), ('luminosity', 0.6)])

参照 https://www.reddit.com/r/Python/comments/38ee9d/intro_to_namedtuple/

名前付きタプルに似ているが変更可能な名前付きリストもあります https://pypi.python.org/pypi/namedlist

9
Kevin Zhu

Tupleとは何ですか?

名前が示すように、namedtupleは名前を持つTupleです。標準のTupleでは、インデックスを使用して要素にアクセスしますが、namedtupleではユーザーは要素の名前を定義できます。これは特にcsv(コンマ区切り値)ファイルの処理や複雑で大きなデータセットの処理に非常に便利です。そこではコードがインデックスの使用で面倒になります(Pythonicではなく)。

使い方は?

>>>from collections import namedtuple
>>>saleRecord = namedtuple('saleRecord','shopId saleDate salesAmout totalCustomers')
>>>
>>>
>>>#Assign values to a named Tuple 
>>>shop11=saleRecord(11,'2015-01-01',2300,150) 
>>>shop12=saleRecord(shopId=22,saleDate="2015-01-01",saleAmout=1512,totalCustomers=125)

読み物

>>>#Reading as a namedtuple
>>>print("Shop Id =",shop12.shopId)
12
>>>print("Sale Date=",shop12.saleDate)
2015-01-01
>>>print("Sales Amount =",shop12.salesAmount)
1512
>>>print("Total Customers =",shop12.totalCustomers)
125

CSV処理における興味深いシナリオ

from csv import reader
from collections import namedtuple

saleRecord = namedtuple('saleRecord','shopId saleDate totalSales totalCustomers')
fileHandle = open("salesRecord.csv","r")
csvFieldsList=csv.reader(fileHandle)
for fieldsList in csvFieldsList:
    shopRec = saleRecord._make(fieldsList)
    overAllSales += shopRec.totalSales;

print("Total Sales of The Retail Chain =",overAllSales)

内部のPythonでは、Tupleという名前のコンテナをうまく利用できます。これはクラスの定義を作成するために使用でき、元のTupleのすべての機能を備えています。

名前付きTupleを使用すると、デフォルトのクラステンプレートに直接適用されて単純なクラスが生成されます。この方法では、読みやすさを向上させるために多くのコードを使用できます。

5
Marcus Thornton

これを試して:

collections.namedtuple()

基本的に、namedtuplesは簡単に作成できる軽量のオブジェクト型です。それらはタプルを簡単なタスクのための便利なコンテナに変えます。 namedtuplesを使えば、Tupleのメンバーにアクセスするために整数のインデックスを使う必要はありません。

例:

コード1

>>> from collections import namedtuple

>>> Point = namedtuple('Point','x,y')

>>> pt1 = Point(1,2)

>>> pt2 = Point(3,4)

>>> dot_product = ( pt1.x * pt2.x ) +( pt1.y * pt2.y )

>>> print dot_product
11

コード2

>>> from collections import namedtuple

>>> Car = namedtuple('Car','Price Mileage Colour Class')

>>> xyz = Car(Price = 100000, Mileage = 30, Colour = 'Cyan', Class = 'Y')

>>> print xyz

Car(Price=100000, Mileage=30, Colour='Cyan', Class='Y')
>>> print xyz.Class
Y
1
saarthak johari

名前付きTupleを使用するもう1つの方法(新しい方法)は、パッケージの入力からNamedTupleを使用することです。 namedtupleにヒントを入力する

それを使用する方法を見るためにこの記事の一番上の答えの例を使用しましょう。

(1)名前付きタプルを使用する前のコードは次のとおりです。

pt1 = (1.0, 5.0)
pt2 = (2.5, 1.5)

from math import sqrt
line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2)
print(line_length)

(2)今、名前付きタプルを使います

from typing import NamedTuple, Number

namedTupleクラスを継承し、新しいクラスに変数名を定義します。 testはクラスの名前です。

class test(NamedTuple):
x: Number
y: Number

クラスからインスタンスを作成し、それらに値を割り当てる

pt1 = test(1.0, 5.0)   # x is 1.0, and y is 5.0. The order matters
pt2 = test(2.5, 1.5)

インスタンスからの変数を使って計算する

line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2)
print(line_length)
0
Richard Liang