58 Stimmen

Warum unterstützt Python keine Datensatztypen (z. B. veränderbare Namedtupel)?

Warum unterstützt Python nicht von Haus aus einen Record-Typ? Es geht darum, eine veränderbare Version von namedtuple zu haben.

Ich könnte Folgendes gebrauchen namedtuple._replace . Aber ich muss diese Datensätze in einer Sammlung haben und da namedtuple._replace eine weitere Instanz erstellt, muss ich auch die Sammlung ändern, was schnell unübersichtlich wird.

Hintergrund: Ich habe ein Gerät, dessen Attribute ich abfragen muss, indem ich es über TCP/IP abfrage, d.h. seine Darstellung ist ein veränderliches Objekt.

Bearbeiten: Ich habe eine Reihe von Geräten, für die ich eine Umfrage durchführen muss.

Bearbeiten: Ich muss durch das Objekt iterieren und seine Attribute mit PyQt anzeigen. Ich weiß, ich kann spezielle Methoden hinzufügen wie __getitem__ y __iter__ aber ich möchte wissen, ob es einen einfacheren Weg gibt.

Bearbeiten: Ich würde einen Typ bevorzugen, dessen Attribute fest sind (so wie sie in meinem Gerät sind), aber veränderbar sind.

56voto

tzot Punkte 86792

Python <3.3

Sie meinen so etwas wie das hier?

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)

Beachten Sie, dass die angegebenen Methoden nur eine Auswahl möglicher Methoden darstellen.

Python 3.3 Aktualisierung

Sie können verwenden types.SimpleNamespace :

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

dir(r) liefert Ihnen die Attributnamen (und filtert alle .startswith("__") natürlich).

18voto

Cameron Punkte 91138

Gibt es einen Grund, warum Sie nicht ein normales Wörterbuch verwenden können? Es scheint, dass die Attribute in Ihrer speziellen Situation keine bestimmte Reihenfolge haben.

Alternativ können Sie auch eine Klasseninstanz verwenden (die eine schöne Syntax für den Zugriff auf Attribute hat). Sie könnten verwenden __slots__ wenn Sie vermeiden möchten, dass ein __dict__ für jede Instanz erstellt.

Ich habe auch gerade eine Rezept für "Rekorde" , die als veränderbare benannte Tupel beschrieben werden. Sie werden durch Klassen implementiert.

Aktualisierung:

Da Sie sagen, dass die Reihenfolge für Ihr Szenario wichtig ist (und Sie durch alle Attribute iterieren möchten), wird ein OrderedDict scheint der richtige Weg zu sein. Dies ist Teil des Standards collections Modul ab Python 2.7; es gibt weitere Implementierungen die im Internet für Python < 2.7 kursieren.

Um den Zugriff über Attribute hinzuzufügen, können Sie sie wie folgt untergliedern:

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)

Dann können Sie das tun:

>>> 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']

11voto

Abbafei Punkte 2988

Dies kann mit Hilfe einer leeren Klasse und deren Instanzen geschehen, etwa so:

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

10voto

Leif Bork Punkte 403

Es gibt eine Bibliothek ähnlich wie namedtuple, aber veränderbar, namens recordtype.

Paket nach Hause: http://pypi.python.org/pypi/recordtype

Einfaches Beispiel:

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)

Einfaches Beispiel für einen Standardwert:

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

Iterieren Sie durch die Felder von person1 der Reihe nach:

map(person1.__getattribute__, Person._fields)

8voto

Daniel Punkte 1256

Diese Frage ist alt, aber nur der Vollständigkeit halber: Python 3.7 hat Datenklassen die so ziemlich alle Rekorde sind.

>>> from dataclasses import dataclass
>>>
>>> @dataclass
... class MyRecord:
...     name: str
...     age: int = -1
...
>>> rec = MyRecord('me')
>>> rec.age = 127
>>> print(rec)
MyRecord(name='me', age=127)

Die attrs-Bibliothek von Drittanbietern bietet mehr Funktionen für Python 2 und Python 3. Nichts falsch mit vendoring Abhängigkeiten entweder, wenn die Anforderung ist mehr um Dinge, die Sie nicht lokal halten können, anstatt speziell nur mit der stdlib. dephell hat einen netten Helfer für das tun.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X