[PYTHON] About the Visitor pattern

Introduction

I had the opportunity to implement the Visitor pattern in my work, and I didn't understand it clearly, so this is a summary of what I learned from the following books.

Overview

The Visitor pattern can separate data structure and processing.

The Visitor pattern is divided into a class that holds data and a class that implements the algorithm (Visitor class).

If you have a data structure in your application and some algorithms access that data structure,

The Visitor pattern allows data structures to focus on retaining and accessing data.

You can extend the functionality without modifying the existing class. (Principle of open / closed)

background

Many elements are stored in the data structure, and I want to do some processing for each element.

Where should I write the "processing" code at this time? If you write it in a class that represents a data structure ** The data structure class must be modified each time new processing is needed. ** **

The Visitor pattern is useful for solving the above problems.

Feature

According to Introduction to Design Patterns Learned in Java Language, the following relationships are associated with data structure classes and algorithms that describe algorithms. there is.

Let the class that holds the data structure be the Visitable class, and the class that describes the algorithm for the data structure be the Visitor class.

Define the visit (visitable) method in the Visitor class. In visit (), write the algorithm while accessing the attributes and behavior of the class of the data structure.

On the other hand, the Visitable class defines the ʻaccept (visitor) method. Within ʻaccept (visitor), call visit () of the Visitor object passed as the ** argument. ** **

Sample code

Describes a data structure class (Visitable class). Describes a class that holds list-type data and a class that holds dictionary-type data. Define a method (ʻaccept () `) that accepts the Visitor class in each class.

visitable.py


class VisitableList(list):

    def accept(self, visitor):
        visitor.visit_list(self)

class VisitableDict(dict):

    def accept(self, visitor):
        visitor.visit_dict(self)

Next, write the Visitor class that describes the algorithm. In the code below, the data held by the class of the data structure described above is simply output as standard.

visitor.py


class Printer(object):
    def visit_list(self, instance):
        print('The contents of the list: {}'.format(instance))

    def visit_dict(self, instance):
        print('Keys in the dictionary: {}'.format(
            ', '.join(instance.keys())
        ))

Then use the data structure class and the Visitor class as shown in the sample code below. Create an object of the data structure class, Data structure object .accept (Visitor object) It is described as.

main.py



def main():

    vistitable_list = VisitableList([1, 2, 3, 5])
    vistitable_list.accept(Printer())
    vistitable_dict = VisitableDict({'one': 1, 'two': 2, 'three': 3})
    vistitable_dict.accept(Printer())

if __name__ == "__main__":

    main()
$ python main.py
The contents of the list: [1, 2, 3, 5]
Keys in the dictionary: one, two, three

Connect Visitor and Visitor classes using the characteristics of introspection

Introspection is the nature and coverage of an object (object in this case). A feature that can be investigated to cover what is possible.

For example, referencing or retrieving "what properties have" for an object is called introspection.

The following code takes advantage of the characteristics of introspection and describes a class that connects the Visitor and Visitor classes.

class Connect():
    def __init__(self, visited, vistor):
        self.__cls = visited.__class__.__name__
        self.__method_name = 'visit_%s' % self.__cls
        self.__method = getattr(vistor, self.__method_name, None)
        
        # visit()Implemented
        self.__method(visited)

vistied.__class.___name__ and getattr () are introspections.

In the code below, implement it using the Printer class described above as well.

main.py


if __name__ == "__main__":

    Connect([1, 2, 3], Printer())
$ python main.py
The contents of the list: [1, 2, 3]
Keys in the dictionary: one, two, three

By using introspection, you don't have to implement accept () in your Visitable class.

Impressions

In Introduction to Design Patterns Learned in Java Language, as a basic form, Define ʻaccept ()in the data structure class and thevisit ()` method in the class that implements the algorithm. Then, within the defined method, we call each other's methods. (A technique called double dispatch)

In Expert Python Programming Revised 2nd Edition, in Python, the attributes of objects are dynamically It turns out that you can refer to, and as a result you can implement the Visitor pattern without using the accept () method.

In any case, I think it is necessary to implement the visit () method in the definition class (Visitor) after fully understanding the attributes and behavior of the class in the data structure.

References

Recommended Posts

About the Visitor pattern
About the test
About the queue
Learn the design pattern "Visitor" in Python
Visitor pattern in Python
About the Unfold function
About the service command
About the confusion matrix
About the Python module venv
About the ease of Python
About the enumerate function (python)
About the traveling salesman problem
About understanding the 3-point reader [...]
About the components of Luigi
About the features of Python
Think about the minimum change problem
Change the Flyweight pattern to Pythonic (?) (2)
About the Ordered Traveling Salesman Problem
About the return value of pthread_mutex_init ()
Implement the Singleton pattern in Python
About the return value of the histogram.
About the basic type of Go
About the upper limit of threads-max
Change the Flyweight pattern to Pythonic (?) (1)
About the average option in sklearn.metrics.f1_score
About the behavior of yield_per of SqlAlchemy
About the size of matplotlib points
About the basics list of Python basics
Roughly think about the loss function
About the matter that the re.compiled object can be used for the re.match pattern
I studied about design patterns (personal memo) Part 5 (Composite pattern, Decorator pattern, Visitor pattern)
Learn the design pattern "Builder" in Python
[Python Kivy] About changing the design theme
[Gang of Four] Design pattern learning --Visitor
Learn the design pattern "Flyweight" in Python
Learn the design pattern "Observer" in Python
Learn the design pattern "Memento" in Python
Learn the design pattern "Proxy" in Python
Miscellaneous notes about the Django REST framework
GoF design pattern from the problem 2. Structure
[OpenCV] About the array returned by imread
About the open source support group NumFOCUS
Learn the design pattern "Bridge" in Python
Learn the design pattern "Mediator" in Python
Learn the design pattern "Decorator" in Python
Roughly think about the gradient descent method
[Python] Summarize the rudimentary things about multithreading
About the development environment you are using
Learn the design pattern "Iterator" in Python
About the relationship between Git and GitHub
About the Normal Equation of Linear Regression
Learn the design pattern "Strategy" in Python
Learn the design pattern "Composite" in Python
Learn the design pattern "Singleton" with Python
Learn the design pattern "State" in Python
Learn the design pattern "Adapter" in Python
Learn the design pattern "Facade" with Python
GoF design pattern from the problem 3. Behavior
A note about doing the Pyramid tutorial