Python如何扩展“str”并重载其构造函数? [复制]

2023-12-20

我有一个字符序列,如果你愿意的话,可以是一个字符串,但我想存储有关字符串来源的元数据。另外我想提供一个简化的构造函数。

我尝试过延长str谷歌会为我解决尽可能多的课程。到了这个地步,我就放弃了;

class WcStr(str):
    """wc value and string flags"""

    FLAG_NIBBLES = 8 # Four Bytes

    def __init__(self, value, flags):
        super(WcStr, self).__init__()
        self.value = value
        self.flags = flags

    @classmethod
    def new_nibbles(cls, nibbles, flag_nibbles=None):
        if flag_nibbles is None:
            flag_nibbles = cls.FLAG_NIBBLES

        return cls(
            nibbles[flag_nibbles+1:],
            nibbles[:flag_nibbles]
        )

当我将两个参数注释掉时@classmethod的 cls() 调用它给了我这个错误:

TypeError: __init__() takes exactly 3 arguments (1 given)

非常典型,参数数量错误错误,

还有两个参数(例如,如示例代码所示):

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

我尝试过改变__init__的参数,super().__init__的参数,似乎都没有改变 ant 。

仅传递一个参数cls(...)调用,正如 str 类的错误所询问的那样,我得到这个:

TypeError: __init__() takes exactly 3 arguments (2 given)

所以我在这里赢不了,出了什么问题?


PS这应该是第二篇文章,但是 str 的原始字符串值被放入什么属性?我想尽可能少地重载 str 类,以将此元数据添加到构造函数中。


这正是__new__ https://docs.python.org/2/reference/datamodel.html#object.__new__方法是为了.

在Python中,创建一个对象实际上有两个步骤。在伪代码中:

value = the_class.__new__(the_class, *args, **kwargs)
if isinstance(value, the_class):
    value.__init__(*args, **kwargs)

这两个步骤称为构造和初始化。大多数类型不需要任何花哨的构造,因此它们可以只使用默认值__new__并定义一个__init__方法——这就是为什么教程等只提到__init__.

But str对象是不可变的,因此初始化程序无法执行设置属性等常规操作,因为您无法在不可变对象上设置属性。

所以,如果你想改变什么str实际上成立,你必须重写它__new__方法,并调用 super__new__与你修改后的参数。

在这种情况下,你实际上并不想这样做......但是你do想确定str.__new__没有看到你的额外参数,所以你still需要覆盖它,只是为了隐藏那些参数。


同时,你问:

str 的原始字符串值被放入什么属性?

事实并非如此。重点是什么?它的值是一个字符串,所以你会有一个str它有一个相同的属性str它有一个属性,等等无穷无尽。

当然,它必须在幕后存储某物。但那是在幕后。特别是,在 CPython 中,str类是用 C 实现的,除其他外,它还包含一个 Cchar *用于表示字符串的实际字节数组。您无法直接访问它。

但是,作为一个子类str,如果你想知道你的字符串值,那就是self。毕竟,这就是作为子类的全部意义。


So:

class WcStr(str):
    """wc value and string flags"""

    FLAG_NIBBLES = 8 # Four Bytes

    def __new__(cls, value, *args, **kwargs):
        # explicitly only pass value to the str constructor
        return super(WcStr, cls).__new__(cls, value)

    def __init__(self, value, flags):
        # ... and don't even call the str initializer 
        self.flags = flags

当然你并不真的need __init__这里;你可以在构建的同时进行初始化__new__。但如果你不打算flags作为一个不可变的、仅在构造期间设置的值,将其作为初始值设定项更具有概念意义,就像任何普通类一样。


同时:

我想尽可能少地重载 str 类

那可能不会达到你想要的效果。例如,str.__add__ and str.__getitem__将返回一个str,不是您的子类的实例。如果那很好,那么你就完成了。如果没有,您将必须重载所有这些方法并更改它们以使用适当的元数据包装返回值。 (您可以通过编程方式执行此操作,方法是在类定义时生成包装器,或者使用__getattr__动态生成包装器的方法。)


最后要考虑的一件事:str构造函数并不只接受一个参数。

可能需要 0:

str() == ''

而且,虽然这与 Python 2 无关,但在 Python 3 中它可能需要 2:

str(b'abc', 'utf-8') == 'abc'

另外,即使需要 1 个参数,它显然也不必是字符串:

str(123) == '123'

那么...您确定这是您想要的界面吗?也许你最好创建一个对象owns一个字符串(在self.value),并且只是明确地使用它。或者甚至隐式地使用它,鸭子类型作为str通过仅委托大部分或全部str方法self.value?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python如何扩展“str”并重载其构造函数? [复制] 的相关文章

随机推荐