我正在尝试对 str 对象进行子类化,并为其添加几个方法。我的主要目的是学习如何去做。
UserString 是在可以直接继承 str 之前创建的,因此更喜欢继承 str,而不是使用 UserString(正如另一个答案所暗示的那样)。
当子类化不可变对象时,通常需要在实例化对象之前修改数据 - 因此您需要同时实现__new__ 并调用父对象__new__(最好使用super , 而不是 str.__new__ 另一个答案建议)。
在 Python 3 中,像这样调用 super 会更高效:
class Caps(str):
def __new__(cls, content):
return super().__new__(cls, content.upper())
__new__ 看起来像一个类方法,但它实际上是作为静态方法实现的,所以我们需要将cls 作为第一个参数冗余传递。但是,我们不需要 @staticmethod 装饰器。
如果我们像这样使用super 来支持Python 2,我们会更清楚地注意到多余的cls:
class Caps(str):
def __new__(cls, content):
return super(Caps, cls).__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().__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!!!')
回复评论
为什么只调用 Python 3,即 super().method(arg) 更高效?
该函数已经可以访问__class__ 和self,而无需进行全局和本地查找:
class Demo:
def foo(self):
print(locals())
print(__class__)
>>> Demo().foo()
{'self': <__main__.Demo object at 0x7fbcb0485d90>, '__class__': <class '__main__.Demo'>}
<class '__main__.Demo'>
请参阅source 了解更多信息。