在原地修改子类化字符串
我有一个字符串的子类:
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
我希望它能这样工作:
>>> x = S("My")
>>> x.conc("name")
'My name'
>>> x
'My name'
结果却是这样:
>>> x = S("My")
>>> x.conc("name")
'My name'
>>> x
'My'
有没有办法直接修改这个字符串? 我觉得这涉及到可变字符串和不可变字符串的区别。创建子类似乎是把字符串当作可变对象处理的正确方法(至少根据Python文档),但我觉得我的实现中缺少了一些关键的部分。
5 个回答
Python中的字符串(还有从字符串派生的任何东西)是不可变的,也就是说一旦创建了字符串,你就不能改变它的内容。
在UserString模块里有一个叫做MutableString的类,可能可以满足你的需求。
如果你使用的是比较新的Python版本(比如2.7或3.1),你也可以看看bytearray,虽然它有自己的一些限制和特点。
这一行代码 self = self + delimiter + next_val
是在创建一个新的变量 self
,并把 self + delimiter + next_val
的结果赋值给这个新的 self
。如果你想实现你想要的效果,你需要直接对原来的 self
变量进行操作。但因为字符串是不可变的(也就是说,一旦创建就不能改变),你无法这样做。这就是为什么所有的 str
方法都会返回一个新的字符串,而不是直接修改它们操作的字符串。
所以很抱歉,你无法实现你想要的效果。
你问的事情是做不到的,因为字符串是不可变的。文档里告诉你要包装一下str
类,也就是说你需要创建一个类,这个类里有一个属性,用来保存当前的“可变字符串”。在Python 2.x的标准库里有这个功能,叫UserString.MutableString
(不过在Python 3里就没有了);不过其实自己写一个也挺简单的:
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
不过,更好的办法是使用StringIO
。实际上,你可以通过继承StringIO
来实现你想要的功能(注意要使用纯Python版本,而不是C版本来做,而且它是旧式类,所以不能用super
)。这样做更整洁、更快,而且我觉得更优雅。
>>> 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
如果你想让x
看起来更像一个字符串,可以重写__repr__
,但这其实是不太好的做法,因为__repr__
的目的是返回对象在Python中的描述,尽量不要随便改。