python可变字符串类无法正常工作

时间:2019-05-29 11:10:58

标签: python string

我基于内置的str类在Python中创建了一个可变的String类。

我可以更改第一个字符,但是当我调用capitalize()时,它将使用旧值代替

class String(str):

    def __init__(self, string):
        self.string = list(string)

    def __repr__(self):
        return "".join(self.string)

    def __str__(self):
        return "".join(self.string)

    def __setitem__(self, index, value):
        self.string[index] = value

    def __getitem__(self, index):
        if type(index) == slice:
            return "".join(self.string[index])
        return self.string[index]

    def __delitem__(self, index):
        del self.string[index]

    def __add__(self, other_string):
        return String("".join(self.string) + other_string)

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

text = String("cello world")
text[0] = "h"
print(text)
print(text.capitalize())
  

预期输出:

hello world

Hello world
     

实际输出:

hello world

Cello world

3 个答案:

答案 0 :(得分:1)

您的实现继承自str,因此它带来了str实现的所有方法。但是,str.capitalize()方法的实现并未考虑到这一点。像str.capitalize()这样的方法会返回 new str对象,并应用所需的更改。

此外,Python内置类型不将其状态存储在属性的__dict__映射中,而是使用internal struct data structures),仅在C级别上可访问;您的self.string属性不在(C equivalent of) str.__new__()存储字符串数据的位置。 str.capitalize()方法的返回值基于创建实例时存储在内部数据结构中的值,而该值不能从Python代码中更改。

您将必须隐藏所有返回新值的str方法,包括str.capitalize()才能表现不同。如果希望这些方法从返回新实例到就地更改值,则必须自己这样做:

class String(str):
    # ...

    def capitalize(self):
        """Capitalize the string, in place""" 
        self.string[:] ''.join(self.string).capitalize()
        return self  # or return None, like other mutable types would do

要做很多工作,为返回更新值的每种可能的str方法编写此类方法。相反,您可以使用__getattribute__钩子来重定向方法:

_MUTATORS = {'capitalize', 'lower', 'upper', 'replace'}  # add as needed

class String(str):
    # ...

    def __getattribute__(self, name):
        if name in _MUTATORS:
            def mutator(*args, **kwargs):
                orig = getattr(''.join(self.string), name)
                self.string[:] = orig(*args, **kwargs)
                return self  # or return None for Python type consistency
            mutator.__name__ = name
            return mutator
        return super().__getattribute__(name)

在上面的类中添加了__getattribute__方法的演示:

>>> text = String("cello world")
>>> text[0] = "h"
>>> print(text)
hello world
>>> print(text.capitalize())
Hello world
>>> print(text)
Hello world

一个侧面说明:__repr__方法应使用repr()返回正确的表示形式,而不仅仅是返回值:

def __repr__(self):
    return repr(''.join(self.string))

还要考虑到,大多数用C编码并以str值作为输入的Python API都可能使用C API for Unicode strings,因此不仅完全忽略了您的自定义实现,而且原始的str.capitalize()方法也将忽略self.string属性。相反,它们也将与内部str数据进行交互。

答案 1 :(得分:0)

您继承了strcapitalize的定义,该定义将忽略您的类的行为,而仅使用“真实” str的基础数据。

要从这样的内置类型有效地继承,需要您重新实现每个方法,或使用__getattribute__进行一些元编程;否则,基础类型的行为将被原样继承。

答案 2 :(得分:0)

这种方法不如已经建议的答案。之所以会产生更多开销,是因为您不能仅仅将事物作为列表进行跟踪,例如isinstance(s, str)就行不通。

完成此操作的另一种方法是子类collections.UserString。它是内置字符串类型的包装,将其存储为名为data的成员。所以你可以做类似的事情

from collections import UserString

class String(UserString):
    def __init__(self, string):
        super().__init__(string)
    def __setitem__(self, index, value):
        data_list = list(self.data)
        data_list[index] = value
        self.data = "".join(data_list)
    # etc.

然后您将免费获得capitalize和其他字符串方法。