Movatterモバイル変換


[0]ホーム

URL:


— FREE Email Series —

🐍 Python Tricks 💌

Python Tricks Dictionary Merge

🔒 No spam. Unsubscribe any time.

Browse TopicsGuided Learning Paths
Basics Intermediate Advanced
aialgorithmsapibest-practicescareercommunitydatabasesdata-sciencedata-structuresdata-vizdevopsdjangodockereditorsflaskfront-endgamedevguimachine-learningnewsnumpyprojectspythonstdlibtestingtoolsweb-devweb-scraping

Table of Contents

Custom Python Strings: Inheriting From str vs UserString

Custom Python Strings: Inheriting From str vs UserString

byLeodanis Pozo RamosReading time estimate 15mintermediatepython

Table of Contents

Remove ads

The Pythonstr class has many useful features that can help you out when you’re processingtext orstrings in your code. However, in some situations, all these great features may not be enough for you. You may need to createcustom string-like classes. To do this in Python, you can inherit from the built-instr class directly or subclassUserString, which lives in thecollections module.

In this tutorial, you’ll learn how to:

  • Create custom string-like classes by inheriting from thebuilt-instr class
  • Build custom string-like classes by subclassingUserString from thecollections module
  • Decide when to usestr orUserString to createcustom string-like classes

Meanwhile, you’ll write a few examples that’ll help you decide whether to usestr orUserString when you’re creating your custom string classes. Your choice will mostly depend on your specific use case.

To follow along with this tutorial, it’ll help if you’re familiar with Python’s built-instr class and its standard features. You’ll also need to know the basics ofobject-oriented programming andinheritance in Python.

Sample Code:Click here to download the free sample code that you’ll use to create custom string-like classes.

Creating String-Like Classes in Python

The built-instr class allows you to createstrings in Python. Strings are sequences of characters that you’ll use in many situations, especially when working with textual data. From time to time, the standard functionalities of Python’sstr may be insufficient to fulfill your needs. So, you may want to create custom string-like classes that solve your specific problem.

You’ll typically find at least two reasons for creating custom string-like classes:

  1. Extending the regular string by adding new functionality
  2. Modifying the standard string’s functionality

You can also face situations in which you need to both extendand modify the standard functionality of strings at the same time.

In Python, you’ll commonly use one of the following techniques to create your string-like classes. You can inherit from the Python built-instr class directly or subclassUserString fromcollections.

Note: Inobject-oriented programming, it’s common practice to use the verbsinherit andsubclass interchangeably.

One relevant feature of Python strings isimmutability, which means that you can’t modify themin place. So, when selecting the appropriate technique to create your own custom string-like classes, you need to consider whether your desired features will affect immutability or not.

For example, if you need to modify the current behavior of existing string methods, then you’ll probably be okay subclassingstr. In contrast, if you need to change how strings are created, then inheriting fromstr will demand advanced knowledge. You’ll have to override the.__new__() method. In this latter case, inheriting fromUserString may make your life easier because you won’t have to touch.__new__().

In the upcoming sections, you’ll learn the pros and cons of each technique so that you can decide which is the best strategy to use for your specific problem.

Inheriting From Python’s Built-instr Class

For a long time, it was impossible to inherit directly from Python types implemented inC. Python 2.2 fixed this issue. Now you cansubclass built-in types, includingstr. This new feature is quite convenient when you need to create custom string-like classes.

By inheriting fromstr directly, you can extend and modify the standard behavior of this built-in class. You can also tweak theinstantiation process of your custom string-like classes to perform transformations before new instances are ready.

Extending the String’s Standard Behavior

An example of requiring a custom string-like class is when you need to extend the standard Python strings with new behavior. For example, say that you need a string-like class that implements a new method to count the number of words in the underlying string.

In this example, your custom string will use the whitespace character as its default word separator. However, it should also allow you to provide a specific separator character. To code a class that fulfills these needs, you can do something like this:

Python
>>>classWordCountString(str):...defwords(self,separator=None):...returnlen(self.split(separator))...

This class inherits fromstr directly. This means that it provides the sameinterface as its parent class.

