6 Stimmen

Unterklassifizierte Zeichenfolge an Ort und Stelle ändern

Ich habe die folgende String-Unterklasse:

class S(str):
    def conc(self, next_val, delimiter = ' '):
        """Concatenate values to an existing string"""
        if not next_val is None:
            self = self + delimiter + next_val
        return self

Ich erwarte, dass dies folgendermaßen funktioniert:

>>> x = S("My")
>>> x.conc("name")
'My name'
>>> x
'My name'

Stattdessen erhalte ich dies:

>>> x = S("My")
>>> x.conc("name")
'My name'
>>> x
'My'

Gibt es eine Möglichkeit, die Zeichenfolge an Ort und Stelle zu ändern? Ich denke, dass dies den Unterschied zwischen veränderlichen und unveränderlichen Zeichenketten betrifft. Die Unterklassifizierung scheint der richtige Weg zu sein, um Strings als veränderbare Objekte zu behandeln (zumindest nach der Python-Dokumente ), aber ich glaube, mir fehlt ein wichtiges Element in meiner Umsetzung.

5voto

Katriel Punkte 115208

Sie können nicht tun, was Sie fragen, weil Strings unveränderlich sind. Die Dokumentation sagt Ihnen, dass Sie wickeln die str Klasse zu erstellen, d.h. eine Klasse mit einem Attribut, das der aktuelle Wert des "mutable string" ist. Dies existiert in der Standardbibliothek von Python 2.x als UserString.MutableString (ist aber in Python 3 verschwunden); es ist aber ziemlich einfach zu schreiben:

class MutableString(object):
    def __init__(self, value):
        self.value = value

    def conc(self, value, delim=' '):
        self.value = "{self.value}{delim}{value}".format(**locals())

    def __str__(self):
        return self.value

Ein besserer Plan ist jedoch die Verwendung eines StringIO . In der Tat können Sie der gewünschten Funktionalität ziemlich nahe kommen, indem Sie eine Unterklasse StringIO (Beachten Sie, dass Sie die reine Python-Version und nicht die C-Version verwenden müssen, um dies zu tun, und dass es eine Klasse im alten Stil ist, so dass Sie nicht super ). Das ist übersichtlicher, schneller und alles in allem IMO eleganter.

>>> from StringIO import StringIO as sIO
>>> class DelimitedStringIO(sIO):
...     def __init__(self, initial, *args, **kwargs):
...             sIO.__init__(self, *args, **kwargs)
...             self.write(initial)
...
...     def conc(self, value, delim=" "):
...             self.write(delim)
...             self.write(value)
...
...     def __str__(self):
...             return self.getvalue()
...
>>> x = DelimitedStringIO("Hello")
>>> x.conc("Alice")
>>> x.conc("Bob", delim=", ")
>>> x.conc("Charlie", delim=", and ")
>>> print x
Hello Alice, Bob, and Charlie

Sie können überschreiben __repr__ wenn Sie möchten x um noch mehr wie eine Zeichenkette auszusehen, aber das ist eine schlechte Praxis, denn wenn möglich __repr__ dient dazu, eine Beschreibung des Objekts in Python zurückzugeben.

3voto

moinudin Punkte 125641

Die Linie self = self + delimiter + next_val erstellt eine neu variabel self und die Zuweisung des Ergebnisses von self + delimiter + next_val dazu. Um das zu erreichen, was Sie wollen, müssen Sie den Vorgang direkt auf die self variabel. Da Strings jedoch unveränderlich sind, können Sie dies nicht tun. Das ist genau der Grund, warum alle str Methoden geben eine neue Zeichenkette zurück, anstatt die Zeichenketten zu verändern, die sie bearbeiten.

Es tut mir sehr leid, dass Sie das, was Sie erreichen wollen, nicht tun können.

1voto

bdew Punkte 1310

Python-Strings (und alles, was von ihnen erbt) sind unveränderlich.

Es gibt eine Klasse namens MutableString im UserString-Modul, die das tun könnte, was Sie wollen.

Wenn Sie eine neuere (wie in 2.7/3.1) Version von Python verwenden, können Sie auch Bytearray betrachten, obwohl es eine Reihe von Grenzen und Macken hat.

0voto

Es gibt keine veränderbaren Zeichenketten. Es gibt Bytes/Bytearrays und Listen mit einstelligen Zeichenketten, die man ändern und dann in eine Zeichenkette verwandeln kann. Wenn Sie eine "veränderbare Zeichenkette" emulieren wollen, müssen Sie eine Zeichenkette in einem privaten Feld aufbewahren, diese ersetzen und ansonsten so tun, als wären Sie diese Zeichenkette (das ist wahrscheinlich das, was MutableString tut). Seien Sie jedoch gewarnt: Dies wird sehr ineffizient sein und ist wahrscheinlich nicht notwendig. Außerdem können Sie nicht immer veränderbare Strings anstelle von unveränderlichen Strings verwenden (z. B. als dict key). Warum glauben Sie, dass Sie eine veränderbare Zeichenkette brauchen? Der Rest von uns (und die Java- und .NET-Jungs) kommen ganz gut ohne aus.

Ihr conc funktioniert nicht, weil Python kein pass-by-reference kennt. self = ... ändert nicht das aktuelle Objekt, sondern überschreibt lediglich eine lokale Variable ( self.member = ... ) fait funktionieren, da es sich um einen Methodenaufruf handelt, der ein Wörterbuch ändert).

0voto

dheerosaur Punkte 13811

Hier ist eine Umsetzung dessen, was Sie tun möchten:

class S(object):
    def __init__(self, val=""):
        self.data = val;

    def conc(self, next_val, delimiter = ' '):
        if not next_val is None:
            self.data = self.data + delimiter + next_val
        return self

    def __repr__(self):
        return self.data

Sie können diese Klasse um weitere Methoden erweitern.

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