Составные функции в python — двойная компоновка

#python #lambda #functional-programming #higher-order-functions

#python #лямбда #функциональное программирование #функции более высокого порядка

Вопрос:

Я столкнулся со следующей проблемой домашнего задания:

введите описание изображения здесь

Мой код для этой проблемы был помечен неправильно, и когда я просмотрел предложенное решение, я не мог понять, где я ошибся. Я запустил коды обеих функций в Python IDLE compiler только для того, чтобы увидеть, что обе функции возвращают один и тот же результат, как показано ниже:

 >>> def dual_function(f,g,n): #Suggested solution
    def helper(x):
        f1,g1 = f,g
        if n%2==0:
            f1,g1=g1,f1
        for i in range(n):
            x=f1(x)
            f1,g1=g1,f1
        return x
    return helper

>>> def dual_function_two(f,g,n): #My solution
    def helper(x):
        if n%2==0:
            for i in range (n):
                if i%2==0:
                    x = g(x)
                else:
                    x = f(x)
        else:
            for i in range(n):
                if i%2==0:
                    x = f(x)
                else:
                    x = g(x)
        return x
    return helper

>>> add1 = lambda x: x 1
>>> add2 = lambda x: x 2
>>> dual_function(add1,add2,4)(3)
9
>>> dual_function_two(add1,add2,4)(3)
9
>>> 
  

Я был бы признателен, если бы кто-нибудь мог определить ошибку в моем решении. Спасибо.

Комментарии:

1. Знаете ли вы тестовые примеры, используемые для оценки вашей проблемы? Я не могу найти ни одного случая, когда эти две функции различались.

2. Это не очень хорошие тестовые функции, поскольку сложение является коммутативным — если вы вызовете их в неправильном порядке, вы не заметите разницы. Но я попытался смешать сложение и умножение, и я также не смог найти разницы.

3. Вероятно, это намного медленнее, чем предлагаемое решение из-за постоянных операций по модулю. Замена будет намного быстрее.

4. @Sebastian К сожалению, у меня нет тестовых примеров : (

5. @Barmar Спасибо, что сообщили мне об использовании коммутативных операторов в таких функциях, буду помнить о них при работе над подобными проблемами в будущем.

Ответ №1:

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

 def dual (f, g, n):
  if n == 0:
    return lambda x: x
  else:
    return lambda x: f(dual(g, f, n - 1)(x))

add1 = lambda x: 1   x
add2 = lambda x: 2   x

print(dual(add1,add2,4)(3))
# 9
# (1   2   1   2   3)

print(dual(add1,add2,9)(3))
# 16
# (1   2   1   2   1   2   1   2   1   3)

print(dual(add1,add2,0)(3))
# 3
  

Причина, по которой это работает, заключается в том, что в рекурсивной ветви мы вызываем dual с замененными аргументами, dual(g,f,n-1) . Таким образом, f и g каждый раз меняются местами по мере n уменьшения до 0 базового варианта, который возвращает функцию идентификации (без операции).

Немного менее читаемая версия, но работает идентично —

 def dual (f, g, n):
  return lambda x: 
    x if n == 0 else f(dual(g, f, n - 1)(x))
  

Комментарии:

1. Отлично, никогда не знал, что я могу быть таким простым. Спасибо за объяснение! 🙂