2010-12-23 11 views
6

Tengo el siguiente subclase cadena:modificar una cadena subclase en lugar

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 

espero que esto funcione de la siguiente manera:

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

En vez me sale esto:

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

¿Hay alguna manera de modificar la cadena en su lugar? Creo que esto entra en la diferencia entre cadenas mutables e inmutables. La creación de subclases parece ser la forma correcta de tratar cadenas como objetos mutables (al menos de acuerdo con python docs), pero creo que me falta algo clave en mi implementación.

+4

¡Los documentos le dicen a _wrap_ la clase de cadena no la subclase! Es decir, para hacer lo que usted desea, debe hacer que una clase herede de 'objeto' con un atributo que contenga el valor actual de la cadena. – katrielalex

+0

[golpea la frente con la mano] ¡Oh! Gracias. Gracias. Haga una respuesta al comentario anterior (o agréguela a la existente) para poder aceptarla. Pensé que me estaba perdiendo algo obvio. – mwolfe02

Respuesta

4

No puede hacer lo que pregunta, porque las cadenas son inmutables. Los documentos le dicen que envuelva la clase str; es decir, para hacer una clase con un atributo que es el valor actual de la "cadena mutable". Esto existe en la biblioteca estándar de Python 2.x como UserString.MutableString (pero se ha ido en Python 3); que es bastante fácil de escribir, sin embargo:

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 

sin embargo, un plan mejor es utilizar un StringIO. De hecho, puedes acercarte bastante a la funcionalidad que querías subclasificando StringIO (ten en cuenta que necesitas usar la versión pura de Python no la versión C para hacer esto, y que es una clase de estilo antiguo, así que no puedes usar super). Esto es más ordenado, más rápido y en conjunto IMO más elegante.

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

Puede anular __repr__ si quieres x mirar aún más como una cadena, pero esto es una mala práctica, ya que en lo posible se entiende __repr__ para devolver una descripción en Python del objeto.

+0

Como sugirió en su comentario a mi pregunta, acabo de cambiar mi clase para heredar de 'object' y usé' __init__' para establecer el valor de la cadena. ¡Funciona genial! – mwolfe02

+0

Acabo de ver sus nuevos ejemplos después de actualizar. Gran respuesta completa. – mwolfe02

3

La línea self = self + delimiter + next_val es la creación de una nueva variables self y asignar el resultado de self + delimiter + next_val a esto. Para lograr lo que desea, debe aplicar la operación directamente a la variable self. Pero como las cuerdas son inmutables, no puedes hacer esto. Esta es exactamente la razón por la cual todos los métodos de str devuelven una nueva cadena en lugar de modificar las cadenas en las que operan.

Lo siento, no puede hacer lo que está tratando de lograr.

0

No hay cadenas mutables. Hay bytes/bytearrays y listas de cadenas de un solo carácter, que puede modificar y luego convertir en una cadena. Si quieres emular una "cadena mutable", tendrías que mantener una cadena en un campo privado, reemplazarla y pretender que eres esa cadena (esto es lo que hace MutableString). Tenga cuidado, sin embargo: Esto será altamente ineficiente y no es necesario. Además, no siempre puede usar cadenas mutables en lugar de cadenas inmutables (por ejemplo, como clave dict). ¿Por qué crees que necesitas una cuerda mutable? El resto de nosotros (y los chicos de Java y .NET) nos llevamos bien sin eso.

Su conc no funciona porque Python no tiene una referencia pasada. self = ... no cambia el objeto actual, simplemente sobrescribe una variable local (self.member = ...) funciona, porque esa es una llamada a método que modifica algún diccionario).

+0

Todo en Python es una referencia. Asignar a uno mismo simplemente vuelve a enlazar el nombre. – katrielalex

+0

@katrielalex: Sí, cada variable es una referencia, pero Python pasa estas referencias (o punteros, en C/C++) por valor. – delnan

1

Las cadenas de Python (y cualquier cosa que herede de ellas) son inmutables.

Hay una clase llamada MutableString en el módulo UserString que puede hacer lo que quiera.

Si está utilizando una versión reciente (como en 2.7/3.1) de python, también puede consultar bytearray, aunque tiene su propio conjunto de límites y peculiaridades.

0

Aquí es una implementación de lo que quiere hacer:

Puede extender esta clase con más métodos.

+0

Su ejemplo solo funciona si 'subclase' 'object' en lugar de' str'. – mwolfe02

+0

Gracias, editado. Estuve tentado de heredar todos los métodos predeterminados de 'str'. Pero, no sabía que no funcionaría si añadía un método personalizado. ¿No podemos agregar nuestros propios métodos si heredamos 'str'? – dheerosaur

Cuestiones relacionadas