Повторное использование функции как метода с фиксированными аргументами и обновленным списком аргументов - PullRequest
0 голосов
/ 14 апреля 2020

Я пытаюсь разработать аккуратную структуру проекта. Я подумал, что аккуратно иметь расчеты, например:

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 здесь?

...