我正在尝试继承str对象,并为其添加几个方法。我的主要目的是学习如何做到这一点。我被困在哪里,我是否应该在元类中继承字符串,并使用该元或子类str直接创建我的类?
而且,我想我需要以某种方式实现__new__()
,因为我的自定义方法将修改我的字符串对象,并将返回新的mystr obj。
我的类的方法应该可以使用str方法完全链接,并且应该在自定义方法修改它时始终返回一个新的我的类实例。我希望能够做到这样的事情:
a = mystr("something")
b = a.lower().mycustommethod().myothercustommethod().capitalize()
issubclass(b,mystr) # True
我希望拥有str
拥有的所有能力。例如,a = mystr("something")
然后我想使用它,如,
a.capitalize()。mycustommethod()。下()
据我了解,我需要实施__new__()
。我想是这样的,因为,字符串方法可能会尝试创建新的str实例。所以,如果我覆盖__new__()
,他们应该会返回我的自定义str类。但是,在这种情况下,我不知道如何将参数传递给我的自定义类的__init__()
方法。我想我需要使用type()
才能在__new__()
方法中创建新实例吗?
答案 0 :(得分:32)
如果要修改构造中的字符串,则覆盖__new__()
有效:
class caps(str):
def __new__(cls, content):
return str.__new__(cls, content.upper())
但是如果你只是想添加新方法,你甚至不必触及构造函数:
class text(str):
def duplicate(self):
return text(self + self)
请注意,继承的方法(例如upper()
)仍会返回正常的str
,而不是text
。
答案 1 :(得分:12)
我试图继承str对象,并添加几个方法。我的主要目的是学习如何做到这一点。
不要将方法硬编码到父类(如最常见的答案)。相反,使用这样的super
来支持Python 2:
class Caps(str):
def __new__(cls, content):
return super(Caps, cls).__new__(cls, content.upper())
在Python 3中,像这样调用super
更高效,但它不向后兼容Python 2:
class Caps(str):
def __new__(cls, content):
return super().__new__(cls, content.upper())
用法:
>>> Caps('foo')
'FOO'
>>> isinstance(Caps('foo'), Caps)
True
>>> isinstance(Caps('foo'), str)
True
到目前为止,没有一个答案符合您的要求:
我的班级方法应该可以用str方法完全链接, 并且应该总是在自定义方法时返回一个新的我的类实例 修改它。我希望能够做到这样的事情:
a = mystr("something") b = a.lower().mycustommethod().myothercustommethod().capitalize() issubclass(b,mystr) # True
(我相信你的意思是isinstance()
,而不是issubclass()
。)
您需要一种方法来拦截字符串方法。 __getattribute__
这样做。
class Caps(str):
def __new__(cls, content):
return super(Caps, cls).__new__(cls, content.upper())
def __repr__(self):
"""A repr is useful for debugging"""
return f'{type(self).__name__}({super().__repr__()})'
def __getattribute__(self, name):
if name in dir(str): # only handle str methods here
def method(self, *args, **kwargs):
value = getattr(super(), name)(*args, **kwargs)
# not every string method returns a str:
if isinstance(value, str):
return type(self)(value)
elif isinstance(value, list):
return [type(self)(i) for i in value]
elif isinstance(value, tuple):
return tuple(type(self)(i) for i in value)
else: # dict, bool, or int
return value
return method.__get__(self) # bound method
else: # delegate to parent
return super().__getattribute__(name)
def mycustommethod(self): # shout
return type(self)(self + '!')
def myothercustommethod(self): # shout harder
return type(self)(self + '!!')
现在:
>>> a = Caps("something")
>>> a.lower()
Caps('SOMETHING')
>>> a.casefold()
Caps('SOMETHING')
>>> a.swapcase()
Caps('SOMETHING')
>>> a.index('T')
4
>>> a.strip().split('E')
[Caps('SOM'), Caps('THING')]
要求的案件有效:
>>> a.lower().mycustommethod().myothercustommethod().capitalize()
Caps('SOMETHING!!!')
答案 2 :(得分:8)
这是一个快速破解你想做的事情:你基本上拦截每个函数调用,如果你看到它返回一个字符串,你将它转换回你自己的类类型。
虽然这在这个简单的例子中起作用,但它有一些局限性。除其他外,下标运营商等运营商显然没有得到处理。
class FunWrapper(object):
def __init__(self, attr):
self.attr = attr
def __call__(self, *params, **args):
ret = self.attr(*params, **args)
if type(ret) is str:
return Foo(ret)
return ret
class Foo(object):
def __init__(self, string):
self.string = string
def __getattr__(self, attr):
return FunWrapper(getattr(self.string, attr))
def newMethod(self):
return "*%s*" % self.string.upper()
f = Foo('hello')
print f.upper().newMethod().lower()
答案 3 :(得分:8)
我对其他答案的复杂性感到震惊,python标准库也是如此。您可以使用collections.UserString来创建字符串子类,并且不要使用代理str
的方法。
只需将其子类化,然后添加您的方法。 self.data
包含由您的对象表示的实际字符串,因此您甚至可以实现str - " mutating"通过内部重新分配self.data
的方法。
答案 4 :(得分:0)
您可以尝试以下内容:
class mystr(str):
def new_method(self):
pass
但你不确定标准方法是否也会返回'mystr'实例