Python, как построить объект более питоническим способом?

Мне нужно создать объект динамически. Здесь может помочь паттерн-строитель. Мой последний объект должен иметь (среди прочего) два метода: сортировку и цвет. Метод сортировки используется для сортировки (по возрастанию, убыванию, нет), метод цвета используется для возврата теплых или холодных цветов.

Мой последний объект должен иметь один метод сортировки и один метод цвета.

Я сконструировал что-то, что работает, но у меня такое чувство, что я решил это с помощью какого-то хака. Вот код:

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)

Как видите, у меня есть NetworkBuilder объект, содержащий все методы, которые мне могут понадобиться (_sort_asc, _sort_desc, _sort_none, _warm, _cold) и некоторые методы для внедрения выбранных методов в конечный объект (set_sort_func, set_color_func).

Я также пробовал решение с функциями:

import abc
from typing import List

funcs = {
    'sorting': {
        'asc': lambda lst: sorted(lst, reverse=False),
        'desc': lambda lst: sorted(lst, reverse=True),
        'none': lambda lst: lst,
    },
    'coloring': {
        'warm': lambda number: 'red' if number > 3 else 'orange' if number == 3 else 'yellow',
        'cold': lambda number: 'blue' if number > 3 else 'green' if number == 3 else 'black'
    }
}


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 = funcs['sorting']['asc']
        self._product.color = funcs['coloring']['warm']

    def set_sort_func(self, func_name):
        self._product.sort = funcs['sorting'][func_name]
        return self

    def set_color_func(self, func_name):
        self._product.color = funcs['coloring'][func_name]
        return self

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)

И объекты:

import abc
from typing import List

class Sorting:
    def __init__(self, func_name):
        funcs = {
            'asc': self._asc,
            'desc': self._desc,
            'none': self._none
        }
        self.sort = funcs[func_name]

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

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

    def _none(self, lst):
        return lst

class Coloring:
    def __init__(self, func_name):
        funcs = {
            'warm': self._warm,
            'cold': self._cold
        }
        self.color = funcs[func_name]

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

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


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 = Sorting('asc').sort
        self._product.color = Coloring('warm').color

    def set_sort_func(self, sort_func_name: str):
        self._product.sort = Sorting(sort_func_name).sort
        return self

    def set_color_func(self, color_func_name):
        return self

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)

Как создать объект более питоническим способом без взлома?

EDIT1 По словам Теда Браунлоу, я согласен, что это гораздо более простое решение. Меня просто немного беспокоит организация функций в словаре и обеспечение того, чтобы их подпись была одинаковой для одной и той же группы. В любом случае это гораздо более простое и чистое решение.

funcs = {
    'sorting': {
        'asc': lambda lst: sorted(lst, reverse=False),
        'desc': lambda lst: sorted(lst, reverse=True),
        'none': lambda lst: lst,
    },
    'coloring': {
        'warm': lambda number: 'red' if number > 3 else 'orange' if number == 3 else 'yellow',
        'cold': lambda number: 'blue' if number > 3 else 'green' if number == 3 else 'black'
    }
}

class Network:
    def __init__(self, sort, color):
        self.sort = sort
        self.color = color

def build_network(sort_name="asc", color_name="warm"):
    return Network(
        sort=funcs['sorting'][sort_name],
        color=funcs['coloring'][color_name]
    )

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 = build_network(sort_name="asc', color_name="warm")
    show_obj_functioning(obj1, data)

    obj2 = build_network(sort_name="desc", color_name="cold")
    show_obj_functioning(obj2, data)

    obj3 = build_network(sort_name="none", color_name="cold")
    show_obj_functioning(obj3, data)

    obj4 = build_network()
    show_obj_functioning(obj4, data)

/ EDIT1

1 ответ
1

Для такого приложения шаблон построителя может оказаться излишним. Вся ваша логика выполнения для сетевого объекта может выглядеть следующим образом.

class Network:
    def __init__(self, sort, color):
        self.sort = sort
        self.color = color

Точно так же сеть может быть построена с использованием очень простых запросов из вашей таблицы.

def build_network(sort_name="asc", color_name="warm"):
    return Network(
        sort=funcs['sorting'][sort_name],
        color=funcs['coloring'][color_name]
    )

Я бы сохранил функции сортировки и функции окраски как отдельные переменные, но разные штрихи для разных людей.

Тогда можно было бы использовать сетевой объект таким образом.

obj1 = build_network('asc','warm')
show_obj_functioning(obj1, data)

  • Я добавил раздел EDIT1 с вашим предложением. Это выглядит намного чище, чем мои идеи. Благодарю. У меня будут более сложные функции, чем сортировка или раскраска. В этом случае я определю функции, а затем помещу их в словарь. Чего мне здесь не хватает, так это обеспечения того, чтобы все функции имели одинаковую сигнатуру (параметры и их типы). Мне нужно что-то вроде интерфейса для этих функций.

    – user3225309

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *