Python: pasar una función a otra función

95

Estoy resolviendo un rompecabezas usando Python y, dependiendo del rompecabezas que esté resolviendo, tendré que usar un conjunto especial de reglas. ¿Cómo puedo pasar una función a otra función en Python?

Ejemplo

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

Esto es solo un pseudo código y, por lo tanto, no es específico, pero obtengo el código para compilar, pero necesito saber cómo llamar a la función Gamey si está definida correctamente, ya que las reglas se cambiarán por Rule1(v)o Rule2(v).

jchanger
fuente

Respuestas:

151

Simplemente páselo como cualquier otro parámetro:

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

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

print b(a,10)
John Millikin
fuente
44
Las funciones son objetos de primera clase en Python. puede pasarlos, incluirlos en dictados, listas, etc. Simplemente no incluya el paréntesis después del nombre de la función. Por ejemplo, para una función llamada myfunction: myfunctionsignifica la función en sí, myfunction()significa llamar a la función y obtener su valor de retorno.
nosklo
1
¿Y si la función es un método en un objeto y usa una propiedad de ese objeto para hacer su trabajo?
CpILL
2
¿Qué pasa si las funciones que paso tienen un número variable de argumentos de entrada? ¿Debería entonces usar argumentos de palabras clave?
H. Vabri
¿Qué pasa si las dos funciones están en archivos de Python separados?
Adrian Jimenez
25

Trate la función como una variable en su programa para que pueda pasarla a otras funciones fácilmente:

def test ():
   print "test was invoked"

def invoker(func):
   func()

invoker(test)  # prints test was invoked
Piotr Czapla
fuente
Si. En el ejemplo anterior, la invokerfunción necesitaría proporcionar esos argumentos al llamar a la función.
codeape
15

Para pasar tanto una función como cualquier argumento a la función:

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)

Dependiendo de lo que esté haciendo, podría tener sentido definir un decorator, o quizás usar functools.partial.

Ryanjdillon
fuente
9

Simplemente páselo, así:

Game(list_a, list_b, Rule1)

y luego su función de Juego podría verse algo así (aún 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
fuente
9

El nombre de una función puede convertirse en un nombre de variable (y por lo tanto pasar como un argumento) eliminando los paréntesis. Un nombre de variable puede convertirse en un nombre de función añadiendo paréntesis.

En su ejemplo, equipare la variable rulesa una de sus funciones, dejando los paréntesis y la mención del argumento. Luego, en tu game()función, invoca rules( v )con el paréntesis y el vparámetro.

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

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