On top of this inherited interface, you add a new method called.words(). This method takes aseparator character as an argument that is passed on to.split(). Its default value isNone which willsplit on runs of consecutive whitespace. Then you call.split() with the target separator to split the underlying string into words. Finally, you use thelen() function to determine the word count.

Here’s how you can use this class in your code:

Python
>>>sample_text=WordCountString(..."""Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime...    mollitia, molestiae quas vel sint commodi repudiandae consequuntur...    voluptatum laborum numquam blanditiis harum quisquam eius sed odit...    fugiat iusto fuga praesentium optio, eaque rerum! Provident similique...    accusantium nemo autem. Veritatis obcaecati tenetur iure eius earum...    ut molestias architecto voluptate aliquam nihil, eveniet aliquid...    culpa officia aut! Impedit sit sunt quaerat, odit, tenetur error,...    harum nesciunt ipsum debitis quas aliquid."""...)>>>sample_text.words()68

Cool! Your.words() methods works fine. It splits the input text into words and then returns the word count. You can modify how this method delimits and processes words, but the current implementation works okay for this demonstrative example.

In this example, you haven’t modified the standard behavior of Python’sstr. You’ve just added new behavior to your custom class. However, it’s also possible to change the default behavior ofstr by overriding any of its default methods, as you’ll explore next.

Modifying the String’s Standard Behavior

To learn how to modify the standard behavior ofstr in a custom string-like class, say that you need a string class that alwaysprints its letters in uppercase. You can do this by overriding the.__str__()special method, which takes care of how string objects are printed.

Here’s anUpperPrintString class that behaves as you need:

Python
>>>classUpperPrintString(str):...def__str__(self):...returnself.upper()...

Again, this class inherits fromstr. The.__str__() method returns a copy to the underlying string,self, with all of its letters in uppercase. To transform the letters, you use the.upper() method.

To try out your custom string-like class, go ahead and run the following code:

Python
>>>sample_string=UpperPrintString("Hello, Pythonista!")>>>print(sample_string)HELLO, PYTHONISTA!>>>sample_string'Hello, Pythonista!'

When you print an instance ofUpperPrintString, you get the string in uppercase letters on your screen. Note that the original string wasn’t modified or affected. You only changed the standard printing feature ofstr.

Tweaking the Instantiation Process ofstr

In this section, you’ll do something different. You’ll create a string-like class that transforms the original input string before making the final string object. For example, say that you need a string-like class that stores all of its letters in lowercase. To do this, you’ll try to override the class initializer,.__init__(), and do something like this:

Python
>>>classLowerString(str):...def__init__(self,string):...super().__init__(string.lower())...

In this code snippet, you provide an.__init__() method that overrides the defaultstr initializer. Inside this.__init__() implementation, you usesuper() to access the parent class’s.__init__() method. Then you call.lower() on the input string to convert all of its letters into lowercase letters before initializing the current string.

However, the above code doesn’t work, as you’ll confirm in the following example:

Python
>>>sample_string=LowerString("Hello, Pythonista!")Traceback (most recent call last):...TypeError:object.__init__() takes exactly one argument...

Sincestr objects are immutable, you can’t change their value in.__init__(). This is because the value is set during object creation and not during object initialization. The only way to transform the value of a given string during the instantiation process is to override the.__new__() method.

Here’s how to do this:

Python
>>>classLowerString(str):...def__new__(cls,string):...instance=super().__new__(cls,string.lower())...returninstance...>>>sample_string=LowerString("Hello, Pythonista!")>>>sample_string'hello, pythonista!'

In this example, yourLowerString class overrides the super class’s.__new__() method to customize how instances are created. In this case, you transform the input string before creating the newLowerString object. Now your class works as you need it to. It takes a string as input and stores it as a lowercase string.

If you ever need to transform the input string at instantiation time, then you’ll have to override.__new__(). This technique will require advanced knowledge of Python’sdata model and special methods.

SubclassingUserString Fromcollections

The second tool that allows you to create custom string-like classes is theUserString class from thecollections module. This class is a wrapper around the built-instr type. It was designed to develop string-like classes when it wasn’t possible to inherit from the built-instr class directly.

The possibility of directly subclassingstr means you might have less need forUserString. However, this class is still available in thestandard library, both for convenience and backward compatibility. In practice, this class also has some hidden features that can be helpful, as you’ll learn soon.

