#python #software-design
Вопрос:
Имейте в виду, длинный вопрос.
У меня сложная проблема с дизайном в моем проекте на Python. Я попытаюсь упростить проблему, абстрагируясь от некоторых деталей. Я надеюсь, что моя проблема будет ясна. Если это не так, пожалуйста, попросите меня рассказать подробнее.
У меня есть несколько классов (давайте назовем Foo1
, Foo2
,… Foon
), которые являются подклассами Foo
класса. Foo
имеет вызываемый метод score()
. Каждый подкласс Foo
переопределяет score
метод.
Большинство методов оценки используют некоторые общие функции из другого модуля. Давайте назовем этот модуль lib
. lib
имеет некоторые функции, такие как f1(*args)
, f2(*args)
. Большинство из них очень просты, они просто вычисляют значение args
с помощью простых математических операций, а затем возвращают это значение.
Пример метода оценки:
def score():
retval = 0
retval = lib.f1(some_arguments)
retval = lib.f2(some_other_arguments)
return retval
Примерный lib.f
метод:
def f1(a, b, c):
return a b c
Общий поток примерно такой:
Основная функция вызывает foo1.score() (где foo1-объект подкласса Foo
), который вызывает некоторые lib
функции.
MainFunction
-> foo1.score()
-> lib.f1(*args)
, lib.f2(*args)
Пока все хорошо.
В этот момент я понял, что некоторые lib.f
функции (давайте назовем их lib.deep_f
функциями) не так просты. Некоторым из них необходимо вызвать одну или несколько функций оценки объектов Foo1, Foo2,…. Пример:
def deep_f1(foo_object):
value = 0
value = foo_object.score()
for other_foo_object in foo_object.neighbors:
value = other_foo_object.score()
return value
Таким образом, поток может стать следующим:
MainFunction
-> foo1.score()
-> lib.deep_f1(*args)
-> foo1.score()
, foo2.score
, … -> lib.deep_f1(*args)
-> …
As you can see, there is a problem: a method calls another method that calls itself again. They may call each other infinitely. To solve this problem, I added a control parameter to lib.deep_f
functions like deep_call
. If it is a deep call (That is, if the function is called as a result of a deep_f
function), I can return a predetermined value. So, I can change it as:
def deep_f1(foo_object, *, deep_call=False):
if deep_call:
return 7
value = 0
value = foo_object.score(deep_call=True)
for other_foo_object in foo_object.neighbors:
value = other_foo_object.score(deep_call=True)
return value
Also, I need to change all score methods that uses lib.deep_f
functions, to delegate the deep_call
parameter. So, the they will be similar to:
def score(deep_call=False):
retval = 0
retval = lib.deep_f1(self, deep_call=deep_call)
retval = lib.f1(some_arguments)
retval = lib.deep_f2(some_other_arguments, deep_call=deep_call)
return retval
If I do the mentioned modifications, it will work as expected. The problem is that the number of Foo
subclasses is very large. I need to add deep_call
parameter to all of them. Also, I’ll add new Foo
subclasses in the future. I will need to make these modifications on those classes as well. I think, there must be a better way. I guess, It may be done with Python context structures but I couldn’t find a solution. I imagine something as follows:
def deep_f1(foo_object, *, deep_call=False):
if deep_call:
return 7
value = 0
with context: # All deep_f function in this context should be called with deep_call=True
value = foo_object.score()
for other_foo_object in foo_object.neighbors:
value = other_foo_object.score()
return value
Но любое решение, которое избавит меня от изменения всех score()
методов, приемлемо. Спасибо.