samedi 2 janvier 2021

Python, how to build an object in more pythonic way?

I have a need to create object dynamically. Builder pattern could help here. My final object should have (among other things) two methods: sort and color. Sort method is used for sorting (ascending, descending, none), color method is used for returning warm or cold colors.

My final object should have one sort and one color method.

I have constructed something that works, but I have a feeling that I solved it by using kind of hack. Here is the code:

import abc
from typing import List

class Network:
    pass

class Builder(abc.ABC):

    @abc.abstractmethod
    def set_sort_func(self):
        pass

    @abc.abstractmethod
    def set_color_func(self):
        pass

    def get_product(self):
        return self._product

class NetworkBuilder(Builder):
    def __init__(self):
        self._product = Network()
        self._product.sort = self._sort_asc
        self._product.color = self._warm

    def set_sort_func(self, sort_func_name: str):
        sort_funcs = {
            'asc' : self._sort_asc,
            'desc': self._sort_desc,
            'none': self._sort_none
        }
        self._product.sort = sort_funcs[sort_func_name]
        return self

    def _sort_asc(self, lst: List):
        return sorted(lst, reverse=False)

    def _sort_desc(self, lst: List):
        return sorted(lst, reverse=True)

    def _sort_none(self, lst: List):
        return lst

    def set_color_func(self, color_func_name):
        color_methods = {
            'warm' : self._warm,
            'cold': self._cold
        }
        self._product.color = color_methods[color_func_name]
        return self

    def _warm(self, number: int):
        color =  'red' if number > 3 else 'orange' if number == 3 else 'yellow'
        return color

    def _cold(self, number: int):
        color =  'blue' if number > 3 else 'green' if number == 3 else 'black'
        return color

def show_obj_functioning(obj, data):
    sorted_data = obj.sort(data)
    print('sorted_data = ', sorted_data)
    for x in sorted_data:
        print(x, obj.color(x))


if __name__ == '__main__':

    data = [1,3,2,5,4]
    print('data = ', data)

    obj1 = (
        NetworkBuilder()
            .set_sort_func('asc')
            .set_color_func('warm')
            .get_product()
    )
    show_obj_functioning(obj1, data)

    obj2 = (
        NetworkBuilder()
            .set_sort_func('desc')
            .set_color_func('cold')
            .get_product()
    )
    show_obj_functioning(obj2, data)

    obj3 = (
        NetworkBuilder()
            .set_sort_func('none')
            .set_color_func('cold')
            .get_product()
    )
    show_obj_functioning(obj3, data)

    obj4 = (
        NetworkBuilder()
            .get_product()
    )
    show_obj_functioning(obj4, data)

As you can see, I have a NetworkBuilder object that contains all methods that I could need (_sort_asc, _sort_desc, _sort_none, _warm, _cold) and some methods for injecting chosen methods to final object (set_sort_func, set_color_func).

How to create an object in more pythonic way with no hacking?

Aucun commentaire:

Enregistrer un commentaire