2010-03-17 15 views
6

Dado que las funciones son valores en Python, ¿cómo puedo determinar si la variable es una función?¿Cómo determinar si la variable es una función en Python?

Por ejemplo:

boda = len # boda is the length function now 
if ?is_var_function(boda)?: 
    print "Boda is a function!" 
else: 
    print "Boda is not a function!" 

Aquí hipotética ?is_var_function(x)? debería devolver cierto si x es una función exigible, y falso si no lo es.

+0

¿Desea que también sea cierto para las clases, ya que están habilitadas? – Javier

+4

La mejor solución es dejar de querer hacer esto. –

+1

¿Qué le impide leer el código? –

Respuesta

11

El callable incorporado mencionado en otras respuestas no responde a su pregunta como se planteó, porque también devuelve True, además de funciones, para métodos, clases, instancias de clases que definen un método __call__. Si el título y el texto de su pregunta son incorrectos, y no le importa si algo es de hecho una función, pero solo si es invocable, entonces use esa función incorporada. Pero la mejor respuesta a su pregunta tal como se plantea es: importe el método inspect de la biblioteca estándar de Python, y use inspect.isfunction. (Hay otras formas de abstracción más baja, pero siempre es una buena idea usar la funcionalidad del módulo inspect para la introspección cuando está allí, con preferencia a los enfoques de bajo nivel: inspect ayuda a mantener su código conciso, claro, robusto y futuro -prueba).

+1

Otra respuesta errónea aceptada en SO. Debería comenzar una lista. Esto falla para las funciones integradas y los métodos de clase, como mencioné en algunas otras respuestas. También necesitaría marcar inspect.isbuiltin() e inspeccionar. Ismethod(), y no hay nada "a prueba de futuro" para tener tantos casos especiales. –

+0

¿Y por qué no escribe (a) == types.functionType? – AsTeR

7

Hay una función callable en python.

if callable(boda): 
+0

Una función/método es cada objeto que implementa un método '__call__'. invocable() es una buena forma de probar la existencia de dicho método de llamada. – tux21b

+0

Pero invocable también devolverá verdadero para una clase, ¿no? No está claro si el OP también quería eso. – Javier

+1

Sospecho que el OP no conoce la diferencia y, de hecho, quiere que todo sea invocable. Hay muchas posibilidades de que si no sabes cómo verificar si algo es una función en Python, en realidad no quieras hacerlo. –

4

Uso callable(boda) para determinar si boda es exigible o no.

Llamable significa aquí que es una función, método o incluso una clase. Pero como quiera distinguir solo entre variables y funciones, debería funcionar bien.

Su código sería el siguiente aspecto:

boda = len # boda is the length function now 
if callable(boda): 
    print "Boda is a function!" 
else: 
    print "Boda is not a function!" 
2
>>> import types 
>>> def f(): pass 
... 
>>> x = 0 
>>> type(f) == types.FunctionType 
True 
>>> type(x) == types.FunctionType 
False 

Eso comprobará si se trata de una función. callable() comprobará si es invocable (es decir, tiene un método __call__), por lo que devolverá true en una clase, así como en una función o método.

+0

'isinstance' es generalmente preferido para la verificación de tipo. 'is' generalmente se prefiere a' == 'para verificar singletons.Requerir una función y no otra cosa que actúe exactamente como una función es una mala política. –

+1

'type (sys.exit) == types.FunctionType' y' type ((1.0) .hex) == types.FunctionType' son ambos falsos. (Todavía falla con isinstance; no sé por qué BuiltinFunctionType y MethodType no son subclases de FunctionType.) –

11

Puede usar inspect.isfunction(object). Ver: docs.python.org

Dicho esto, debe evitar el uso de esta técnica en su código del día a día. En ocasiones, es necesario utilizar la reflexión; por ejemplo, un marco MVC podría necesitar cargar una clase e inspeccionar sus miembros. Pero por lo general, debe devolver/pasar/tratar con objetos que tienen la misma "interfaz". Por ejemplo, no devuelva un objeto que puede ser un número entero o una función: siempre devuelva el mismo "tipo" de objeto para que su código pueda ser coherente.

+0

@Justin Ethier: parece que alguien rechazó cada respuesta. – kgrad

+1

Proporciona consejos sobre cómo hacer algo que normalmente es malo sin contexto sobre cómo crear código Python bueno, robusto e idiomático. –

+3

También sucede para responder a la pregunta, que es el propósito de este sitio. – harto

0

¿Y qué debería devolver para un property, al que accede como un atributo de valor pero en realidad invoca una función? Su pregunta aparentemente simple en realidad abre una lata de gusanos en Python. Lo que significa que cosas como callable y isfunction son buenas para su educación e introspección, pero probablemente no sean cosas en las que quiera confiar al interactuar con otros códigos.

Tangencial: Consulte la presentación Turtles All The Way Down para obtener más información sobre cómo se arma Python.

+1

Una propiedad es un ejemplo extraño. Las propiedades no se parecen mucho a las funciones y, más concretamente, en una situación normal no se accede al objeto de propiedad real, se accede al objeto que tiene para usted. –

1

La filosofía de cómo utilizar diferentes objetos en un programa de Python se llama pato escribir -si es que parece un pato, grazna como pato y camina como un pato, es un pato. Los objetos se agrupan no por su tipo, sino por lo que son capaces de hacer, y esto incluso se extiende a las funciones. Al escribir un programa de Python, siempre debe saber qué pueden hacer todos sus objetos y usarlos sin verificar.

Por ejemplo, podría definir una función

def add_three(a, b c): 
    return a + b + c 

y significar para que sea utilizado con tres flotadores. Pero al no comprobar esto, tengo una función mucho más útil: puedo usarla con enteros, con decimales decimales o fracciones. Por ejemplo, fracciones.

Lo mismo se aplica a tener una función. Si sé que tengo una función y quiero llamarla, debería llamarla. Tal vez lo que tengo es una función y tal vez tengo una llamada diferente (como un método vinculado o una instancia de una clase arbitraria que define __call__) que podría ser igual de buena. Al no verificar nada, hago que mi código sea capaz de manejar una amplia gama de circunstancias que tal vez ni siquiera había pensado con antelación.

En el caso de los callables, puedo determinar bastante confiablemente si tengo uno o no, pero por el bien de la simplicidad de mi código, no me gustaría. Si alguien transfiere algo que no se puede llamar, recibirá un error cuando lo llame de todos modos. Si estoy escribiendo código que acepta un parámetro que puede ser invocable o no y hago diferentes cosas dependiendo de él, parece que debería mejorar mi API definiendo dos funciones para hacer estas dos cosas diferentes.

Si tenía una manera de manejar el caso donde la persona que llama pasó algo que no funciona (y esto no fue solo el resultado de una API demente), la solución correcta sería atrapar el TypeError que se genera cuando intentas llamar a algo que no se puede invocar. En general, es mejor tratar de hacer algo y recuperar si falla en lugar de verificarlo con anticipación. (Recuerde el cliché: "Es más fácil pedir perdón que permiso".) Controlar con anticipación puede generar problemas inesperados basados ​​en errores sutiles en la lógica y puede conducir a condiciones de carrera.

¿Por qué crees que necesitas tipear?

Cuestiones relacionadas