¿Cómo paso un método como parámetro en Python?

191

¿Es posible pasar un método como parámetro a un método?

self.method2(self.method1)

def method1(self):
    return 'hello world'

def method2(self, methodToRun):
    result = methodToRun.call()
    return result
Dan
fuente

Respuestas:

263

Sí lo es, solo use el nombre del método, como lo ha escrito. Los métodos / funciones son objetos en Python, como cualquier otra cosa, y puede pasarlos de la forma en que realiza las variables. De hecho, puede pensar en un método (o función) como una variable cuyo valor es el objeto de código invocable real.

Para su información, no hay ningún callmétodo, creo que se llama __call__, pero no tiene que invocarlo explícitamente:

def method1():
    return 'hello world'

def method2(methodToRun):
    result = methodToRun()
    return result

method2(method1)

Si quisieras method1ser llamado con argumentos, entonces las cosas se vuelven un poco más complicadas. method2tiene que escribirse con un poco de información sobre cómo pasar argumentos method1, y necesita obtener valores para esos argumentos de alguna parte. Por ejemplo, si method1se supone que toma un argumento:

def method1(spam):
    return 'hello ' + str(spam)

entonces podría escribir method2para llamarlo con un argumento que se pasa:

def method2(methodToRun, spam_value):
    return methodToRun(spam_value)

o con un argumento de que se calcula a sí mismo:

def method2(methodToRun):
    spam_value = compute_some_value()
    return methodToRun(spam_value)

Puede expandir esto a otras combinaciones de valores pasados ​​y valores calculados, como

def method1(spam, ham):
    return 'hello ' + str(spam) + ' and ' + str(ham)

def method2(methodToRun, ham_value):
    spam_value = compute_some_value()
    return methodToRun(spam_value, ham_value)

o incluso con argumentos de palabras clave

def method2(methodToRun, ham_value):
    spam_value = compute_some_value()
    return methodToRun(spam_value, ham=ham_value)

Si no sabe, al escribir method2, qué argumentos methodToRuntomará, también puede usar el desempaquetado de argumentos para llamarlo de manera genérica:

def method1(spam, ham):
    return 'hello ' + str(spam) + ' and ' + str(ham)

def method2(methodToRun, positional_arguments, keyword_arguments):
    return methodToRun(*positional_arguments, **keyword_arguments)

method2(method1, ['spam'], {'ham': 'ham'})

En este caso positional_argumentsdebe ser una lista o tupla o similar, y keyword_argumentses un dict o similar. En method2puede modificar positional_argumentsy keyword_arguments(por ejemplo, agregar o eliminar ciertos argumentos o cambiar los valores) antes de llamar method1.

David Z
fuente
34

Sí, es posible. Solo llámalo:

class Foo(object):
    def method1(self):
        pass
    def method2(self, method):
        return method()

foo = Foo()
foo.method2(foo.method1)

fuente
1
¿Qué pasa si no hay una instancia foo?
Lei Yang
1
Entonces simplemente no necesitas foo, por ejemplo: def method1(): pass def method2(method) return method() method2(method1)
Tom
14

Aquí está su ejemplo reescrito para mostrar un ejemplo de trabajo independiente:

class Test:
    def method1(self):
        return 'hello world'

    def method2(self, methodToRun):
        result = methodToRun()
        return result

    def method3(self):
        return self.method2(self.method1)

test = Test()

print test.method3()
Trent
fuente
6

Si; Las funciones (y métodos) son objetos de primera clase en Python. Los siguientes trabajos:

def foo(f):
    print "Running parameter f()."
    f()

def bar():
    print "In bar()."

foo(bar)

Salidas:

Running parameter f().
In bar().

Este tipo de preguntas son triviales para responder usando el intérprete de Python o, para más funciones, el shell de IPython .

lt_kije
fuente
5

Si desea pasar un método de una clase como argumento pero aún no tiene el objeto sobre el que va a llamarlo, simplemente puede pasar el objeto una vez que lo tenga como primer argumento (es decir, el "yo" argumento).

class FooBar:

    def __init__(self, prefix):
        self.prefix = prefix

    def foo(self, name):
        print "%s %s" % (self.prefix, name)


def bar(some_method):
    foobar = FooBar("Hello")
    some_method(foobar, "World")

bar(FooBar.foo)

Esto imprimirá "Hola Mundo"

Lado delantero
fuente
5

Muchas buenas respuestas pero extraño que nadie haya mencionado el uso de una lambdafunción.
Entonces, si no tienes argumentos, las cosas se vuelven bastante triviales:

def method1():
    return 'hello world'

def method2(methodToRun):
    result = methodToRun()
    return result

method2(method1)

Pero supongamos que tiene uno (o más) argumentos en method1:

def method1(param):
    return 'hello ' + str(param)

def method2(methodToRun):
    result = methodToRun()
    return result

Entonces puedes simplemente invocar method2como method2(lambda: method1('world')).

method2(lambda: method1('world'))
>>> hello world
method2(lambda: method1('reader'))
>>> hello reader

Encuentro esto mucho más limpio que las otras respuestas mencionadas aquí.

Scrotch
fuente
Si este fuera un valor en un diccionario, ¿cómo podría ejecutarlo en lugar de devolver un objeto de función? Editar: Acabo de darme cuenta de que puedo poner ()al final del objeto en mi llamada de regreso, duh.
vaponteblizzard
3

Los métodos son objetos como cualquier otro. Para que pueda pasarlos, almacenarlos en listas y dictados, hacer lo que quiera con ellos. Lo especial de ellos es que son objetos invocables para que pueda invocarlos __call__. __call__se le llama automáticamente cuando invoca el método con o sin argumentos, por lo que solo necesita escribir methodToRun().

Vasil
fuente
0

No es exactamente lo que desea, pero una herramienta útil relacionada es getattr()utilizar el nombre del método como parámetro.

class MyClass:
   def __init__(self):
      pass
   def MyMethod(self):
      print("Method ran")

# Create an object
object = MyClass()
# Get all the methods of a class
method_list = [func for func in dir(MyClass) if callable(getattr(MyClass, func))]
# You can use any of the methods in method_list
# "MyMethod" is the one we want to use right now

# This is the same as running "object.MyMethod()"
getattr(object,'MyMethod')()
Dersu Giritlioğlu
fuente