How do I create new methods and attributes for built-in datatypes in python? [duplicate]

I want to create new methods for str datatype. Here's what I tried

class str(str):
    def __init__(self) -> None:
        super().__init__()

    def work(self):
        # Just for testing
        print("works")

Here, when I initialize strings using str() this works but wrapping them around simple quotation this raises the error AttributeError: 'str' object has no attribute 'work'

Like this:

b = str("Hello world")
b.work()

Works as intended with stdout "works"

but,

a = "Hello world"
a.work()

Raises AttributeError: 'str' object has no attribute 'work'

I want to create new methods such that they work with these cases :

"foo".work()
str("foo").work() # <- This actually works :D
bar = "foo"; bar.work()

Thanks for the help.


Solution 1:

This can't be done, since str is one of the immutable types in Python. Among the immutable types are bool, int, float, tuple, string, frozenset and perhaps a few more I don't know about.

With other types, you might be able to do something like this:

class MyClass:
    def __str__(self):
        return "my class"


def print_me_quoted(self):
    print(f'"{self}"')

mc_old = MyClass()
MyClass.print_me_quoted = print_me_quoted
mc_new = MyClass()

# both now have it
mc_old.print_me_quoted()
mc_new.print_me_quoted()

It's still a spectacularly bad idea, to change the behaviour of a class by monkey-patching it like this, but it can be done. Expect your editor or IDE not to like it, or to understand it - you'll see warnings.

If you try this with str:

def print_me_quoted(self):
    print(f'"{self}"')


str.print_me_quoted = print_me_quoted
mc = str(10)
mc.print_me_quoted()

You get this TypeError:

TypeError: cannot set 'print_me_quoted' attribute of immutable type 'str'

You could do it on your own version of str:

class Str(str):
    ...


def print_me_quoted(self):
    print(f'"{self}"')


Str.print_me_quoted = print_me_quoted
mc = Str(10)
mc.print_me_quoted()

But of course that does not change the standard behaviour of strings - which is exactly the point.