web-dev-qa-db-ja.com

なぜPythonはレコードタイプをサポートしないのですか?(つまり、変更可能なnamedtuple)

なぜPythonはレコードタイプをネイティブにサポートしないのですか?namedtupleの変更可能なバージョンを持つことの問題です。

namedtuple._replaceを使用できます。しかし、これらのレコードをコレクションに含める必要があり、namedtuple._replaceが別のインスタンスを作成するため、コレクションを変更する必要があります。

背景:TCP/IPを介してポーリングすることで属性を取得する必要があるデバイスがあります。つまり、その表現は可変オブジェクトです。

編集:ポーリングする必要があるデバイスのセットがあります。

編集:PyQtを使用して属性を表示するオブジェクトを反復処理する必要があります。 __getitem____iter__などの特別なメソッドを追加できることは知っていますが、もっと簡単な方法があるかどうか知りたいです。

編集:属性が固定されているタイプ(デバイスにあるのと同じ)を好みますが、可変です。

47
Salil

Python <3.3

こんな感じ?

_class Record(object):
    __slots__= "attribute1", "attribute2", "attribute3",

    def items(self):
        "dict style items"
        return [
            (field_name, getattr(self, field_name))
            for field_name in self.__slots__]

    def __iter__(self):
        "iterate over fields Tuple/list style"
        for field_name in self.__slots__:
            yield getattr(self, field_name)

    def __getitem__(self, index):
        "Tuple/list style getitem"
        return getattr(self, self.__slots__[index])

>>> r= Record()
>>> r.attribute1= "hello"
>>> r.attribute2= "there"
>>> r.attribute3= 3.14

>>> print r.items()
[('attribute1', 'hello'), ('attribute2', 'there'), ('attribute3', 3.1400000000000001)]
>>> print Tuple(r)
('hello', 'there', 3.1400000000000001)
_

提供されるメソッドは、可能なメソッドのサンプルにすぎないことに注意してください。

Python≥3.3アップデート

_types.SimpleNamespace_ を使用できます:

_>>> import types
>>> r= types.SimpleNamespace()
>>> r.attribute1= "hello"
>>> r.attribute2= "there"
>>> r.attribute3= 3.14
_

dir(r)は属性名を提供します(もちろんすべての.startswith("__")を除外します)。

48
tzot

通常の辞書を使用できない理由はありますか?特定の状況では、属性に特定の順序がないようです。

または、クラスインスタンス(Nice属性アクセス構文を使用)を使用することもできます。インスタンスごとに__slots__を作成しないようにする場合は、__dict__を使用できます。

また、 "records"のレシピ を見つけました。これは、変更可能な名前付きタプルとして記述されています。それらはクラスを使用して実装されます。

更新:

シナリオでは順序が重要であると言うので(そして、すべての属性を反復処理したいので)、OrderedDictが道のりのようです。これは、Python 2.7以降の標準のcollectionsモジュールの一部です。 Python <2.7のために、他にも 実装 インターネットの周りに浮かんでいます。

属性スタイルのアクセスを追加するには、次のようにサブクラス化できます。

from collections import OrderedDict

class MutableNamedTuple(OrderedDict):
    def __init__(self, *args, **kwargs):
        super(MutableNamedTuple, self).__init__(*args, **kwargs)
        self._initialized = True

    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        if hasattr(self, '_initialized'):
            super(MutableNamedTuple, self).__setitem__(name, value)
        else:
            super(MutableNamedTuple, self).__setattr__(name, value)

その後、次のことができます。

>>> t = MutableNamedTuple()
>>> t.foo = u'Crazy camels!'
>>> t.bar = u'Yay, attribute access'
>>> t.foo
u'Crazy camels!'
>>> t.values()
[u'Crazy camels!', u'Yay, attribute access']
18
Cameron

これは、次のように空のクラスとそのインスタンスを使用して実行できます。

>>> class a(): pass
... 
>>> ainstance = a()
>>> ainstance.b = 'We want Moshiach Now'
>>> ainstance.b
'We want Moshiach Now'
>>> 
10
Abbafei

Namedtupleに似ていますが、可変で、recordtypeと呼ばれるライブラリがあります。

パッケージホーム: http://pypi.python.org/pypi/recordtype

簡単な例:

from recordtype import recordtype

