Effective Python Learning Memorandum Day 12 [12/100]

Introduction

The other day I learned about 100 Days Of Code, which was popular on Twitter for a while. The purpose of this article is to keep a record and output how much I, as a beginner, can grow through 100 days of study. I think there are many mistakes and difficult to read. I would appreciate it if you could point out!

Teaching materials to be learned this time

--Chapter 8 structure --Page 216 of this chapter

Today's progress

--Progress: Pages 73-78 --Chapter 3: Classes and Inheritance ――I will write down what I often forget or didn't know about what I learned today.

Use multiple inheritance only for mix-in utility classes

Multiple inheritance shouldn't be used much, and mix-ins should be used instead.

What is a mix-in?

A small class that just defines a set of additional methods that the class should provide. Also, unlike regular classes, it doesn't have instance attributes and you don't even have to call the __init__ constructor.

Define the mix-in example as a new method added in any inherited class as follows.

class ToDictMixin(object):
    def to_dict(self):
        '''
Returns the attributes of this object as a dictionary
        '''

        return self._traverse_dict(self.__dict__)

    def _traverse_dict(self, instance_dict):
        '''
Receives a dictionary and returns a new dictionary output.

        Parameters
        ----------
        instance_dict: dict
        
        Returns
        -------
        output : dict
To the key, instance_To the key and value of dict_traverse()
        '''

        output = {}
        for key, value in instance_dict.items():
            output[key] = self._traverse(key, value)
        return output

    def _traverse(self, key, value):
        '''
Call the function according to the value type of the dictionary.
        '''
        
        if isinstance(value, ToDictMixin):
            return value.to_dict()
        elif isinstance(value, dict):
            return self._traverse_dict(value)
        elif isinstance(value, list):
            return [self._traverse(key, i) for i in value]
        elif hasattr(value, '__dict__'):
            return self._traverse_dict(value.__dict__)
        else: return value

Next, use this mix-in to define a class that creates a binary tree dictionary representation and output the object attributes.

class BinaryTree(ToDictMixin):
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

tree = BinaryTree(5,
    left=BinaryTree('aaa', right=BinaryTree(4)),
    right=BinaryTree(2.4, left=BinaryTree(8)))

#Display tree object attributes as a dictionary
print(tree.to_dict())

The advantage of mix-ins is that they are type independent and can override functionality when needed. For example, override the BinaryTree subclass above to hold a reference to the parent.

class BinaryTreeWithParent(BinaryTree):
    def __init__(self, value, left=None,
                 right=None, parent=None):
        super().__init__(value, left=left, right=right)
        self.parent = parent
    
    #The default implementation loops forever, so change it to handle only the values ​​you need
    def _traverse(self, key, value):
        '''
If the value type is BinaryTreeWithParent attribute and the key is parent class, value.Returns value,
Otherwise, of the parent class_Changed to do the same processing as traverse
        '''
        if (isinstance(value, BinaryTreeWithParent) and
                 key == 'parent'):
            return value.value    #Prevent the cycle
        else:
            return super()._traverse(key, value)

Print with pprint for readability

import pprint

root = BinaryTreeWithParent(5)
root.left = BinaryTreeWithParent(3, parent=root)
root.left.right = BinaryTreeWithParent(13, parent=root.left)
pprint.pprint(root.to_dict())

Output result

{'left': {'left': None,
          'parent': 5,
          'right': {'left': None, 'parent': 3, 'right': None, 'value': 13},
          'value': 3},
 'parent': None,
 'right': None,
 'value': 5}

By defining BinaryTreeWithParent._traverse, ToDictMixin will work automatically for all classes with attributes of type BinaryTreeWithParent.

class NamedSubTree(ToDictMixin):
    def __init__(self, name, tree_with_parent):
        self.name = name
        self.tree_with_parent = tree_with_parent

mytree = NamedSubTree('bbb',root.left.right)
pprint.pprint(mytree.to_dict())

Output result

{'name': 'bbb',
 'tree_with_parent': {'left': None, 'parent': 3, 'right': None, 'value': 13}}

Summary

--Basically, use mix-in rather than multiple inheritance --Customize each class when you need a mix-in class

Recommended Posts

Effective Python Learning Memorandum Day 15 [15/100]
Effective Python Learning Memorandum Day 6 [6/100]
Effective Python Learning Memorandum Day 12 [12/100]
Effective Python Learning Memorandum Day 9 [9/100]
Effective Python Learning Memorandum Day 8 [8/100]
Effective Python Learning Memorandum Day 14 [14/100]
Effective Python Learning Memorandum Day 1 [1/100]
Effective Python Learning Memorandum Day 13 [13/100]
Effective Python Learning Memorandum Day 3 [3/100]
Effective Python Learning Memorandum Day 5 [5/100]
Effective Python Learning Memorandum Day 4 [4/100]
Effective Python Learning Memorandum Day 7 [7/100]
Effective Python Learning Memorandum Day 2 [2/100]
Python learning day 4
Python memorandum
Python Memorandum 2
Python memorandum
python learning
python memorandum
python memorandum
Python day 1
Python memorandum
python memorandum
Python memorandum
Python basics memorandum
[Python] Learning Note 1
Python learning notes
Python pathlib memorandum
python learning output
Deep Learning Memorandum
Python learning site
Python Deep Learning
Python learning (supplement)
Deep learning × Python
Python memorandum [links]
python learning notes
Python study day 1
Machine learning starting with Python Personal memorandum Part1
Python memorandum numbering variables
Python class (Python learning memo ⑦)
Learning Python with ChemTHEATER 03
"Object-oriented" learning with python
Learning Python with ChemTHEATER 05-1
Python: Deep Learning Practices
Python ~ Grammar speed learning ~
python memorandum (sequential update)
Python: Unsupervised Learning: Basics
Learning record 4 (8th day)
Learning record 9 (13th day)
[1day1lang AdventCalender] day4 Python
Learning record 3 (7th day)
Learning record 5 (9th day)
Learning record 6 (10th day)
Python memorandum (personal bookmark)
Programming learning record day 2
Learning record 8 (12th day)
Learning record 1 (4th day)
Learning record 7 (11th day)
Private Python learning procedure
Learning Python with ChemTHEATER 02
Python basic memorandum part 2