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

Unlock This Lesson

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

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Mixin Classes

Give Feedback

00:00 One of the great things about having access to multiple inheritance is that we can utilize what are called mixins. A mixin is a class that provides methods to other classes, but it’s not considered a base class itself.

00:18 This special class is going to expose some methods that the derived class can utilize—methods that will essentially be mixed in to the derived class.

00:31 When it comes to mixins, forget about the is a relationship. We’re not creating a specialized version of the mixin—we’re just inheriting from it so we can utilize one or more of its methods.

00:46 Let’s say you want to convert objects of certain types in your application to a dictionary representation. We could provide a .to_dict() method in each class, but the implementation of this method—or the code inside of it—is going to be identical for each class. Instead, let’s create a mixin class that defines that method and then we’ll make some other classes inherit from the mixin so they gain access to the method.

01:20 This mixin class will be like a utility, and as such, I don’t think we should code it in any of our existing modules. Instead, I’ll create a new module called representations, which will house this class.

01:38 The mixin will be called AsDictionaryMixin.

01:43 It’s only going to expose one method called .to_dict(), which will scan for all of the instance attributes in the object it’s being called on, and then return a dictionary where the keys are the attribute names and the values are the attribute values.

02:04 This is going to map an attribute name to its value, but in a convenient dictionary that we can work with. In order to do this, we’re going to have to use some fancy dictionary comprehension.

02:19 I’ll have a link down in the video notes if you’d like to learn more about this, but if you’re not familiar, just understand that this code will turn our instance attributes into a dictionary of attribute names and their associated values.

02:37 In fact, this self.__dict__.items() is a method that every custom class inherits from the object superclass, which returns a __dict__.items object that basically contains all the instance attributes and their values.

02:57 This is good, but you might notice that the code in this method is utilizing two other methods: ._represent() and ._is_internal().

03:11 We have to implement those methods too. The ._represent() method will attempt to return the dictionary representation of the value passed in.

03:25 I’m calling it ._represent() to indicate that this is a private method that should be used only within this class, notably by the .to_dict() method above. This method will be passed on to the child classes of this mixin, but the underscore (_) tells other developers not to use it outside this mixin class. It’s just a helper method, if you will.

03:53 Again, in the interest of not having this course be five hours long, I’m not going to walk through this line by line. But basically, this method will return the proper format of the passed-in value appropriate for a dictionary. This might be a string, or if the current object has a .to_dict() method itself—because it inherited from the mixin too—then it’ll return the dictionary generated by its .to_dict() method.

04:26 The last private method we need is ._is_internal(),

04:33 which will just filter out any instance attributes that are marked as private. All right. That’s it for the mixin class. To clarify how this actually works, let me utilize it in two other classes. First, I’m going to move over to the Employee class. Before I can use the mixin anywhere, I need to import it at the top.

05:03 Then, I can make the Employee class inherit from AsDictionaryMixin.

05:10 Remember, even though this is an inheritance relationship, the whole is a relationship we normally use does not apply here. The Employee is not an AsDictionaryMixinit simply inherits the .to_dict() method for use with this Employee object.

05:31 That’s it. I don’t want every instance attribute to be represented in the generated dictionary, and so I’m going to mark two attributes as private by appending an underscore (_) at the beginning of their names. If you remember from before, the dictionary comprehension code filters out any instance attributes that are marked as private, so these two instance attributes will not appear in our generated dictionary.

06:01 The other class I want to inherit from AsDictionaryMixin is the Address, which represents an employee address. That’s something that would make sense being represented as a dictionary.

06:16 I’ll move over to contacts.py and make the Address class inherit from our mixin.

06:29 Now, we’re ready to test. There’s a few ways we can do this, but I think the easiest would be to move over to program.py and comment out most of the code we have.

06:42 I’m using Visual Studio Code, so I can highlight the code I want to comment out and press Command + K + C. Other IDEs have this capability too, although the keyboard shortcut may be different.

06:58 Commenting out this code will allow us to temporarily disable it. This demo will utilize a bit of json, so I’ll import that at the top. I have a video course on JSON if you’d like to learn more about it.

07:14 I’ll move down below the commented-out code and define a one-liner method called print_dict(), which will take a dictionary and print it in JSON format.

07:29 Now, all that’s left to do is iterate through all of our Employee objects and print each one’s dictionary representation.

07:40 This works because the Employee class inherits the .to_dict() method from the mixin class, so every Employee object has access to it.

07:53 And as you can see, there’s the "id", the "name", and the "address" of each employee, encoded as a dictionary.

08:02 The ._role and ._payroll attributes we marked as private, and so they were filtered out of the dictionary representation. Also, notice that the address of each employee is a dictionary in and of itself.

08:18 That’s because we made the Address class inherit from AsDictionaryMixin, so it too was able to represent itself as a dictionary.

08:29 As you can see, mixins are a handy way to utilize multiple inheritance. They allow for the same method to be reused in multiple classes, and because they only inherit methods and not attributes, we don’t run the risk of causing any problems.

dejiok on April 19, 2020

Hi, thanks for this exellent video. Do you mind explaining this section of the code..

    def _represent(self, value):
        if isinstance(value, object):
            if hasattr(value, 'to_dict'):
                return value.to_dict()
            else:
                return str(value)
        else:
            return value

kbram on June 15, 2020

I am also interested in understanding this code. Can you respond with the link to explain the 19APR2020 comment?

Roy Telles on Aug. 16, 2020

From what I gather by the video’s small comments and looking up the code by line (where needed) this is what I came up with:

def _represent(self, value):
        if isinstance(value, object):
            if hasattr(value, 'to_dict'):
                return value.to_dict()
            else:
                return str(value)
        else:
            return value
  • if isinstance(value, object): checks if the value passed is an object (i.e. a class)
  • if hasattr(value, 'to_dict'): if it is a class, check if it has a to_dict attribute (more on this later)
    • return value.to_dict(): if it does have a 'to_dict' attribute, call that class’s to_dict method
    • NOTE: In previous lessons, we learned that methods can be referred to as attributes when not passed any arguments, hence methods can be referred to as attributes and hence hasattr() is used to make this check
  • else: return str(value): if there is no to_dict attribute in the class, return the string representation of the passed in value instead
  • else: return value: if the passed in value isn’t an instance of the object super class, return the value itself

In general this method seems to be checking 3 things:

  1. If value is a class, check for a to_dict method, if there is, call that class’ to_dict method
  2. If value is a class, but DOESN’T have a to_dict method, return the string representation of the value passed in (noted by str(value))
  3. If value ISN’T a class, return the value itself

As far as isinstance and hasattr are concerned, these are the tests I ran in a REPL:

>>> string = 'hello'
>>> isinstance(string, object)
True
>>> dir(string)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>> hasattr(string, 'isspace')
True
  • I passed in a string “value” into isinstance, checking to see that it’s an instance of the object super class (it is, as we know)
  • I checked to see what attributes the string class comes with by using dir(string) just to get a simple case example to use with hasattr
  • As an example I passed 'isspace' to hasattr to see what gets returned, and this seems to be a boolean that checks whether the value or class passed has the provided attribute

As far as why this check needs to be done in general, that’s beyond me, since as of Python 3 everything inherits from the object super class so it appears to me that isinstance(value, object) would always return true. But I was able to find this StackOverflow article about making your code “Python Agnostic” (adhering to both Python 2 and Python 3 syntax). Hope this helps :)

Become a Member to join the conversation.