The most relevant feature ofUserString is its.data attribute, which gives you access to the wrapped string object. This attribute can facilitate the creation of custom strings, especially in cases where your desired customization affects the string mutability.

In the following two sections, you’ll revisit the examples from previous sections, but this time you’ll be subclassingUserString instead ofstr. To kick things off, you’ll start by extending and modifying the standard behavior of Python strings.

Extending and Modifying the String’s Standard Behavior

Instead of subclassing the built-instr class, you could implementWordCountString andUpperPrintString by inheriting from theUserString class. This new implementation will only require you to change the superclass. You won’t have to change the original internal implementation of your classes.

Here are new versions ofWordCountString andUpperPrintString:

Python
>>>fromcollectionsimportUserString>>>classWordCountString(UserString):...defwords(self,separator=None):...returnlen(self.split(separator))...>>>classUpperPrintString(UserString):...def__str__(self):...returnself.upper()...

The only difference between these new implementations and the original ones is that now you’re inheriting fromUserString. Note that inheriting fromUserString requires you toimport the class from thecollections module.

If you try out these classes with the same examples as before, then you’ll confirm that they work the same as their equivalent classes based onstr:

Python
>>>sample_text=WordCountString(..."""Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime...    mollitia, molestiae quas vel sint commodi repudiandae consequuntur...    voluptatum laborum numquam blanditiis harum quisquam eius sed odit...    fugiat iusto fuga praesentium optio, eaque rerum! Provident similique...    accusantium nemo autem. Veritatis obcaecati tenetur iure eius earum...    ut molestias architecto voluptate aliquam nihil, eveniet aliquid...    culpa officia aut! Impedit sit sunt quaerat, odit, tenetur error,...    harum nesciunt ipsum debitis quas aliquid."""...)>>>sample_text.words()68>>>sample_string=UpperPrintString("Hello, Pythonista!")>>>print(sample_string)HELLO, PYTHONISTA!>>>sample_string'Hello, Pythonista!'

In these examples, your new implementations ofWordCountString andUpperPrintString work the same as the old ones. So, why should you useUserString rather thanstr? Up to this point, there’s no apparent reason for doing this. However,UserString comes in handy when you need to modify how your strings are created.

Tweaking the Instantiation Process ofUserString

You can code theLowerString class by inheriting fromUserString. By changing the parent class, you’ll be able to customize the initialization process in the instance initializer,.__init__(), without overriding the instance creator,.__new__().

Here’s your new version ofLowerString and how it works in practice:

Python
>>>fromcollectionsimportUserString>>>classLowerString(UserString):...def__init__(self,string):...super().__init__(string.lower())...>>>sample_string=LowerString("Hello, Pythonista!")>>>sample_string'hello, pythonista!'

In the example above, you’ve made running transformations on the input string possible by usingUserString instead ofstr as your superclass. The transformations are possible becauseUserString is a wrapper class that stores the final string in its.data attribute, which is the real immutable object.

BecauseUserString is a wrapper around thestr class, it provides a flexible and straightforward way to create custom strings with mutable behaviors. Providing mutable behaviors by inheriting fromstr is complicated because of the class’s natural immutability condition.

In the following section, you’ll useUserString to create a string-like class that simulates amutable string data type.

Simulating Mutations in Your String-Like Classes

As a final example of why you should haveUserString in your Python tool kit, say that you need a mutable string-like class. In other words, you need a string-like class that you can modify in place.

Unlikelists anddictionaries, strings don’t provide the.__setitem__() special method, because they’re immutable. Your custom string will need this method to allow you to update characters andslices by their indices using anassignment statement.

Your string-like class will also need to change the standard behavior of common string methods. To keep this example short, you’ll only modify the.upper() and.lower() methods. Finally, you’ll provide a.sort() method to sort your string in place.

Standard string methods don’t mutate the underlying string. They return a new string object with the required transformation. In your custom string, you need the methods to perform their changes in place.

To achieve all these goals, fire up your favoritecode editor, create a file namedmutable_string.py, and write the following code:

