Мне нужно создать объект динамически. Здесь может помочь паттерн-строитель. Мой последний объект должен иметь (среди прочего) два метода: сортировку и цвет. Метод сортировки используется для сортировки (по возрастанию, убыванию, нет), метод цвета используется для возврата теплых или холодных цветов.
Мой последний объект должен иметь один метод сортировки и один метод цвета.
Я сконструировал что-то, что работает, но у меня такое чувство, что я решил это с помощью какого-то хака. Вот код:
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 ответ
Для такого приложения шаблон построителя может оказаться излишним. Вся ваша логика выполнения для сетевого объекта может выглядеть следующим образом.
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