2010-12-23 5 views
6

ich die folgende Zeichenfolge Unterklasse haben:Ändern subclassed Zeichenfolge anstelle

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 wie folgt arbeiten:

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

Stattdessen bekomme 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 in den Unterschied zwischen veränderlichen und unveränderlichen Strings kommt. Subclassing scheint der richtige Weg zu sein, Strings als veränderbare Objekte zu behandeln (zumindest nach der python docs), aber ich denke, dass mir ein Schlüsselelement in meiner Implementierung fehlt.

+4

Die Dokumente sagen Ihnen, _wrap_ die String-Klasse nicht Unterklasse es! Das heißt, um das zu tun, was Sie wollten, sollten Sie eine Klasse von "object" ableiten, wobei ein Attribut den aktuellen Wert der Zeichenfolge enthält. – katrielalex

+0

[Schlägt die Stirn mit der Hand] D'oh! Vielen Dank. Vielen Dank. Bitte machen Sie Ihren obigen Kommentar zu einer Antwort (oder fügen Sie sie zu Ihrer bestehenden hinzu), damit ich sie akzeptieren kann. Ich dachte, ich hätte etwas Offensichtliches vermisst. – mwolfe02

Antwort

4

Sie können nicht tun, was Sie fragen, weil Strings unveränderlich sind. Die Dokumente sagen Ihnen Wrap die str Klasse; das heißt, eine Klasse mit einem Attribut zu erstellen, das der aktuelle Wert der "veränderbaren Zeichenfolge" ist. Dies existiert in der Standardbibliothek von Python 2.x als UserString.MutableString (ist aber in Python 3 verschwunden); es ist ziemlich einfach zu schreiben, aber:

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 

jedoch ein besserer Plan ist es, ein StringIO zu verwenden. Tatsächlich können Sie der gewünschten Funktionalität ziemlich nahe kommen, indem Sie StringIO ableiten (beachten Sie, dass Sie dafür die reine Python-Version und nicht die C-Version verwenden müssen und dass es sich um eine alte Klasse handelt, die Sie nicht verwenden können) super). Das ist sauberer, schneller und insgesamt 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 __repr__ außer Kraft setzen, wenn Sie x wollen mehr sehen noch wie eine Zeichenfolge, aber das ist eine schlechte Praxis, da wo möglich __repr__ gemeint ist eine Beschreibung in Python des Objekts zurückzukehren.

+0

Wie Sie in Ihrem Kommentar zu meiner Frage vorgeschlagen haben, habe ich meine Klasse so geändert, dass sie von "object" erbt und "__init__" verwendet hat, um den Zeichenfolgenwert festzulegen. Funktioniert super! – mwolfe02

+0

Habe gerade deine neuen Beispiele nach dem Auffrischen gesehen. Große, gründliche Antwort. – mwolfe02

3

Die Linie self = self + delimiter + next_val ist die Schaffung einer neuen variable self und das Ergebnis der self + delimiter + next_val auf diese zuzuweisen. Um das zu erreichen, was Sie wollen, müssen Sie die Operation direkt auf die Variable self anwenden. Aber da Strings unveränderlich sind, können Sie das nicht tun. Das ist genau der Grund, warum alle str s-Methoden eine neue Zeichenfolge zurückgeben, anstatt die Zeichenfolgen zu ändern, auf denen sie arbeiten.

Es tut uns leid, Sie können nicht tun, was Sie erreichen möchten.

0

Es gibt keine veränderbaren Zeichenketten. Es gibt Bytes/Bytearrays und Listen von Ein-Zeichen-Strings, die Sie ändern und dann in einen String umwandeln können. Wenn Sie eine "veränderbare Zeichenkette" emulieren möchten, müssten Sie eine Zeichenkette in einem privaten Feld behalten, diese ersetzen und andernfalls vorgeben, dass Sie diese Zeichenkette sind (das ist wahrscheinlich, was MutableString tut). Seien Sie jedoch gewarnt: Dies wird höchst ineffizient sein und wird wahrscheinlich nicht benötigt. Außerdem können Sie nicht immer veränderbare Zeichenfolgen anstelle von unveränderlichen Zeichenfolgen (z. B. als dict-Schlüssel) verwenden. Warum denkst du, du brauchst eine veränderbare Saite? Der Rest von uns (und die Java- und .NET-Leute) kommen gut ohne aus.

Ihr conc funktioniert nicht, da Python nicht über die Referenz verfügt. self = ... ändert nicht das aktuelle Objekt, es überschreibt nur eine lokale Variable (self.member = ...) funktioniert Arbeit, weil das ein Methodenaufruf ist, der ein Wörterbuch ändert).

+0

Alles in Python ist eine Referenz. Das Zuweisen an sich selbst bindet nur den Namen. – katrielalex

+0

@katrielalex: Ja, jede Variable ist eine Referenz, aber Python übergibt diese Referenzen (oder Zeiger, in C/C++ sprechen) nach Wert. – delnan

1

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

Es gibt eine Klasse namens MutableString im UserString-Modul, die möglicherweise das tun würde, was Sie wollen.

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

0

ist eine Implementierung von dem, was Sie tun möchten:

Sie diese Klasse mit mehr Methoden erweitern können.

+0

Ihr Beispiel funktioniert nur, wenn Sie "objekt" statt "str" ​​ableiten. – mwolfe02

+0

Danke, bearbeitet. Ich war versucht, alle Standardmethoden von 'str' zu erben. Aber wusste nicht, dass es nicht funktionieren würde, wenn ich eine benutzerdefinierte Methode hinzufügen würde. Können wir nicht unsere eigenen Methoden hinzufügen, wenn wir 'str' erben? – dheerosaur