[Python] Eliminate conditional branching by if by making full use of Enum and eval

Trigger

I was impressed by reading Mr. Masuda's How to write "case classification". It all started with trial and error, wondering if it could be done with Python. I intended to keep it in my own memo, but I thought that some people might have similar troubles, I decided to post.

When using if

As an example, consider the code to find the area of a shape.

def calculate_area(shape_type, shape_info):
    if shape_type == 'triangle':
        return shape_info['bottom'] * shape_info['height'] / 2

    if shape_type == 'rectangle':
        return shape_info['bottom'] * shape_info['height']

I'm not happy that the number of if statements in the function increases as the number of types of shapes increases. (This is a simple example, but it will be difficult to fix if the if is nested)

Prepare Class

Let's prepare a class for each figure as a preliminary preparation.

from abc import ABCMeta, abstractmethod

class Shape(metaclass=ABCMeta):
    def __init__(self, shape_info):
        self.shape_info = shape_info

    @abstractmethod
    def calculate_area(self):
        pass

class Triangle(Shape):
    def calculate_area(self):
        return self.shape_info['bottom'] * self.shape_info['height'] / 2

class Rectangle(Shape):
    def calculate_area(self):
        return self.shape_info['bottom'] * self.shape_info['height']

We have prepared Triangle class and Rectangle class. However, if this is all, which class is instantiated with if for each shape_type when calling It seems that it will be necessary to separate the cases.

if shape_type == 'triangle':
    shape = Triangle(shape_info)

if shape_type == 'rectangle':
    shape = Rectangle(shape_info)

Use Enum and eval

By using Enum, shape_type and class name can be linked, You can use eval to execute the contents of a string as it is in Python syntax.

class ShapeType(Enum):
    triangle = 'Triangle'
    rectangle = 'Rectangle'

    @classmethod
    def get_shape_instance(cls, shape_type, shape_info):
        return eval(cls[shape_type].value)(shape_info)

If you write it like this, you don't need to be aware of the implementation class. You can use ShapeType like an interface. When calling, it will be as follows.

shape = ShapeType.get_shape_instance(shape_type, shape_info)

Finally

Because this is my first post and I am still studying There may be some deficiencies in the text, but please forgive me. I hope this article helps someone.

Recommended Posts

[Python] Eliminate conditional branching by if by making full use of Enum and eval
Conditional branching of Python learned by chemoinformatics
[Introduction to Data Scientists] Basics of Python ♬ Conditional branching and loops
Extraction of tweet.js (json.loads and eval) (Python)
I want to revive the legendary Nintendo combination by making full use of AI and HR Tech!
Full understanding of Python threading and multiprocessing
python development environment -use of pyenv and virtualenv-
Python> Sort by number and sort by alphabet> Use sorted ()
Python asynchronous processing ~ Full understanding of async and await ~
Paiza Python Primer 2: Learn Conditional Branching and Comparison Operators
[Python of Hikari-] Chapter 08-03 Module (Import and use of standard library)
Python application: Data cleansing # 3: Use of OpenCV and preprocessing of image data
[Python] Summary of how to use split and join functions
Comparison of how to use higher-order functions in Python 2 and 3
[Python of Hikari-] Chapter 05-07 Control syntax (conditional branching of comprehension notation)
The process of making Python code object-oriented and improving it
[You have to know it! ] I tried to set up a Python environment profitably by making full use of the privileges of university students.