Python の「名前付きタプル」とは何ですか?
-
24-10-2019 - |
質問
を読む Python 3.1 での変更点, 、何かを見つけました...予想外:
sys.version_info タプルは、 名前付きタプル:
名前付きタプルについてはこれまで聞いたことがなかったので、要素は番号 (タプルやリストなど) またはキー (辞書など) でインデックス付けできると思っていました。両方の方法でインデックスが作成できるとは思いもしませんでした。
したがって、私の質問は次のとおりです。
- 名前付きタプルとは何ですか?
- それらの使い方は?
- 通常のタプルの代わりに名前付きタプルを使用する必要があるのはなぜですか?
- 名前付きタプルの代わりに通常のタプルを使用する必要があるのはなぜですか?
- 何らかの種類の「名前付きリスト」(名前付きタプルの可変バージョン)はありますか?
解決
名前のタプルは、基本的に作成が簡単な軽量オブジェクトタイプです。名前付きのTupleインスタンスは、オブジェクトのような変数の控除または標準のタプル構文を使用して参照できます。同様に使用できます struct
または、それらが不変であることを除いて、他の一般的なレコードタイプ。それらはPython 2.6とPython 3.0に追加されましたが、 Python 2.4での実装のレシピ.
たとえば、ポイントをタプルとして表すのが一般的です (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
したがって、 オブジェクト表記があなたのコードをよりPythonicでより簡単に読みやすくすると思われるどこでも、タプルの代わりに名前付きタプルを使用する必要があります. 。私は個人的にそれらを使用して、特に関数のパラメーターとしてそれらを渡すときに、非常に単純な値タイプを表すように始めました。タプルパッキングのコンテキストを見ることなく、関数をより読みやすくします。
さらに、 通常の交換もできます 不変 関数がないクラス, 、彼らとのフィールドのみ。名前のタプルタイプを基本クラスとして使用することもできます。
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
値を変更できるようにしたい場合は、別のタイプが必要です。便利なレシピがあります 可変記録型 これにより、新しい値を属性に設定できます。
>>> 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
ただし、新しいフィールドを追加できる「名前付きリスト」の形態を知りません。この状況では、辞書を使用するだけかもしれません。名前付きタプルは、使用して辞書に変換できます pt1._asdict()
戻ります {'x': 1.0, 'y': 5.0}
すべての通常の辞書関数で動作することができます。
すでに述べたように、あなたはすべきです ドキュメントを確認してください これらの例が構築された詳細については。
他のヒント
namedtuple aです 工場機能 タプルクラスを作るため。そのクラスでは、名前で呼ばれるタプルを作成できます。
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)
タプルという名前は何ですか?
名前のタプルはタプルです。
タプルができるすべてを行います。
しかし、それは単なるタプル以上のものです。
これは、指定されたフィールドと固定長を備えた仕様に合わせてプログラム的に作成されたタプルの特定のサブクラスです。
これは、たとえば、タプルのサブクラスを作成し、固定長(この場合は3)である以外に、壊れずにタプルが使用される至る所で使用できます。これはリスコフの代替性として知られています:
>>> 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']
より深い説明
名前付きのタプルを理解するには、まずタプルが何であるかを知る必要があります。タプルは本質的に不変です(メモリ内の状態で変更することはできません)リストです。
通常のタプルを使用する方法は次のとおりです。
>>> student_tuple = 'Lisa', 'Simpson', 'A'
>>> student_tuple
('Lisa', 'Simpson', 'A')
>>> student_tuple[0]
'Lisa'
>>> student_tuple[1]
'Simpson'
>>> student_tuple[2]
'A'
繰り返し可能なアンパックでタプルを拡張できます。
>>> first, last, grade = student_tuple
>>> first
'Lisa'
>>> last
'Simpson'
>>> grade
'A'
名前付きのタプルは、単なるインデックスの代わりに名前で要素にアクセスできるようにするタプルです!
あなたはこのような名前のあるものを作ります:
>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['first', 'last', 'grade'])
また、スペースで区切られた名前を持つ単一の文字列を使用することもできます。
>>> Student = namedtuple('Student', 'first last grade')
それらの使用方法は?
Tuppleができるすべてのことを行うことができます(上記を参照)だけでなく、次のことを行うこともできます。
>>> 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
基本的に、簡単な速記で作成できるクラスです。それらをクラスのように扱います。ピクルスや他のユーザーがそれらを見つけることができるように、モジュールレベルでそれらを定義します。
グローバルモジュールレベルの作業例:
>>> 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
通常のタプルの代わりに名前のタプルを使用する必要があるのはなぜですか?
コードを改善するときにそれらを使用して、タプル要素のセマンティクスをコードで表現します。それ以外の場合は、不変のデータ属性と機能がないオブジェクトを使用する場合は、オブジェクトの代わりにそれらを使用できます。あなたもすることができます たとえば、機能を追加するためにサブクラス化します:
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)
名前付きタプルの代わりに通常のタプルを使用する必要があるのはなぜですか?
おそらく、名前のタプルの使用からタプルに切り替えることはおそらく回帰でしょう。先行設計の決定は、関与する追加コードからのコストがタプルを使用したときに読みやすさを改善する価値があるかどうかを中心にしています。
名前のタプルとタプルによって使用される追加のメモリはありません。
「名前付きリスト」(名前付きタプルの可変バージョン)はありますか?
静的なサイズのリストのすべての機能を実装するスロット付きオブジェクトまたは名前のタプルのように機能するサブクラス化リストのいずれかを探しています(そして、何らかの形でリストのサイズが変更されるのをブロックします)。
現在、拡張されている、そしておそらくリスコフの代替可能な例:最初の例:
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).__name__ + 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
AndameTuppleは優れた機能であり、データに最適なコンテナです。データを「保存」する必要がある場合、次のようなタプルや辞書を使用します。
user = dict(name="John", age=20)
また:
user = ("John", 20)
辞書は、Tuppleよりも可変で遅いため、辞書アプローチは圧倒的です。一方、タプルは不変で軽量ですが、データフィールドの多くのエントリの読みやすさがありません。
NamedTupplesは、2つのアプローチの完璧な妥協点であり、優れた読みやすさ、軽量性、不変性を持っています(さらに、ポリ型です!)。
名前付きタプルは、このようなバージョンをチェックするコードとの後方互換性を可能にします
>>> sys.version_info[0:2]
(3, 1)
この構文を使用することにより、将来のコードをより明示的にすることを許可しながら
>>> sys.version_info.major
3
>>> sys.version_info.minor
1
namedtuple
コードをクリーンアップして読みやすくする最も簡単な方法の1つです。それはタプルで何が起こっているのか自己ドキュメントです。 NamedTupplesインスタンスは、インスタンスごとの辞書を持たないのと同じように、通常のタプルと同じくらいメモリ効率が高く、辞書よりも速くなります。
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"
タプルの各要素に名前を付けることなく、次のように読みます。
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と呼ぶことができます。理解しやすいです。そして、それはきれいに見えます。
dictionaryを作成するよりも、dictionaryのインスタンスを作成する方が簡単です。
# 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を使用できますか
- 先ほど述べたように、AngiandTupleはタプルを理解しやすくします。したがって、タプル内のアイテムを参照する必要がある場合は、名前を付けたものとして作成することは理にかなっています。
- 辞書よりも軽量であることに加えて、namedTupleは辞書とは異なり、注文も保持します。
- 上記の例のように、辞書よりもnamedtupleのインスタンスを作成する方が簡単です。名前のタプルのアイテムを参照すると、辞書よりもきれいに見えます。
p.hue
それよりもp['hue']
.
構文
collections.namedtuple(typename, field_names[, verbose=False][, rename=False])
- namedtupleはコレクションライブラリにあります。
- TypeName:これは新しいタプルサブクラスの名前です。
- field_names:各フィールドの名前のシーケンス。リストのようにシーケンスにすることができます
['x', 'y', 'z']
または文字列x y z
(コンマなし、ただの白人)またはx, y, z
. - 名前を変更:名前がisの場合
True
, 、無効なフィールド名は自動的に位置名に置き換えられます。例えば、['abc', 'def', 'ghi','abc']
に変換されます['abc', '_1', 'ghi', '_3']
, 、キーワードを排除します'def'
(それは機能を定義するための予約された言葉であるため)および重複したフィールド名'abc'
. - 冗長:冗長の場合
True
, 、クラスの定義は、構築される直前に印刷されます。
あなたがそうするなら、あなたは引き続き彼らの位置で名前を付けたタプルにアクセスできます。 p[1] == p.saturation
. 。それはまだ通常のタプルのように解き放たれます。
方法
全ての 通常のタプル方法 サポートされています。例:min()、max()、len()、in、in、in、in、concatenation(+)、index、sliceなど、namedtupleにはいくつかの追加のものがあります。注:これらはすべてアンダースコアから始まります。 _replace
, _make
, _asdict
.
_replace
指定されたタプルの新しいインスタンスを、指定されたフィールドを新しい値に置き換えます。
構文
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)
知らせ: :フィールド名は引用符ではありません。ここではキーワードです。覚えて: :タプルは不変です - たとえ彼らが名前が付けられていても、 _replace
方法。 _replace
aを生成します new
実例;オリジナルを変更したり、古い値を置き換えたりしません。もちろん、新しい結果を変数に保存できます。 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
最後のものはどうなりましたか?括弧内のアイテムは反復可能である必要があります。したがって、括弧内のリストまたはタプルは機能しますが、反復可能なものとして囲まれていない値のシーケンスはエラーを返します。
_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
名前付きタプルとは何ですか?
名前が示すように、namedtuple は名前を持つタプルです。標準タプルではインデックスを使用して要素にアクセスしますが、namedtuple ではユーザーが要素の名前を定義できます。これは、特に csv (カンマ区切り値) ファイルを処理したり、インデックスを使用するとコードが煩雑になる (あまり Python 的ではない) 複雑で大規模なデータセットを操作する場合に非常に便利です。
使い方は?
>>>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を使用する別の方法(新しい方法)は、タイピングパッケージから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
AndameTupleクラスを継承し、新しいクラスの変数名を定義します。テストはクラスの名前です。
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)
これを試して:
collections.namedtuple()
基本的、 namedtuples
簡単に作成できる軽量オブジェクトタイプです。彼らはタプルを簡単なタスクのために便利なコンテナに変えます。と namedtuples
, 、タプルのメンバーにアクセスするために整数インデックスを使用する必要はありません。
例:
コード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
他の誰もがすでにそれに答えていますが、私はまだ他に追加するものがあると思います。
namedtupleは、クラスを定義するためのショートカットと直感的に見なされる可能性があります。
aを定義するための面倒で従来の方法を参照してください class
.
class Duck:
def __init__(self, color, weight):
self.color = color
self.weight = weight
red_duck = Duck('red', '10')
In [50]: red_duck
Out[50]: <__main__.Duck at 0x1068e4e10>
In [51]: red_duck.color
Out[51]: 'red'
はどうかと言うと namedtuple
from collections import namedtuple
Duck = namedtuple('Duck', ['color', 'weight'])
red_duck = Duck('red', '10')
In [54]: red_duck
Out[54]: Duck(color='red', weight='10')
In [55]: red_duck.color
Out[55]: 'red'