How can I change the string object inside a string object?

144 Views Asked by At

I'm trying to create a mutable string object by just subclassing str (Unlike the answer to this other question).

Here's my code so far:

class mstr(str):

    def __new__(self, s):

        self.s = list(s)
        return str.__new__(self, s)

    def __getitem__(self, index):
        return self.s[index]

    def __setitem__(self, index, value):    
        self.s[index] = value

    def __eq__(self, other):
        return ''.join(self.s) == other

    def __ne__(self, other):
        return ''.join(self.s) != other

    def __lt__(self, other):
        return len(self.s) < len(other)

    def __gt__(self, other):
        return len(self.s) > len(other)

    def __le__(self, other):
        return len(self.s) <= len(other)

    def __ge__(self, other):
        return len(self.s) >= len(other)

    def __add__(self, other):
        return ''.join(self.s) + other

    def __mul__(self, other):
        return ''.join(self.s) * other

    def __hash__(self):
        return hash(''.join(self.s))

    def __str__(self):
        return ''.join(self.s)

def main():

    s = mstr("Hello ")
    s[5] = " World!"
    print(s)

if __name__ == '__main__':

    main()

By just outputting this example, it's easy to be fooled by the __ str __ return value:

Hello World! 

It's also easy to be fooled by the return value of __ add __ :

print(s + " Bloody madness!")

Output:

Hello World! Bloody madness!

But the immutable truth is revealed once we pass the mstr itself by the other argument of __ add __, as an example:

print(s + s)

Output:

Hello World!Hello 

Removing all the extra methods:

class mstr(str):

    def __new__(self, s):

        self.s = list(s)
        return str.__new__(self, s)

    def __setitem__(self, index, value):    
        self.s[index] = value
        self = ''.join(self.s) # Foolish attepmt.

Output of print(s) is just "Hello ".

So, how can I change the string object inside the string object? I mean, WHERE is the string actual and physical content stored in str or object or whatever? Wherever that is, I want to assign there.

1

There are 1 best solutions below

0
On BEST ANSWER

It's in here:

typedef struct {
    PyObject_VAR_HEAD
    long ob_shash;
    int ob_sstate;
    char ob_sval[1]; // This part. (Not actually one char.)

    /* ... */
} PyStringObject;

Unless you want to screw with the memory directly with ctypes or something, you can't get at it. If you do screw with it, weird things will break, because the assumption that that data is immutable isn't waived for string subclasses.