Python - przekazywanie funkcji do innej funkcji

95

Rozwiązuję zagadkę w Pythonie iw zależności od tego, którą układam, będę musiał użyć specjalnego zestawu reguł. Jak mogę przekazać funkcję do innej funkcji w Pythonie?

Przykład

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

To jest tylko pseudokod i dlatego nie jest konkretny, ale otrzymuję kod do skompilowania, ale muszę wiedzieć, jak wywołać funkcję Gamei czy jest poprawnie zdefiniowana, ponieważ reguły zostaną przełączone na albo Rule1(v)lub Rule2(v).

jchanger
źródło

Odpowiedzi:

151

Po prostu podaj go jak każdy inny parametr:

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

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

print b(a,10)
John Millikin
źródło
44
funkcje są obiektami pierwszej klasy w Pythonie. możesz je przekazywać, włączać do dykt, list itp. Po prostu nie dodawaj nawiasów po nazwie funkcji. Na przykład dla funkcji o nazwie myfunction: myfunctionoznacza samą funkcję, myfunction()czyli wywołanie funkcji i zamiast tego pobranie jej wartości zwracanej.
nosklo
1
A co, jeśli funkcja jest metodą na obiekcie i używa właściwości tego obiektu do wykonania swojej pracy?
CpILL
2
Co się stanie, jeśli przekazane przeze mnie funkcje mają różną liczbę argumentów wejściowych? Czy powinienem zatem używać argumentów słów kluczowych?
H. Vabri,
A co, jeśli te dwie funkcje znajdują się w oddzielnych plikach Pythona?
Adrian Jimenez
25

Traktuj funkcję jako zmienną w swoim programie, aby móc łatwo przekazać ją do innych funkcji:

def test ():
   print "test was invoked"

def invoker(func):
   func()

invoker(test)  # prints test was invoked
Piotr Czapla
źródło
Tak. W powyższym przykładzie invokerfunkcja musiałaby wtedy podać te argumenty podczas wywoływania funkcji.
codeape
15

Aby przekazać zarówno funkcję, jak i wszelkie argumenty do funkcji:

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)

W zależności od tego, co robisz, sensowne decoratormoże być zdefiniowanie lub użycie functools.partial.

ryanjdillon
źródło
9

Po prostu podaj to w ten sposób:

Game(list_a, list_b, Rule1)

a wtedy twoja funkcja Game mogłaby wyglądać mniej więcej tak (nadal pseudokod):

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
źródło
9

Nazwa funkcji może stać się nazwą zmiennej (i tym samym zostać przekazana jako argument) przez usunięcie nawiasów. Nazwa zmiennej może stać się nazwą funkcji poprzez dodanie nawiasów.

W twoim przykładzie zrównaj zmienną rulesz jedną ze swoich funkcji, pomijając nawiasy i wzmiankę o argumencie. Następnie w swojej game()funkcji wywołaj rules( v )z nawiasami i vparametrem.

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

def Game(listA, listB, rules):
    if rules( v ) == True:
        do...
    else:
        do...
Rozpoznać
źródło