Python - passando uma função para outra função

92

Estou resolvendo um quebra-cabeça usando python e dependendo de qual quebra-cabeça estou resolvendo, terei que usar um conjunto especial de regras. Como posso passar uma função para outra função em Python?

Exemplo

def Game(listA, listB, rules):
   if rules == True:
      do...
   else:
      do...

def Rule1(v):
  if "variable_name1" in v:
      return False
  elif "variable_name2" in v:
      return False
  else:
      return True

def Rule2(v):
  if "variable_name3" and "variable_name4" in v:
      return False
  elif "variable_name4" and variable_name1 in v:
      return False
  else:
      return True

Este é apenas um pseudocódigo e, portanto, não é específico, mas consigo o código para compilar, mas preciso saber como chamar a função Gamee se está definida corretamente, pois as regras serão trocadas por Rule1(v)ou Rule2(v).

Jchanger
fonte

Respostas:

148

Basta passá-lo como qualquer outro parâmetro:

def a(x):
    return "a(%s)" % (x,)

def b(f,x):
    return f(x)

print b(a,10)
John Millikin
fonte
43
funções são objetos de primeira classe em python. você pode distribuí-los, incluí-los em dictos, listas, etc. Só não inclua os parênteses após o nome da função. Exemplo, para uma função chamada myfunction: myfunctionsignifica a própria função, myfunction()significa chamar a função e obter seu valor de retorno.
nosklo
1
E se a função for um método em um objeto e usar uma propriedade desse objeto para fazer seu trabalho?
CpILL de
2
E se as funções que eu passar tiverem um número variável de argumentos de entrada? Devo então usar argumentos de palavra-chave?
H. Vabri de
E se as duas funções estiverem em arquivos Python separados?
Adrian Jimenez
24

Trate a função como variável em seu programa para que você possa simplesmente passá-la para outras funções facilmente:

def test ():
   print "test was invoked"

def invoker(func):
   func()

invoker(test)  # prints test was invoked
Piotr Czapla
fonte
Sim. No exemplo acima, a invokerfunção precisaria fornecer esses argumentos ao chamar a função.
codeape
15

Para passar uma função e quaisquer argumentos para a função:

from typing import Callable    

def looper(fn: Callable, n:int, *args, **kwargs):
    """
    Call a function `n` times

    Parameters
    ----------
    fn: Callable
        Function to be called.
    n: int
        Number of times to call `func`.
    *args
        Positional arguments to be passed to `func`.
    **kwargs
        Keyword arguments to be passed to `func`.

    Example
    -------
    >>> def foo(a:Union[float, int], b:Union[float, int]):
    ...    '''The function to pass'''
    ...    print(a+b)
    >>> looper(foo, 3, 2, b=4)
    6
    6
    6       
    """
    for i in range(n):
        fn(*args, **kwargs)

Dependendo do que você está fazendo, pode fazer sentido definir um decorator, ou talvez usar functools.partial.

Ryanjdillon
fonte
9

Basta passá-lo, assim:

Game(list_a, list_b, Rule1)

e sua função de jogo poderia ser parecida com isto (ainda pseudocódigo):

def Game(listA, listB, rules=None):
    if rules:
        # do something useful
        # ...
        result = rules(variable) # this is how you can call your rule
    else:
        # do something useful without rules
Ian Clelland
fonte
9

Um nome de função pode se tornar um nome de variável (e, portanto, ser passado como um argumento) eliminando os parênteses. Um nome de variável pode se tornar um nome de função adicionando parênteses.

Em seu exemplo, iguale a variável rulesa uma de suas funções, deixando de fora os parênteses e a menção do argumento. Então, em sua game()função, invoque rules( v )com os parênteses e o vparâmetro.

if puzzle == type1:
    rules = Rule1
else:
    rules = Rule2

def Game(listA, listB, rules):
    if rules( v ) == True:
        do...
    else:
        do...
Ken
fonte