我基于内置的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
答案 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)
您继承了str
对capitalize
的定义,该定义将忽略您的类的行为,而仅使用“真实” 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
和其他字符串方法。