从 str 或 int 继承

发布于 2024-08-29 21:02:27 字数 347 浏览 8 评论 0原文

为什么我在创建从 str(或从 int 继承)继承的类时遇到问题,

class C(str):
   def __init__(self, a, b):
     str.__init__(self,a)
     self.b = b

C("a", "B")

TypeError: str() takes at most 1 argument (2 given)

如果我尝试使用 int 而不是 str,也会发生同样的情况,但它适用于自定义类。我需要使用 __new__ 而不是 __init__?为什么?

Why I have problem creating a class inheriting from str (or also from int)

class C(str):
   def __init__(self, a, b):
     str.__init__(self,a)
     self.b = b

C("a", "B")

TypeError: str() takes at most 1 argument (2 given)

the same happens if I try to use int instead of str, but it works with custom classes. I need to use __new__ instead of __init__? why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

鼻尖触碰 2024-09-05 21:02:27
>>> class C(str):
...     def __new__(cls, *args, **kw):
...         return str.__new__(cls, *args, **kw)
... 
>>> c = C("hello world")
>>> type(c)
<class '__main__.C'>

>>> c.__class__.__mro__
(<class '__main__.C'>, <type 'str'>, <type 'basestring'>, <type 'object'>)

由于 __init__ 是在对象构造之后调用的,因此修改不可变类型的值就为时已晚。请注意,__new__是一个类方法,因此我调用了第一个参数cls

参见此处了解更多信息

>>> class C(str):
...     def __new__(cls, value, meta):
...         obj = str.__new__(cls, value)
...         obj.meta = meta
...         return obj
... 
>>> c = C("hello world", "meta")
>>> c
'hello world'
>>> c.meta
'meta'
>>> class C(str):
...     def __new__(cls, *args, **kw):
...         return str.__new__(cls, *args, **kw)
... 
>>> c = C("hello world")
>>> type(c)
<class '__main__.C'>

>>> c.__class__.__mro__
(<class '__main__.C'>, <type 'str'>, <type 'basestring'>, <type 'object'>)

Since __init__ is called after the object is constructed, it is too late to modify the value for immutable types. Note that __new__ is a classmethod, so I have called the first parameter cls

See here for more information

>>> class C(str):
...     def __new__(cls, value, meta):
...         obj = str.__new__(cls, value)
...         obj.meta = meta
...         return obj
... 
>>> c = C("hello world", "meta")
>>> c
'hello world'
>>> c.meta
'meta'
不知所踪 2024-09-05 21:02:27

继承内置类型很少值得。你必须处理几个问题,但你并没有真正获得太多好处。

使用组合几乎总是更好。您可以将 str 对象保留为属性,而不是继承 str

class EnhancedString(object):
     def __init__(self, *args, **kwargs):
         self.s = str(*args, **kwargs)

您可以使用 __getattr__ 手动或自动推迟任何您想要在底层 str self.s 上使用的方法。

话虽这么说,需要您自己的字符串类型应该会让您停下来。有许多类应该存储字符串作为其主要数据,但您通常希望使用 strunicode (如果您表示文本,则为后者)作为一般表示字符串。 (一个常见的例外是,如果您需要使用 UI 工具包的字符串类型。)如果您想向字符串添加功能,请尝试是否可以使用对字符串进行操作的函数而不是 >用作字符串的新对象,这使您的代码更简单并且与其他人的程序更兼容。

Inheriting built-in types is very seldom worth while. You have to deal with several issues and you don't really get much benefit.

It is almost always better to use composition. Instead of inheriting str, you would keep a str object as an attribute.

class EnhancedString(object):
     def __init__(self, *args, **kwargs):
         self.s = str(*args, **kwargs)

you can defer any methods you want to work on the underlying str self.s manually or automatically using __getattr__.

That being said, needing your own string type is something that should give you pause. There are many classes that should store a string as their main data, but you generally want to use str or unicode (the latter if you're representing text) for general representation of strings. (One common exception is if you have need to use a UI toolkit's string type.) If you want to add functionality to your strings, try if you can to use functions that operate on strings rather than new objects to serve as strings, which keeps your code simpler and more compatible with everyone else's programs.

千纸鹤带着心事 2024-09-05 21:02:27

当您实例化一个类时,您传入的参数将传递给该类的 __new__(构造函数),然后传递给该类的 __init__(初始化程序)方法。因此,如果您继承的类对实例化期间可能提供的参数数量有限制,则必须保证其 __new__ 和 __init__ 都不会获得更多参数比他们期望得到的。这就是你遇到的问题。您可以使用 C("a", "B") 实例化您的类。解释器在C中查找__new__方法。 C 没有它,因此 python 会查看它的基类 str。由于它有一个,因此该值与两个参数一起使用和提供。但是 str.__new__ 期望仅获得一个参数(除了作为第一个参数的类对象之外)。因此引发了 TypeError 。这就是为什么您必须在子类中扩展它,类似于使用 __init__ 所做的事情。但请记住,它必须返回类实例,并且它是一个静态方法(无论它是否使用 @staticmethod 装饰器定义),如果您使用超级功能。

