Trabalhando com Funções em Python
Atribuindo Funções a Variáveis
Em Python, podemos atribuir funções a variáveis e chamá-las através dessas variáveis. Veja o exemplo:
def say_hello():
    print("Hello")
def say_goodbye():
    print("Good Bye")
message = say_hello
message()       # Hello
message = say_goodbye
message()       # Good ByeNeste exemplo, a variável message recebe uma das funções. Inicialmente, ela é atribuída à função say_hello():
message = say_helloAgora, a variável message está associada à função say_hello. Isso significa que podemos chamar a variável message como se fosse a própria função:
message()       # HelloAo executar esse comando, o Python chama a função say_hello, exibindo "Hello" no console. Posteriormente, podemos atribuir outra função à variável message e chamá-la da mesma maneira.
Também podemos usar uma variável para chamar funções com parâmetros e retornar seus resultados:
def sum(a, b):
    return a + b
def multiply(a, b):
    return a * b
operation = sum
result = operation(5, 6)
print(result)   # 11
operation = multiply
print(operation(5, 6))      # 30Passando Funções como Parâmetros
Em Python, podemos passar funções como parâmetros para outras funções. Vamos definir uma função que exibe no console o resultado de uma operação qualquer:
def do_operation(a, b, operation):
    result = operation(a, b)
    print(f"result = {result}")
def sum(a, b):
    return a + b
def multiply(a, b):
    return a * b
do_operation(5, 4, sum)         # result = 9
do_operation(5, 4, multiply)    # result = 20Neste exemplo, a função do_operation possui três parâmetros, sendo que o terceiro espera receber uma função que aceite dois parâmetros e retorne um resultado. Ou seja, o terceiro parâmetro, operation, representa uma operação que será definida apenas no momento em que a função do_operation for chamada. Sabemos apenas que essa operação receberá dois parâmetros e retornará algum valor, que será exibido no console.
Ao chamarmos do_operation, podemos passar a função sum como o terceiro parâmetro:
do_operation(5, 4, sum)Neste caso, o parâmetro operation representará a função sum e retornará a soma dos dois números.
Da mesma forma, podemos passar a função multiply, que realizará a multiplicação dos números:
do_operation(5, 4, multiply)    # result = 20Isso torna as funções mais flexíveis, pois permitem que outras funções sejam passadas como parâmetros.
Retornando Funções de Outras Funções
Uma função em Python também pode retornar outra função. Vamos definir uma função que retorna diferentes operações dependendo do valor de um parâmetro:
def sum(a, b):
    return a + b
def subtract(a, b):
    return a - b
def multiply(a, b):
    return a * b
def select_operation(choice):
    if choice == 1:
        return sum
    elif choice == 2:
        return subtract
    else:
        return multiply
operation = select_operation(1)     # operation = sum
print(operation(10, 6))             # 16Dependendo do valor de choice, a função select_operation retornará uma das três funções: sum, subtract ou multiply. Depois de chamar a select_operation, podemos atribuir o resultado a uma variável:
operation = select_operation(1)     # operation = sum
print(operation(10, 6))             # 16Aqui, o valor 1 foi passado para select_operation, que retornou a função sum. Portanto, a variável operation agora faz referência à função sum, que soma dois números:
print(operation(10, 6))             # 16   # equivalente a sum(10, 6)Da mesma forma, podemos retornar e executar outras funções:
operation = select_operation(2)     # operation = subtract
print(operation(10, 6))             # 4
operation = select_operation(3)     # operation = multiply
print(operation(10, 6))             # 60Dessa maneira, podemos criar funções flexíveis que retornam outras funções e executar operações de acordo com o contexto.