2

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.

7
  • 4
    I would strongly recommend not doing this in this way. Maybe create a new class Str that's a subclass of str, but don't call the subclass the same thing as the parent class, as it will only lead to confusion when reading your code, and you'll run into problems like this. Commented Jan 16, 2022 at 5:29
  • Is this in part a spelling issue? self.words instead of self.works? Commented Jan 16, 2022 at 5:30
  • The various ways in which Python creates string objects, such as quoted literals in your source code, directly call the C-language implementation of the str class - the name "str" is not looked up in the process, there is absolutely nothing you can do from Python code to change this behavior. Commented Jan 16, 2022 at 5:32
  • 2
    not really, the words was supposed to be used later. I should edit the post to avoid confusion. Thanks for the comment, @esramish. Commented Jan 16, 2022 at 5:33
  • 1
    Have a look at the duplicate. This is possible to do using implementation knowledge, or the forbiddenfruit package (which basically knows how these types work). Commented Jan 16, 2022 at 9:54

1 Answer 1

2

Edit, this previously said "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."

However, that's incorrect - those are types for immutable objects, but str (as list and dict) are built-in types and are immutable types.

For example:

def append(self, *args, **kwargs):
    print("not appending")


list.append = append

xs = []
xs.append(1)

Will cause the error:

TypeError: cannot set 'append' attribute of immutable type 'list'

So, although an object of type list is mutable, the type list itself is not mutable, unlike a type you might define yourself, or that was defined in one of the many packages in Python.

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.

Sign up to request clarification or add additional context in comments.

6 Comments

@freekdebruijn before I go and revert your edit - how do you figure list to be immutable?
The list class is not - easily - mutable (in the context of the question), since it is defined in C. See for example stackoverflow.com/questions/7507350/… and stackoverflow.com/questions/6738987/…. It is possible using the forbiddenfruit module (pypi.org/project/forbiddenfruit). A list object is mutable.
Sorry, but that's completely besides the point here. I'm reverting the edit and would refer you to docs.python.org/3/reference/datamodel.html: "An object’s mutability is determined by its type; for instance, numbers, strings and tuples are immutable, while dictionaries and lists are mutable." - the implementation details are immaterial.
The first paragraph is misleading. It cannot be done because str is a builtin type, not because strings are immutable in Python. Builtin types whose values are mutable like list, set and dict can't be monkeypatched like that either.
That's a good point, I'll have a look and improve the answer, thanks @Jasmijn
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.