如何在Python中子类化str
我正在尝试对 str 对象进行子类化,并向其添加几个方法。我的主要目的是学习如何去做。我陷入困境的是,我是否应该在元类中对 string 进行子类化,并使用该元创建我的类,或者直接对 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().lower()
据我了解,我需要实现__new__()
。我这么认为是因为,字符串方法可能会尝试创建新的 str 实例。因此,如果我覆盖 __new__(),他们应该会返回我的自定义 str 类。但是,在这种情况下,我不知道如何将参数传递给自定义类的 __init__() 方法。我想我需要使用 type()
才能在 __new__()
方法中创建一个新实例,对吗?
I am trying to subclass str object, and add couple of methods to it. My main purpose is to learn how to do it. Where I am stuck is, am I supposed to subclass string in a metaclass, and create my class with that meta, or subclass str directly?
And also, I guess I need to implement __new__()
somehow, because, my custom methods will modify my string object, and will return new mystr obj.
My class's methods, should be completely chainable with str methods, and should always return a new my class instance when custom methods modified it. I want to be able to do something like this:
a = mystr("something")
b = a.lower().mycustommethod().myothercustommethod().capitalize()
issubclass(b,mystr) # True
I want to have it all the abilities that a str
have. For example, a = mystr("something")
then I want to use it like,
a.capitalize().mycustommethod().lower()
It is my understanding that, I need to implement __new__()
. I think so because, strings methods would probably try to create new str instances. So , if I overwrite __new__()
, They supposedly would return my custom str class. However, I don't know how to pass arguments to my custom class's __init__()
method in that case. And I guess I would need to use type()
in order to create a new instance in __new__()
method right?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果您想在构造时修改字符串,则覆盖 __new__() 是有效的:
但如果您只想添加新方法,您甚至不必接触构造函数:
请注意,继承的方法,例如例如
upper()
仍会返回普通的str
,而不是text
。Overwriting
__new__()
works if you want to modify the string on construction:But if you just want to add new methods, you don't even have to touch the constructor:
Note that the inherited methods, like for example
upper()
will still return a normalstr
, nottext
.UserString
是在可以直接子类化str
之前创建的,因此更喜欢子类化str
,而不是使用UserString
(正如另一个答案所暗示的那样)。当子类化不可变对象时,通常需要在实例化对象之前修改数据 - 因此您需要实现 __new__ 并调用父级 __new__ (最好使用
super
,而不是另一个答案所建议的str.__new__
)。在Python 3中,像这样调用
super
性能更高:__new__
看起来像一个类方法,但它实际上是作为静态方法实现的,所以我们需要通过cls
冗余地作为第一个参数。但是,我们不需要@staticmethod
装饰器。如果我们像这样使用
super
来支持 Python 2,我们会更清楚地注意到冗余的cls
:用法:
完整的答案
到目前为止,没有一个答案能达到您的目的我们在这里请求:
我相信你的意思是
isinstance()
,而不是issubclass()
。)你需要一种方法来拦截字符串方法。
__getattribute__
就是这样做的。现在:
请求的案例有效:
对评论的回应
该函数已经可以访问
__class__
和self
而无需进行全局和本地查找:请参阅 来源 了解更多信息。
UserString
was created before it was possible to subclassstr
directly, so prefer to subclassstr
, instead of usingUserString
(as another answer suggests).When subclassing immutable objects, it's usually necessary to modify the data before you instantiate the object - therefore you need to both implement
__new__
and call the parent__new__
(preferably withsuper
, instead ofstr.__new__
as another answer suggests).In Python 3, it is more performant to call
super
like this:__new__
looks like a class method, but it is actually implemented as a static method, so we need to passcls
redundantly as the first argument. We don't need the@staticmethod
decorator, however.If we use
super
like this to support Python 2, we'll note the redundantcls
more clearly:Usage:
The complete answer
None of the answers so far does what you've requested here:
(I believe you mean
isinstance()
, notissubclass()
.)You need a way to intercept the string methods.
__getattribute__
does this.and now:
And the case requested works:
Response to Comment
The function already has access to both
__class__
andself
without doing a global and local lookup:See the source for more insight.
我对其他答案的复杂性感到有点震惊,Python 的标准库也是如此。您可以使用 collections.UserString 对字符串进行子类化,而不是弄乱了代理
str
的方法。只需对其进行子类化,然后添加您的方法即可。 self.data 包含对象所表示的实际字符串,因此您甚至可以通过在内部重新分配 self.data 来实现 str-“mutating”方法。
示例。
I'm kinda horrified by the complexity of the other answers, and so is Python's standard library. You can use collections.UserString to subclass string and do not mess with proxying
str
's methods.Just subclass it, and add your methods.
self.data
contains the actual string that is being represented by your object, so you can even implement str-"mutating" methods by reassigningself.data
internally.An example.
这是执行您想要的操作的快速技巧:您基本上拦截每个函数调用,并且,如果您看到它返回一个字符串,则将其转换回您自己的类类型。
虽然这在这个简单的示例中有效,但它有一些限制。除此之外,诸如下标运算符之类的运算符显然没有得到处理。
Here's a quick hack to do what you want: you basically intercept every function call, and, if you see that it's returning a string, you convert it back to your own class type.
While this works in this simple example, it has some limitations. Among other things, operators such as the subscript operator are apparently not handled.
您可以尝试类似的方法:
但您不确定标准方法也会返回“mystr”实例
You can try something like:
but you won't be sure that standard methods will return a 'mystr' instance too
这是我整理的一个替代方案,它不需要重写 __getattribute__ ,并且通过利用多重继承和
UserString
包装类更简单,但仍然作为 str 的实例传递:所以,测试:
在我的例子中,我需要一个具有特殊行为的字符串,但它仍然会作为 str 的实例传递,这样我无法控制的 JSON 编码器就不会抱怨我的对象不可序列化。
Here's an alternative I put together that does not need to override
__getattribute__
and is simpler by harnessing multiple inheritance and theUserString
wrapper class, but still passes as an instance of str:And so, the tests:
In my case, I needed a string with special behaviours but that would still pass as an instance of str so that a JSON encoder I can't control wouldn't carp that my object was not serializable.