When you instantiate a class, the arguments that you pass in, are passed to both the __new__ (constructor) and then to the __init__ (initializer) methods of the class. So if you inherit from a class that has restrictions on number of arguments that may be supplied during instantiation, you must guarantee that neither its __new__, nor its __init__ would get more arguments than they expect to get. So that is the problem that you have. You instantiate your class with C("a", "B"). The interpreter looks for __new__ method in C. C doesn't have it, so python peeps into its base class str. And as it has one, that one is used and supplied with the both arguments. But str.__new__ expects to get only one argument (besides its class object as the first argument). So TypeError is raised. That is why you must extend it in your child class similarly to what you do with __init__. But bear in mind that it must return class instance and that it is a static method (irrespective of whether it is defined with @staticmethod decorator or not) that counts if you use super function.

明月松间行 2024-09-05 21:02:27

如果是不可变类型,请使用 __new__ :

class C(str):
    def __new__(cls, content, b):
        return str.__new__(cls, content)

    def __str__(self):
        return str.__str__(self)

a=C("hello", "world")
print a

print 返回 hello 。

Python 字符串是不可变类型。调用函数__new__来创建对象C的新实例。 python __new__ 函数基本上存在于允许从不可变类型继承。

Use __new__ in case of immutable types:

class C(str):
    def __new__(cls, content, b):
        return str.__new__(cls, content)

    def __str__(self):
        return str.__str__(self)

a=C("hello", "world")
print a

print returns hello.

Python strings are immutable types. The function __new__ is called to create a new instance of object C. The python __new__ function is basically exists to allow inheritance from immutable types.

云柯 2024-09-05 21:02:27

仔细阅读 this 后,这是对 str 进行子类化的另一次尝试。其他答案的变化是使用 super(TitleText, cls).__new__ 在正确的类中创建实例。无论何时使用它,它的行为似乎都像 str,但它允许我重写一个方法:

class TitleText(str):
    title_text=""
    def __new__(cls,content,title_text):
        o=super(TitleText, cls).__new__(cls,content)
        o.title_text = title_text
        return o

    def title(self):
        return self.title_text

>>> a=TitleText('name','A nice name')
>>> a
'name'
>>> a[0]
'n'
>>> a[0:2]
'na'
>>> a.title()
'A nice name'

这可以让你正确地进行切片和下标。这是干啥用的?用于在管理索引页面中重命名 Django 应用程序。

After carefully reading this, here is another attempt at subclassing str. The change from other answers is creating the instance in the correct class using super(TitleText, cls).__new__ . This one seems to behave like a str whenever it's used, but has allowed me to override a method:

class TitleText(str):
    title_text=""
    def __new__(cls,content,title_text):
        o=super(TitleText, cls).__new__(cls,content)
        o.title_text = title_text
        return o

    def title(self):
        return self.title_text

>>> a=TitleText('name','A nice name')
>>> a
'name'
>>> a[0]
'n'
>>> a[0:2]
'na'
>>> a.title()
'A nice name'

This lets you do slicing and subscripting correctly. What's this for? For renaming the Django application in the admin index page.

真心难拥有 2024-09-05 21:02:27

上面已经回答了这个问题,这只是一个可能对某人有用的切线观察。

当我试图找到一种方法来在引用的字典被删除后删除临时文件时,我遇到了这个问题。

上下文是一个 Flask 会话:用户可以上传一些文件,但在有效提交将他/她的数据传输到最终目的地所需的整个工作流程之前放弃。在那之前,我将文件保存在临时目录中。假设用户放弃并关闭浏览器窗口,我不希望这些文件徘徊。

由于我将临时路径保留在 Flask 会话中——这只是一个最终会被删除(例如超时)的字典,因此我可以自定义一个 str 类来保存临时目录地址/路径,并且有其__del__方法处理临时目录删除。

就是这样:

class Tempdir(str):
    def __new__(cls, *args, **kwargs):
        from tempfile import mkdtemp
        _dir = mkdtemp()
        return super().__new__(cls, _dir)
    def __del__(self):
        from shutil import rmtree
        rmtree(str(self))

在你的 python 解释器/应用程序中实例化它:

> d = Tempfile()
> d
'/var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw'
> 
> import os
> os.path.exists(d)
True

当你退出解释器时:

$ ls /var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw
ls: /var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw: No such file or directory

就这样了。

The question was already answered above, this is just a tangential observation that may be useful to somebody.

I hit this question when trying to figure out a way to remove a temporary file after the dictionary it was being referred to goes deleted.

The context is a Flask session: the user can upload some files but give up before effectively commit the whole workflow it has to go through to get his/her data into the final destination. Until then, I keep the files in a temporary directory. Let's say the user give up and closes the browser window, I don't want those files lingering around.

Since I keep the temporary path in a Flask session -- which is just a dictionary that eventually goes deleted (e.g, timeout), I can customize a str class to hold the temporary directory address/path, and have its __del__ method handling the temporary directory deletion.

Here it goes:

class Tempdir(str):
    def __new__(cls, *args, **kwargs):
        from tempfile import mkdtemp
        _dir = mkdtemp()
        return super().__new__(cls, _dir)
    def __del__(self):
        from shutil import rmtree
        rmtree(str(self))

Instantiate it in your python interpreter/app:

> d = Tempfile()
> d
'/var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw'
> 
> import os
> os.path.exists(d)
True

When you exit the interpreter:

$ ls /var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw
ls: /var/folders/b1/frq3gywj3ljfqrf1yc7zk06r0000gn/T/tmptwa_g5fw: No such file or directory

There you go.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文