Pythonmutable_string.py
 1fromcollectionsimportUserString 2 3classMutableString(UserString): 4def__setitem__(self,index,value): 5data_as_list=list(self.data) 6data_as_list[index]=value 7self.data="".join(data_as_list) 8 9def__delitem__(self,index):10data_as_list=list(self.data)11deldata_as_list[index]12self.data="".join(data_as_list)1314defupper(self):15self.data=self.data.upper()1617deflower(self):18self.data=self.data.lower()1920defsort(self,key=None,reverse=False):21self.data="".join(sorted(self.data,key=key,reverse=reverse))

Here’s how this code works line by line:

  • Line 3 importsUserString fromcollections.

  • Line 5 createsMutableString as a subclass ofUserString.

  • Line 6 defines.__setitem__(). Python calls this special method whenever you run an assignment operation on a sequence using an index, like insequence[0] = value. This implementation of.__setitem__() turns.data into a list, replaces the item atindex withvalue, builds the final string using.join(), and assigns its value back to.data. The whole process simulates an in-place transformation or mutation.

  • Line 11 defines.__delitem__(), the special method that allows you to use thedel statement for removing characters by index from your mutable string. It’s implemented similar to.__setitem__(). On line 13, you usedel to delete items from the temporary list.

  • Line 16 overridesUserString.upper() and callsstr.upper() on.data. Then it stores the result back in.data. Again, this last operation simulates an in-place mutation.

  • Line 19 overridesUserString.lower() using the same technique as in.upper().

  • Line 22 defines.sort(), which combines the built-insorted() function with thestr.join() method to create a sorted version of the original string. Note that this method has the same signature aslist.sort() and the built-insorted() function.

That’s it! Your mutable string is ready! To try it out, get back to your Python shell and run the following code:

Python
>>>frommutable_stringimportMutableString>>>sample_string=MutableString("ABC def")>>>sample_string'ABC def'>>>sample_string[4]="x">>>sample_string[5]="y">>>sample_string[6]="z">>>sample_string'ABC xyz'>>>delsample_string[3]>>>sample_string'ABCxyz'>>>sample_string.upper()>>>sample_string'ABCXYZ'>>>sample_string.lower()>>>sample_string'abcxyz'>>>sample_string.sort(reverse=True)>>>sample_string'zyxcba'

Great! Your new mutable string-like class works as expected. It allows you to modify the underlying string in place, as you would do with a mutable sequence. Note that this example covers a few string methods only. You can play with other methods and continue providing your class with new mutability features.

Conclusion

You’ve learned to createcustom string-like classes with new or modified behaviors. You’ve done this by subclassing the built-instr class directly and by inheriting fromUserString, which is a convenient class available in thecollections module.

Inheriting fromstr and subclassingUserString are both suitable options when it comes to creating your own string-like classes in Python.

In this tutorial, you’ve learned how to:

  • Create string-like classes by inheriting from thebuilt-instr class
  • Build string-like classes by subclassingUserString from thecollections module
  • Decide when to subclassstr orUserString to create yourcustom string-like classes

Now you’re ready to write custom string-like classes, which will allow you to leverage the full power of this valuable and commonplace data type in Python.

Sample Code:Click here to download the free sample code that you’ll use to create custom string-like classes.

🐍 Python Tricks 💌

Get a short & sweetPython Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Python Tricks Dictionary Merge

AboutLeodanis Pozo Ramos

Leodanis is a self-taught Python developer, educator, and technical writer with over 10 years of experience.

» More about Leodanis

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

MasterReal-World Python Skills With Unlimited Access to Real Python

Locked learning resources

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

MasterReal-World Python Skills
With Unlimited Access to Real Python

Locked learning resources

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Level Up Your Python Skills »

What Do You Think?

Rate this article:

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students.Get tips for asking good questions andget answers to common questions in our support portal.


Looking for a real-time conversation? Visit theReal Python Community Chat or join the next“Office Hours” Live Q&A Session. Happy Pythoning!

Keep Learning

Related Topics:intermediatepython

Keep reading Real Python by creating a free account or signing in:

Already have an account?Sign-In

Almost there! Complete this form and click the button below to gain instant access:

Custom Python Strings: Inheriting From str vs UserString

Custom Python Strings: Inheriting From str vs UserString (Sample Code)

🔒 No spam. We take your privacy seriously.


[8]ページ先頭

©2009-2026 Movatter.jp