Person = recordtype('Person', 'first_name last_name phone_number')
person1 = Person('Trent', 'Steele', '637-3049')
person1.last_name = 'Terrence';

print person1
# Person(first_name=Trent, last_name=Terrence, phone_number=637-3049)

単純なデフォルト値の例:

Basis = recordtype('Basis', [('x', 1), ('y', 0)])

person1のフィールドを順番に繰り返します:

map(person1.__getattribute__, Person._fields)
9
Leif Bork

この回答は 別の1つ と重複しています。 collections.namedtuple- recordclass の代わりに変更可能なものがあります。

namedtupleと同じAPIとメモリフットプリントを持っています(実際には高速です)。割り当てをサポートします。例えば:

from recordclass import recordclass

Point = recordclass('Point', 'x y')

>>> p = Point(1, 2)
>>> p
Point(x=1, y=2)
>>> print(p.x, p.y)
1 2
>>> p.x += 2; p.y += 3; print(p)
Point(x=3, y=5)

より完全な があります(パフォーマンスの比較も含まれます)。

4
intellimath

密接に関連する PythonでのTupleという名前のmutableの存在? 質問13のテストは、namedtupleの6つのmutableの代替を比較するために使用されます。

最新の namedlist 1.7 passes Python 2.7およびPython 3.52016年1月11日現在。これは純粋なpython実装です。

これらのテストによる次善の候補は、C拡張である recordclass です。もちろん、C拡張が優先されるかどうかは要件によって異なります。

特にテストの詳細については、 PythonでのTupleという名前の可変の存在? を参照してください。

1
Ali

時間をかけて集められたいくつかの有用なトリックに基づいて、この「frozenclass」デコレーターは必要なほとんどすべてを実行します。 http://Pastebin.com/fsuVyM45

そのコードは70%を超えるドキュメントとテストであるため、ここではこれ以上述べません。

0
BobC

これは、リストのように動作し、完全に互換性がある、私が作成した完全な変更可能な名前付きタプルです。

class AbstractNamedArray():
    """a mutable collections.namedtuple"""
    def __new__(cls, *args, **kwargs):
        inst = object.__new__(cls)  # to rename the class
        inst._list = len(cls._fields)*[None]
        inst._mapping = {}
        for i, field in enumerate(cls._fields):
            inst._mapping[field] = i
        return inst

    def __init__(self, *args, **kwargs):
        if len(kwargs) == 0 and len(args) != 0:
            assert len(args) == len(self._fields), 'bad number of arguments'
            self._list = list(args)
        Elif len(args) == 0 and len(kwargs) != 0:
            for field, value in kwargs.items():
                assert field in self._fields, 'field {} doesn\'t exist'
                self._list[self._mapping[field]] = value
        else:
            raise ValueError("you can't mix args and kwargs")

    def __getattr__(self, x):
        return object.__getattribute__(self, '_list')[object.__getattribute__(self, '_mapping')[x]]

    def __setattr__(self, x, y):
        if x in self._fields:
            self._list[self._mapping[x]] = y
        else:
            object.__setattr__(self, x, y)

    def __repr__(self):
        fields = []
        for field, value in Zip(self._fields, map(self.__getattr__, self._fields)):
            fields.append('{}={}'.format(field, repr(value)))
        return '{}({})'.format(self._name, ', '.join(fields))

    def __iter__(self):
        yield from self._list

    def __list__(self):
        return self._list[:]

    def __len__(self):
        return len(self._fields)

    def __getitem__(self, x):
        return self._list[x]

    def __setitem__(self, x, y):
        self._list[x] = y

    def __contains__(self, x):
        return x in self._list

    def reverse(self):
        self._list.reverse()

    def copy(self):
        return self._list.copy()


def namedarray(name, fields):
    """used to construct a named array (fixed-length list with named fields)"""
    return type(name, (AbstractNamedarray,), {'_name': name, '_fields': fields})
0
Architektor

独自の__dict__であるthis dictsubclassのようなことができます。基本的な概念はActiveState AttrDict レシピの概念と同じですが、実装は簡単です。インスタンスの属性と値の両方が変更可能であるため、結果は必要以上に変更可能なものになります。属性は順序付けられていませんが、現在の属性やその値を反復処理できます。

class Record(dict):
    def __init__(self, *args, **kwargs):
        super(Record, self).__init__(*args, **kwargs)
        self.__dict__ = self
0
martineau