Kann jemand namedtuple ändern oder eine alternative Klasse bereitstellen, so dass es für veränderbare Objekte funktioniert?Existenz von veränderbaren benannten Tupel in Python?
In erster Linie für die Lesbarkeit, würde ich etwas ähnliches wie namedtuple mag, das dies tut:
from Camelot import namedgroup
Point = namedgroup('Point', ['x', 'y'])
p = Point(0, 0)
p.x = 10
>>> p
Point(x=10, y=0)
>>> p.x *= 10
Point(x=100, y=0)
Es muss möglich sein, das resultierende Objekt beizen. Und je nach den Eigenschaften des benannten Tupels muss die Reihenfolge der Ausgabe bei der Darstellung mit der Reihenfolge der Parameterliste beim Erstellen des Objekts übereinstimmen.
ANTWORT: Vielen Dank an alle, die Vorschläge eingereicht haben. Ich glaube, dass recordclass von @ intellimath ist die beste Lösung (siehe auch here).
recordclass 0,4 Mutable Variante collections.namedtuple, die Zuweisungen
recordclass unterstützt, ist MIT lizenzierte Python-Bibliothek. Es implementiert den Typ memoryslots und factory function recordclass, um satzartige Klassen zu erstellen.
memoryslots ist ein tupelartiger Typ, der Zuweisungsoperationen unterstützt. Recordclass ist eine Factory-Funktion, die ein "veränderbares" Analog von collection.namedtuple erstellt. Diese Bibliothek ist tatsächlich ein "Proof of Concept" für das Problem der "veränderbaren" Alternative von namedtuple.
Ich habe auch einige Tests gegen alle Vorschläge durchgeführt. Nicht alle diese Funktionen wurden angefordert, daher ist der Vergleich nicht wirklich fair. Die Tests dienen nur dazu, die Verwendbarkeit jeder Klasse aufzuzeigen.
# Option 1 (p1): @kennes913
# Option 2 (p2): @MadMan2064
# Option 3 (p3): @intellimath
# Option 4 (p4): @Roland Smith
# Option 5 (p5): @agomcas
# Option 6 (p6): @Antti Haapala
# TEST: p1 p2 p3 p4 p5 p6
# 1. Mutation of field values | x | x | x | x | x | x |
# 2. String | | x | x | x | | x |
# 3. Representation | | x | x | x | | x |
# 4. Sizeof | x | x | x | ? | ?? | x |
# 5. Access by name of field | x | x | x | x | x | x |
# 6. Access by index. | | | x | | | |
# 7. Iterative unpacking. | | x | x | | | x |
# 8. Iteration | | x | x | | | x |
# 9. Ordered Dict | | | x | | | |
# 10. Inplace replacement | | | x | | | |
# 11. Pickle and Unpickle | | | x | | | |
# 12. Fields* | | | yes | | yes | |
# 13. Slots* | yes | | | | yes | |
# *Note that I'm not very familiar with slots and fields, so please excuse
# my ignorance in reporting their results. I have included them for completeness.
# Class/Object creation.
p1 = Point1(x=1, y=2)
Point2 = namedgroup("Point2", ["x", "y"])
p2 = Point2(x=1, y=2)
Point3 = recordclass('Point3', 'x y') # ***
p3 = Point3(x=1, y=2)
p4 = AttrDict()
p4.x = 1
p4.y = 2
p5 = namedlist('Point5', 'x y')
Point6 = namedgroup('Point6', ['x', 'y'])
p6 = Point6(x=1, y=2)
point_objects = [p1, p2, p3, p4, p5, p6]
# 1. Mutation of field values.
for n, p in enumerate(point_objects):
try:
p.x *= 10
p.y += 10
print('p{0}: {1}, {2}'.format(n + 1, p.x, p.y))
except Exception as e:
print('p{0}: Mutation not supported. {1}'.format(n + 1, e))
p1: 10, 12
p2: 10, 12
p3: 10, 12
p4: 10, 12
p5: 10, 12
p6: 10, 12
# 2. String.
for n, p in enumerate(point_objects):
print('p{0}: {1}'.format(n + 1, p))
p1: <__main__.Point1 instance at 0x10c72dc68>
p2: Point2(x=10, y=12)
p3: Point3(x=10, y=12)
p4: {'y': 12, 'x': 10}
p5: <class '__main__.Point5'>
p6: Point6(x=10, y=12)
# 3. Representation.
[('p{0}'.format(n + 1), p) for n, p in enumerate(point_objects)]
[('p1', <__main__.Point1 instance at 0x10c72dc68>),
('p2', Point2(x=10, y=12)),
('p3', Point3(x=10, y=12)),
('p4', {'x': 10, 'y': 12}),
('p5', __main__.Point5),
('p6', Point6(x=10, y=12))]
# 4. Sizeof.
for n, p in enumerate(point_objects):
print("size of p{0}:".format(n + 1), sys.getsizeof(p))
size of p1: 72
size of p2: 64
size of p3: 72
size of p4: 280
size of p5: 904
size of p6: 64
# 5. Access by name of field.
for n, p in enumerate(point_objects):
print('p{0}: {1}, {2}'.format(n + 1, p.x, p.y))
p1: 10, 12
p2: 10, 12
p3: 10, 12
p4: 10, 12
p5: 10, 12
p6: 10, 12
# 6. Access by index.
for n, p in enumerate(point_objects):
try:
print('p{0}: {1}, {2}'.format(n + 1, p[0], p[1]))
except:
print('p{0}: Unable to access by index.'.format(n+1))
p1: Unable to access by index.
p2: Unable to access by index.
p3: 10, 12
p4: Unable to access by index.
p5: Unable to access by index.
p6: Unable to access by index.
# 7. Iterative unpacking.
for n, p in enumerate(point_objects):
try:
x, y = p
print('p{0}: {1}, {2}'.format(n + 1, x, y))
except:
print('p{0}: Unable to unpack.'.format(n + 1))
p1: Unable to unpack.
p2: 10, 12
p3: 10, 12
p4: y, x
p5: Unable to unpack.
p6: 10, 12
# 8. Iteration
for n, p in enumerate(point_objects):
try:
print('p{0}: {1}'.format(n + 1, [v for v in p]))
except:
print('p{0}: Unable to iterate.'.format(n + 1))
p1: Unable to iterate.
p2: [10, 12]
p3: [10, 12]
p4: ['y', 'x']
p5: Unable to iterate.
p6: [10, 12]
In [95]:
# 9. Ordered Dict
for n, p in enumerate(point_objects):
try:
print('p{0}: {1}'.format(n + 1, p._asdict()))
except:
print('p{0}: Unable to create Ordered Dict.'.format(n + 1))
p1: Unable to create Ordered Dict.
p2: Unable to create Ordered Dict.
p3: OrderedDict([('x', 10), ('y', 12)])
p4: Unable to create Ordered Dict.
p5: Unable to create Ordered Dict.
p6: Unable to create Ordered Dict.
# 10. Inplace replacement
for n, p in enumerate(point_objects):
try:
p_ = p._replace(x=100, y=200)
print('p{0}: {1} - {2}'.format(n + 1, 'Success' if p is p_ else 'Failure', p))
except:
print('p{0}: Unable to replace inplace.'.format(n + 1))
p1: Unable to replace inplace.
p2: Unable to replace inplace.
p3: Success - Point3(x=100, y=200)
p4: Unable to replace inplace.
p5: Unable to replace inplace.
p6: Unable to replace inplace.
# 11. Pickle and Unpickle.
for n, p in enumerate(point_objects):
try:
pickled = pickle.dumps(p)
unpickled = pickle.loads(pickled)
if p != unpickled:
raise ValueError((p, unpickled))
print('p{0}: {1}'.format(n + 1, 'Pickled successfully',))
except Exception as e:
print('p{0}: {1}; {2}'.format(n + 1, 'Pickle failure', e))
p1: Pickle failure; (<__main__.Point1 instance at 0x10c72dc68>, <__main__.Point1 instance at 0x10ca631b8>)
p2: Pickle failure; (Point2(x=10, y=12), Point2(x=10, y=12))
p3: Pickled successfully
p4: Pickle failure; '__getstate__'
p5: Pickle failure; Can't pickle <class '__main__.Point5'>: it's not found as __main__.Point5
p6: Pickle failure; (Point6(x=10, y=12), Point6(x=10, y=12))
# 12. Fields.
for n, p in enumerate(point_objects):
try:
print('p{0}: {1}'.format(n + 1, p._fields))
except Exception as e:
print('p{0}: {1}; {2}'.format(n + 1, 'Unable to access fields.', e))
p1: Unable to access fields.; Point1 instance has no attribute '_fields'
p2: Unable to access fields.; 'Point2' object has no attribute '_fields'
p3: ('x', 'y')
p4: Unable to access fields.; '_fields'
p5: ('x', 'y')
p6: Unable to access fields.; 'Point6' object has no attribute '_fields'
# 13. Slots.
for n, p in enumerate(point_objects):
try:
print('p{0}: {1}'.format(n + 1, p.__slots__))
except Exception as e:
print('p{0}: {1}; {2}'.format(n + 1, 'Unable to access slots', e))
p1: ['x', 'y']
p2: Unable to access slots; 'Point2' object has no attribute '__slots__'
p3:()
p4: Unable to access slots; '__slots__'
p5: ('x', 'y')
p6: Unable to access slots; 'Point6' object has no attribute '__slots__'
Könnten Sie eine Liste verwenden? – JGerulskis
Sie könnten eine sehr einfache Point-Klasse erstellen, die dies getan hat. – 101
Siehe auch: http://stackoverflow.com/q/5131044/. Gibt es einen Grund, warum du nicht einfach ein Wörterbuch benutzen kannst? – senshin