2015-03-26 5 views
62

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__' 
+0

Könnten Sie eine Liste verwenden? – JGerulskis

+4

Sie könnten eine sehr einfache Point-Klasse erstellen, die dies getan hat. – 101

+3

Siehe auch: http://stackoverflow.com/q/5131044/. Gibt es einen Grund, warum du nicht einfach ein Wörterbuch benutzen kannst? – senshin

Antwort

63

Es gibt eine veränderbare Alternative zu collections.namedtuple - recordclass.

Es hat die gleiche API und Speicherbedarf wie namedtuple und es unterstützt Zuweisungen (Es sollte auch schneller sein). Zum Beispiel:

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) 

Es gibt ein vollständigere example (es enthält auch Leistungsvergleiche).

+1

Gefällt mir. Diese Bibliothek ist tatsächlich ein "Proof of Concept" für das Problem der "veränderbaren" Alternative des benannten Tupels. – Alexander

+0

'recordclass' ist langsamer, benötigt mehr Speicher und benötigt C-Erweiterungen als [verglichen] (https: // gist .github.com/grantjenks/a06da0db18826be1176c31c95a6ee572) mit Antti Haapalas Rezept und 'namedlist'. – GrantJ

+0

'recordclass' ist eine veränderbare Version von' collection.namedtuple', die den api, den Speicher-Footprint, aber die Support-Zuweisungen erbt. 'Namedlist' ist eigentlich Instanz der Python-Klasse mit Slots. Es ist sinnvoller, wenn Sie keinen schnellen Zugriff auf die Felder nach Index benötigen. – intellimath

19

Es scheint wie die Antwort auf diese Frage ist nein.

Unten ist ziemlich nah, aber es ist technisch nicht veränderbar. Dies ist eine neue namedtuple() Instanz mit einem aktualisierten x Wert zu schaffen:

Point = namedtuple('Point', ['x', 'y']) 
p = Point(0, 0) 
p = p._replace(x=10) 

Auf der anderen Seite können Sie eine einfache Klasse erstellen __slots__ verwenden, die für häufig aktualisiert Klasseninstanz gut funktionieren sollte Attribute:

class Point: 
    __slots__ = ['x', 'y'] 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

Um diese Antwort hinzuzufügen, denke ich, __slots__ ist hier gut zu verwenden, weil es Speicher effizient ist, wenn Sie viele Klasseninstanzen erstellen. Der einzige Nachteil ist, dass Sie keine neuen Klassenattribute erstellen können.

Hier ist ein relevanter Thread, der die Speichereffizienz zeigt - Dictionary vs Object - which is more efficient and why?

Der zitierte Inhalt in der Antwort dieses Threads ist eine sehr kurze Erläuterung, warum __slots__ mehr Speicher effizient ist - Python slots

+1

Schließen, aber klobig.Nehmen wir an, ich wollte eine + = Zuweisung machen, dann müsste ich tun: p._replace (x = px + 10) vs. px + = 10 – Alexander

+0

yeah, es ändert nicht wirklich das existierende Tupel, es erzeugt eine neue Instanz – kennes

1

Tupeln sind per Definition unveränderlich .

Sie können jedoch eine Dictionary-Unterklasse erstellen, in der Sie mit der Punktnotation auf die Attribute zugreifen können.

In [1]: %cpaste 
Pasting code; enter '--' alone on the line to stop or use Ctrl-D. 
:class AttrDict(dict): 
: 
: def __getattr__(self, name): 
:  return self[name] 
: 
: def __setattr__(self, name, value): 
:  self[name] = value 
:-- 

In [2]: test = AttrDict() 

In [3]: test.a = 1 

In [4]: test.b = True 

In [5]: test 
Out[5]: {'a': 1, 'b': True} 
1

Wenn Sie wollen ein ähnliches Verhalten wie namedtuples aber wandelbar versuchen namedlist

Beachten Sie, dass, um wandelbar zu sein, es kann nicht ein Tupel sein.

+0

Danke für den Link. Das sieht so ähnlich aus wie bisher, aber ich muss es genauer auswerten. Übrigens bin ich mir völlig bewusst, dass Tupel unveränderlich sind, weshalb ich nach einer Lösung suche, ähnlich wie namedtuple. – Alexander

3

Lasst uns diese Umsetzung mit dynamischen Typ Schöpfung:

import copy 
def namedgroup(typename, fieldnames): 

    def init(self, **kwargs): 
     attrs = {k: None for k in self._attrs_} 
     for k in kwargs: 
      if k in self._attrs_: 
       attrs[k] = kwargs[k] 
      else: 
       raise AttributeError('Invalid Field') 
     self.__dict__.update(attrs) 

    def getattribute(self, attr): 
     if attr.startswith("_") or attr in self._attrs_: 
      return object.__getattribute__(self, attr) 
     else: 
      raise AttributeError('Invalid Field') 

    def setattr(self, attr, value): 
     if attr in self._attrs_: 
      object.__setattr__(self, attr, value) 
     else: 
      raise AttributeError('Invalid Field') 

    def rep(self): 
     d = ["{}={}".format(v,self.__dict__[v]) for v in self._attrs_] 
     return self._typename_ + '(' + ', '.join(d) + ')' 

    def iterate(self): 
     for x in self._attrs_: 
      yield self.__dict__[x] 
     raise StopIteration() 

    def setitem(self, *args, **kwargs): 
     return self.__dict__.__setitem__(*args, **kwargs) 

    def getitem(self, *args, **kwargs): 
     return self.__dict__.__getitem__(*args, **kwargs) 

    attrs = {"__init__": init, 
       "__setattr__": setattr, 
       "__getattribute__": getattribute, 
       "_attrs_": copy.deepcopy(fieldnames), 
       "_typename_": str(typename), 
       "__str__": rep, 
       "__repr__": rep, 
       "__len__": lambda self: len(fieldnames), 
       "__iter__": iterate, 
       "__setitem__": setitem, 
       "__getitem__": getitem, 
       } 

    return type(typename, (object,), attrs) 

Diese Attribute überprüft, ob sie den Betrieb, bevor ermöglicht weiterhin gültig sind.

So ist das pickleable? Ja, wenn (und nur dann) Sie Folgendes tun:

>>> import pickle 
>>> Point = namedgroup("Point", ["x", "y"]) 
>>> p = Point(x=100, y=200) 
>>> p2 = pickle.loads(pickle.dumps(p)) 
>>> p2.x 
100 
>>> p2.y 
200 
>>> id(p) != id(p2) 
True 

Die Definition hat in Ihrem Namensraum sein, und muss lange genug existiert für Pickel, es zu finden. Wenn Sie dies in Ihrem Paket definieren, sollte es funktionieren.

Point = namedgroup("Point", ["x", "y"]) 

Pickle schlagen fehl, wenn Sie die folgende tun, oder die Definition vorübergehend machen (out of scope geht, wenn die Funktion endet, sagen):

some_point = namedgroup("Point", ["x", "y"]) 

Und ja, es um die Reihenfolge der nicht bewahrt die Felder, die bei der Typerstellung aufgeführt sind.

+0

Wenn Sie eine '__iter__' Methode mit' für k in self._attrs_: yield getattr (self, k) 'hinzufügen, wird das Entpacken wie ein Tupel unterstützt. – snapshoe

+0

Es ist auch ziemlich einfach, '__len__',' __getitem__' und '__setiem__' Methoden hinzuzufügen, um valus nach Index zu erhalten, wie' p [0] '. Mit diesen letzten Bits scheint dies die vollständigste und korrekteste Antwort zu sein (für mich jedenfalls). – snapshoe

+0

'__len__' und' __iter__' sind gut. '__getitem__' und' __setitem__' können wirklich auf 'self .__ dict __.__ setitem__' und' self .__ dict __.__ getitem__' abgebildet werden. – MadMan2064

7

Folgendes ist eine gute Lösung für Python 3: Eine minimale Klasse mit __slots__ und Sequence abstrakte Basisklasse; macht keine fancy error detection oder so, aber es funktioniert und verhält sich meistens wie ein veränderbares Tupel (außer typecheck).

from collections import Sequence 

class NamedMutableSequence(Sequence): 
    __slots__ =() 

    def __init__(self, *a, **kw): 
     slots = self.__slots__ 
     for k in slots: 
      setattr(self, k, kw.get(k)) 

     if a: 
      for k, v in zip(slots, a): 
       setattr(self, k, v) 

    def __str__(self): 
     clsname = self.__class__.__name__ 
     values = ', '.join('%s=%r' % (k, getattr(self, k)) 
          for k in self.__slots__) 
     return '%s(%s)' % (clsname, values) 

    __repr__ = __str__ 

    def __getitem__(self, item): 
     return getattr(self, self.__slots__[item]) 

    def __setitem__(self, item, value): 
     return setattr(self, self.__slots__[item], value) 

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

class Point(NamedMutableSequence): 
    __slots__ = ('x', 'y') 

Beispiel:

>>> p = Point(0, 0) 
>>> p.x = 10 
>>> p 
Point(x=10, y=0) 
>>> p.x *= 10 
>>> p 
Point(x=100, y=0) 

Wenn Sie möchten, können Sie eine Methode, die Klasse zu erstellen (wenn auch eine explizite-Klasse ist transparenter):

def namedgroup(name, members): 
    if isinstance(members, str): 
     members = members.split() 
    members = tuple(members) 
    return type(name, (NamedMutableSequence,), {'__slots__': members}) 

Beispiel:

>>> Point = namedgroup('Point', ['x', 'y']) 
>>> Point(6, 42) 
Point(x=6, y=42) 

In Python 2 müssen Sie es leicht einstellen - wenn Sie inherit from Sequence, the class will have a __dict__ und die __slots__ aufhören zu arbeiten.

Die Lösung in Python 2 ist nicht erben von Sequence, aber object. Wenn isinstance(Point, Sequence) == True gewünscht ist, müssen Sie die NamedMutableSequence als Basisklasse zu Sequence registrieren: sowohl mit Python

Sequence.register(NamedMutableSequence) 
13

Die neuesten namedlist 1.7 Pässe alle Tests 2.7 und Python 3.5 zum 11. Januar 2016. Es ist eine reine Python-Implementierung, während die recordclass eine C-Erweiterung ist. Natürlich hängt es von Ihren Anforderungen ab, ob eine C-Erweiterung bevorzugt wird oder nicht.

Ihre Tests (aber auch den Hinweis unten):

from __future__ import print_function 
import pickle 
import sys 
from namedlist import namedlist 

Point = namedlist('Point', 'x y') 
p = Point(x=1, y=2) 

print('1. Mutation of field values') 
p.x *= 10 
p.y += 10 
print('p: {}, {}\n'.format(p.x, p.y)) 

print('2. String') 
print('p: {}\n'.format(p)) 

print('3. Representation') 
print(repr(p), '\n') 

print('4. Sizeof') 
print('size of p:', sys.getsizeof(p), '\n') 

print('5. Access by name of field') 
print('p: {}, {}\n'.format(p.x, p.y)) 

print('6. Access by index') 
print('p: {}, {}\n'.format(p[0], p[1])) 

print('7. Iterative unpacking') 
x, y = p 
print('p: {}, {}\n'.format(x, y)) 

print('8. Iteration') 
print('p: {}\n'.format([v for v in p])) 

print('9. Ordered Dict') 
print('p: {}\n'.format(p._asdict())) 

print('10. Inplace replacement (update?)') 
p._update(x=100, y=200) 
print('p: {}\n'.format(p)) 

print('11. Pickle and Unpickle') 
pickled = pickle.dumps(p) 
unpickled = pickle.loads(pickled) 
assert p == unpickled 
print('Pickled successfully\n') 

print('12. Fields\n') 
print('p: {}\n'.format(p._fields)) 

print('13. Slots') 
print('p: {}\n'.format(p.__slots__)) 

Ausgabe auf Python 2,7

 
1. Mutation of field values 
p: 10, 12 

2. String 
p: Point(x=10, y=12) 

3. Representation 
Point(x=10, y=12) 

4. Sizeof 
size of p: 64 

5. Access by name of field 
p: 10, 12 

6. Access by index 
p: 10, 12 

7. Iterative unpacking 
p: 10, 12 

8. Iteration 
p: [10, 12] 

9. Ordered Dict 
p: OrderedDict([('x', 10), ('y', 12)]) 

10. Inplace replacement (update?) 
p: Point(x=100, y=200) 

11. Pickle and Unpickle 
Pickled successfully 

12. Fields 
p: ('x', 'y') 

13. Slots 
p: ('x', 'y') 

Der einzige Unterschied mit Python 3.5 ist, dass die namedlist kleiner geworden ist, ist die Größe 56 (Python 2.7 meldet 64).

Beachten Sie, dass ich Ihren Test 10 für den Ersatz vor Ort geändert habe. Die namedlist hat eine _replace() Methode, die eine flache Kopie macht, und das macht für mich Sinn, weil die in der Standard-Bibliothek auf die gleiche Weise verhält. Ändern der Semantik der _replace() Methode wäre verwirrend. Meiner Meinung nach sollte die _update() Methode für In-Place-Updates verwendet werden. Oder vielleicht habe ich die Absicht Ihres Tests nicht verstanden 10?

+0

Es gibt wichtige Nuance. Die 'Namedlist' speichert Werte in der Listeninstanz. Die Sache ist, dass 'cpython'' liste' eigentlich ein dynamisches Array ist. Es weist mehr Speicher zu als nötig, um die Mutation der Liste billiger zu machen. – intellimath

+0

@intellimath benannte Liste ist ein bisschen irreführend. Es erbt nicht wirklich von 'list' und verwendet standardmäßig' __slots__' Optimierung. Als ich gemessen habe, war der Speicherverbrauch geringer als 'recordclass': 96 Bytes vs 104 Bytes für sechs Felder auf Python 2.7 – GrantJ

+0

@GrantJ Ja. 'recorderclass' verwendet mehr Speicher, da es sich um ein' Tupel'-ähnliches Objekt mit variabler Speichergröße handelt. – intellimath

5

types.SimpleNamespace wurde in Python 3.3 eingeführt und unterstützt die angeforderten Anforderungen.

from types import SimpleNamespace 
t = SimpleNamespace(foo='bar') 
t.ham = 'spam' 
print(t) 
namespace(foo='bar', ham='spam') 
print(t.foo) 
'bar' 
import pickle 
with open('/tmp/pickle', 'wb') as f: 
    pickle.dump(t, f) 
0

bereitgestellt Leistung ist von geringer Bedeutung, man einen dummen Hack wie verwenden:

from collection import namedtuple 

Point = namedtuple('Point', 'x y z') 
mutable_z = Point(1,2,[3]) 
+0

Diese Antwort ist nicht sehr gut erklärt. Es sieht verwirrend aus, wenn Sie die Veränderlichkeit von Listen nicht verstehen. --- In diesem Beispiel ... Um 'z' neu zuzuordnen, müssen Sie' mutable_z.z.pop (0) 'und dann' mutable_z.z.append (new_value) 'aufrufen. Wenn Sie das falsch verstehen, haben Sie mehr als 1 Element und Ihr Programm wird sich unerwartet verhalten. – byxor