Я пытаюсь разработать аккуратную структуру проекта. Я подумал, что аккуратно иметь расчеты, например:
def distance_per_leg(number_of_legs, stride_lenght, number_of_steps):
return number_of_steps * stride_length / number_of_legs
отдельно от различных типов объектов, с которыми они могут работать, например, следующих классов:
class AnimalWithLegs():
def __init__(self, number_of_legs):
self.number_of_legs = number_of_legs
human = AnimalWithLegs(2)
dog = AnimalWithLegs(4)
milipede = AnimalWithLegs(100)
class TypeOfStride():
def __init__(self, stride_length):
self.stride_length = stride_length
walk = TypeOfStride(50)
run = TypeOfStride(100)
Конечная цель - быть возможность вызывать функцию distance_per_leg
как метод для вышеуказанных классов, но таким образом, что она принимает число аргументов, уменьшенное атрибутом класса, например:
walk.distance_per_leg(number_of_legs = 2, number_of_steps = 4) # 4 * 50 / 2 = 200
milipede.distance_per_leg(stride_length = 1, number_of_steps = 4) # 4 * 1 / 100 = 0.04
Однако я хочу чтобы быть в состоянии сделать это:
- масштабируемым образом, без больших затрат на количество функций, таких как
distance_per_leg
или классов, таких как AnimalWithLegs,TypeOfStride, WalkLength
et c. - , сохраняющих интерактивность, т. е. я должен быть в состоянии просто написать
walk.distance_per_leg(2,4)
(т. е. использовать позиционные И ключевые аргументы) или сделать так, чтобы автозаполнение показывало исправленную строку документации, без предварительно загруженного аргумента вообще (т. е. walk.distance_per_leg(...
будет показывать только number_of_legs
и number_of_steps
) - сохранение параметров по умолчанию (обычно
None
)
Что я пробовал до сих пор:
- Создание метода, который принимает недостающие аргументы и вызовы функции n с аргументами и атрибутом класса
- не масштабируется (придется писать так для каждой функции, для каждого класса), но интерактивность сохраняется
- Создание функции Фабрика
- также не очень масштабируема (для каждой функции необходимо записать фабрику для комбинации параметров и исправлений, но она позволяет убрать беспорядок из определения класса
- Использование
functools.partial
- , что было очень обидно, потому что в результате частичные позиционные аргументы не меняются местами. Если вы исправите первый позиционный аргумент, то вы в основном застряли только с kwargs.
То, что я не пробовал из-за предела рекурсии моего мозга (простите за самоуничижение) шутка, это означает, что я чувствую, что это может быть каким-то образом, но не могу придумать, как его кодировать):
- Множественное наследование, как при структурировании функций как классов, которые инициализируются с некоторыми фиксированными параметрами?
- Больше уровней в заводской функции, по одному на каждый параметр функции?
Самое элегантное решение, которое приходит мне в голову, имеет форму:
def foo(a = None,
b = None,
c = None,
d = None):
return a * b * c * d
def func_with_params_fixed(func, kwargs_to_fix_and_delete):
...
return updated_func
bar = func_with_params_fixed(foo, {'a':1, 'b':2})
bar(3,4) # 24, here is where partial fails as it would raise TypeError: foo() got multiple values for argument 'a'
bar(c=3) # TypeError
bar(c=3,d=4) # 24, partial works only in this case
. ... или, возможно, мне следует переосмыслить всю структуру проекта, поскольку я, очевидно, что-то делаю против Pythoni c здесь?