Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Extending Enumerations With New Behavior

00:00 Extending enumerations with new behavior. You can provide your enumerations with new functionality by adding new methods to your enumeration classes, as you would do with any regular Python class.

00:13 Enumerations are classes with special features. Like regular classes, they can have methods and special methods. Consider this example adapted from the Python documentation.

00:30 Here you have a Mood enumeration with three members.

00:36 Regular methods such as .describe_mood() are bound to instances of their containing enum, which are the enum members, so you must call regular methods on enum members rather than on the enum class itself.

00:49 Remember that enumerations can’t be instantiated. The members of an enumeration are the enumeration’s allowed instances, so the .self parameter represents the current member.

01:00 Similarly, the .__str__() special method operates on members, providing a nicely printable representation of each member. Finally, the .favorite_mood() method is a class method which operates on the class or enumeration itself.

01:15 Class methods like this one provide access to all the enum members from inside the class. You

01:32 can take advantage of this ability to contain additional behavior when you need to implement the strategy pattern. For example, let’s say you need a class that allows you to use two strategies for sorting a list of numbers in ascending and descending order.

01:48 In this case, you can use an enumeration in this way. Each

02:11 member of Sort represents a sorting strategy. The .__call__() special method makes the members of Sort callable. Inside .__call__(), you use the built-in sorted() function to sort the input values in ascending or descending order depending on the called member.

02:28 This example is intended to demonstrate using an enum to implement the strategy design pattern. In practice, it’s unnecessary to create the SortEnum with the sole purpose of wrapping the sorted() function.

02:41 Instead, you may use sorted() and its reverse argument directly and avoid over-engineering the solution. When you call Sort.ASCENDING, the input numbers are sorted in ascending order.

02:54 In contrast, when you call Sort.DESCENDING, the numbers get sorted in descending order and that’s it. You’ve used an enumeration to quickly implement the strategy design pattern.

03:08 Python supports multiple inheritance as part of its object-oriented features. This means that in Python you can inherit from multiple classes. When creating class hierarchies, multiple inheritance comes in handy when you want to reuse functionality from several classes at the same time. A common practice in object-oriented programming is to use what’s known as mixin classes.

03:31 These classes provide functionality that other classes can use in Python. You can add mixin classes to the list of parents of a given class to automatically get the mixin functionality.

03:44 For example, let’s say you want an enumeration that supports integer comparison. In this case, you can use the built-in int type as a mixin when defining your enum.

03:59 In this example, the Size class inherits from both int and Enum. Inheriting from the int type enables direct comparison between members through the greater than, less than, greater than or equal to, and less than or equal to comparison operators.

04:17 It also enables comparisons between Size members and integer numbers. Note that when you use a data type as a mixin, the member’s .value attribute isn’t the same as the member itself, although it’s equivalent and will compare as such.

04:31 That’s why you can compare members of Size with integer numbers directly.

04:38 Using integer enum member values is a pretty common practice. That’s why the Enum module provides an IntEnum to create enumerations with integer values directly.

04:49 You’ll learn more about this later on in the course. The example you’ve just seen shows that creating enumerations with mixin classes is often of great help when you need to reuse a given piece of functionality.

05:02 If you decide to use this technique in some of your enums, then you’ll have to stick to the signature seen on screen. This signature implies that you can have one or more mixin classes, at most, one data type class, and the parent Enum class in that order.

05:20 Consider this example.

05:47 The ValidEnum class shows in the sequence of bases. You must place as many mixin classes as you need, but only one data type before Enum.

05:57 You can call methods in the mixin class,

06:02 the mixin B class, or str, and all work as expected. However, WrongMixinOrderEnum shows that if you put Enum in any position other than the last, then you’ll get a TypeError with information about the correct signature to use.

06:23 To many data types, Enum confirms that your list of mixin classes must have at most one concrete data type, such as int or str.

06:34 Keep in mind that if you use a concrete data type in your list of mixin classes, then the member values have to match this specific data type.

06:45 In the next section of the course, you’ll learn about other enumeration classes that are available.

Become a Member to join the conversation.