¿Cómo detecto si una variable de Python es una función?

686

Tengo una variable, xy quiero saber si está apuntando a una función o no.

Esperaba poder hacer algo como:

>>> isinstance(x, function)

Pero eso me da:

Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'function' is not defined

La razón por la que elegí eso es porque

>>> type(x)
<type 'function'>
Daniel H
fuente
37
Estoy deprimido por la cantidad de respuestas que solucionan el problema al buscar algún atributo de llamada o función invocable ... Una manera limpia es sobre type (a) == types.functionType como lo sugiere @ryan
AsTeR
44
@AsTeR La forma correcta de verificar las propiedades de los objetos con tipo de pato es preguntarles si graznan, no para ver si caben en un contenedor del tamaño de un pato. El enfoque "compárelo directamente" dará la respuesta incorrecta para muchas funciones, como las incorporadas.
John Feminella
3
@JohnFeminella Si bien estoy de acuerdo contigo en principio. El OP no preguntó si era invocable, solo si es una función. ¿Quizás podría argumentarse que necesitaba una distinción entre, por ejemplo, funciones y clases?
McKay
3
Para mis propósitos, vine aquí porque quería usarlo insepct.getsourceen una variedad de objetos, y en realidad no importa si el objeto era invocable, sino si era algo para lo que daría 'función' type(obj). Como google me llevó aquí, diría que el comentario de AsTeR fue la respuesta más útil (para mí). Hay muchos otros lugares en Internet para que la gente los descubra __call__o descubra callable.
tsbertalan
44
@AsTeR Es types.FunctionType, con una F mayúscula.
Ben Mares

Respuestas:

891

Si esto es para Python 2.xo Python 3.2+, también puede usarlo callable(). Solía ​​estar en desuso, pero ahora está en desuso, por lo que puede volver a usarlo. Puede leer la discusión aquí: http://bugs.python.org/issue10518 . Puedes hacer esto con:

callable(obj)

Si esto es para Python 3.x pero antes de 3.2, verifique si el objeto tiene un __call__atributo. Puedes hacer esto con:

hasattr(obj, '__call__')

El types.FunctionTypesenfoque sugerido con frecuencia no es correcto porque no cubre muchos casos que presumiblemente desearía que pasara, como ocurre con las incorporadas:

>>> isinstance(open, types.FunctionType)
False

>>> callable(open)
True

La forma correcta de verificar las propiedades de los objetos con tipo de pato es preguntarles si graznan, no para ver si caben en un contenedor del tamaño de un pato. No lo use a types.FunctionTypemenos que tenga una idea muy específica de lo que es una función.

John Feminella
fuente
73
Esto tampoco le dirá si es una función, solo si se puede llamar.
Chris B.
23
Depende de la aplicación si la distinción importa o no; Sospecho que tienes razón en que no lo hace para la pregunta original, pero eso está lejos de ser cierto.
Chris B.
55
Las clases pueden tener una función de llamada adjunta. Así que este definitivamente no es un buen método para distinguir. El método de Ryan es mejor.
Brian Bruggeman
43
el concepto de "escritura de pato" hace que esta sea la mejor respuesta, por ejemplo, "¿qué importa si es una función siempre que se comporte como tal?"
jcomeau_ictx
8
Hay casos de uso en los que la distinción entre una función invocable y una función es crucial, por ejemplo, al escribir un decorador (vea mi comentario sobre la respuesta de Ryan).
Turion
267

Los tipos incorporados que no tienen constructores en el espacio de nombres incorporado (por ejemplo, funciones, generadores, métodos) están en el typesmódulo. Puedes usar types.FunctionTypeen una isinstancellamada:

In [1]: import types
In [2]: types.FunctionType
Out[2]: <type 'function'>
In [3]: def f(): pass
   ...:
In [4]: isinstance(f, types.FunctionType)
Out[4]: True
In [5]: isinstance(lambda x : None, types.FunctionType)
Out[5]: True

Tenga en cuenta que esto utiliza una noción muy específica de "función" que generalmente no es lo que necesita. Por ejemplo, rechaza zip(técnicamente una clase):

>>> type(zip), isinstance(zip, types.FunctionType)
(<class 'type'>, False)

open (las funciones integradas tienen un tipo diferente):

>>> type(open), isinstance(open, types.FunctionType)
(<class 'builtin_function_or_method'>, False)

y random.shuffle(técnicamente un método de una random.Randominstancia oculta ):

>>> type(random.shuffle), isinstance(random.shuffle, types.FunctionType)
(<class 'method'>, False)

Si está haciendo algo específico para las types.FunctionTypeinstancias, como descompilar su bytecode o inspeccionar las variables de cierre, use types.FunctionType, pero si solo necesita que un objeto sea invocable como una función, use callable.

Ryan
fuente
55
+1 respondiendo la pregunta. Sin embargo, tratar de adivinar si un objeto es una función, o incluso si es un objeto invocable, suele ser un error. Sin más información de la OP es difícil de descartar de plano, por supuesto, pero aún así ...
bobince
47
En realidad, devolverá False para funciones integradas, como 'abrir', por ejemplo. Entonces, para ser específico, deberá usar isinstance (f, (types.FunctionType, types.BuiltinFunctionType)). Y, por supuesto, si quieres estrictamente funciones, no llamadas ni métodos.
Lukasz Korzybski
55
@ ŁukaszKorzybski y para ser más preddiseñado ... también debe verificar functools.partial: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial))o verificar f.funcen tal caso.
estani
3
@bobince, ¿qué tal este caso de uso? Quiero escribir un decorador @fooque pueda usar como @fooy como @foo(some_parameter). Luego necesita verificar con qué se llama, por ejemplo, la función para decorar (primer caso) o el parámetro (el segundo caso, en el que necesita devolver un decorador adicional).
Turion
types.BuiltinFunctionTypetambién es el tipo de métodos integrados ("normales") , que probablemente no desee permitir, si no va por la callableruta.
user2357112 es compatible con Monica el
92

Desde Python 2.1 puede importar isfunctiondesde el inspectmódulo.

>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True
Paolo
fuente
3
Agradable, pero parece devolver False para funciones integradas como openy hasattr.
Zecc
12
@Zecc isbuiltin es para eso.
Paolo
13
Consulte la inspect.isfunctioncadena de documentación: "Devuelve verdadero si el objeto es una función definida por el usuario".
Mark Mikofski
44
Tenga en cuenta que 'isfunction' no reconoce las funciones functool.partial.
ismael
74

La respuesta aceptada en el momento en que se ofreció se pensó que era correcta. Como resultado, no hay sustituto para callable(), que está de vuelta en Python 3.2: Específicamente, callable()verifica el tp_callcampo del objeto que se está probando. No hay un equivalente de Python simple. La mayoría de las pruebas sugeridas son correctas la mayor parte del tiempo:

>>> class Spam(object):
...     def __call__(self):
...         return 'OK'
>>> can_o_spam = Spam()


>>> can_o_spam()
'OK'
>>> callable(can_o_spam)
True
>>> hasattr(can_o_spam, '__call__')
True
>>> import collections
>>> isinstance(can_o_spam, collections.Callable)
True

Podemos arrojar una llave inglesa en esto eliminando el __call__de la clase. Y solo para mantener las cosas más emocionantes, ¡agregue un falso __call__a la instancia!

>>> del Spam.__call__
>>> can_o_spam.__call__ = lambda *args: 'OK?'

Tenga en cuenta que esto realmente no es invocable:

>>> can_o_spam()
Traceback (most recent call last):
  ...
TypeError: 'Spam' object is not callable

callable() devuelve el resultado correcto:

>>> callable(can_o_spam)
False

Pero hasattrestá mal :

>>> hasattr(can_o_spam, '__call__')
True

can_o_spamtiene ese atributo después de todo; simplemente no se usa cuando se llama a la instancia.

Aún más sutil, isinstance()también se equivoca:

>>> isinstance(can_o_spam, collections.Callable)
True

Debido a que usamos esta verificación antes y luego eliminamos el método, abc.ABCMeta almacena el resultado en caché. Podría decirse que esto es un error abc.ABCMeta. Dicho esto, realmente no hay forma posible de que pueda producir un resultado más preciso que el resultado que si se usa callable()solo, ya que el typeobject->tp_call método de ranura no es accesible de ninguna otra manera.

Solo usa callable()

SingleNegationElimination
fuente
55
La sorprendente ilustración de las trampas del hasattr(o, '__call__')enfoque y por qué callable(), si está disponible, es superior.
MestreLion
39

Lo siguiente debería devolver un booleano:

callable(x)
Nikhil Chelliah
fuente
1
Eso resuelve su problema, pero aún crea un misterio: si x es de la clase 'función' en el módulo integrado , y la ayuda (x .__ clase__) describe "función de clase", ¿por qué aparentemente "función" no está definida "?
Ken
1
"función" no es una palabra clave o un tipo incorporado. El tipo de funciones se define en el módulo "tipos", como "types.FunctionType"
Chris B.
19

callable(x) se devolverá true si el objeto pasado puede ser llamado en Python, pero la función no existe en Python 3.0, y hablando con propiedad, no va a distinguir entre:

class A(object):
    def __call__(self):
        return 'Foo'

def B():
    return 'Bar'

a = A()
b = B

print type(a), callable(a)
print type(b), callable(b)

Obtendrá <class 'A'> Truey <type function> Truecomo salida.

isinstancefunciona perfectamente bien para determinar si algo es una función (prueba isinstance(b, types.FunctionType)); Si está realmente interesado en saber si se puede llamar a algo, puede usarlo hasattr(b, '__call__')o simplemente probarlo.

test_as_func = True
try:
    b()
except TypeError:
    test_as_func = False
except:
    pass

Esto, por supuesto, no le dirá si es invocable pero arroja un TypeErrorcuando se ejecuta, o no es invocable en primer lugar. Eso puede no importarte.

Chris B.
fuente
8
Llamarlo es una mala idea. ¿Qué pasa si tiene efectos secundarios o realmente hace algo pero lleva mucho tiempo?
asmeurer
@asmeurer - ¿Por qué más necesitarías saber si es una función si no la estás llamando?
detly
1
@detly: para la depuración, regularmente quiero imprimir todas las variables en un objeto, los métodos generalmente no me son útiles, por lo que no me gustaría ejecutarlos. Al final, solo enumero todas las propiedades no invocables con los valores correspondientes :)
Wolph
2
El hecho de que no esté llamando no significa que no se esté llamando. Tal vez estás haciendo despacho.
Asmeurer
44
Hay un gran problema con el uso de excepciones para saber si era invocable o no; ¿Qué pasa si es invocable, pero llamarlo genera una excepción que está buscando? Ambos ignorarán silenciosamente un error y diagnosticarán erróneamente si fue invocable. Cuando usa EAFP, realmente desea evitar poner demasiado en el intento, pero no hay forma de hacerlo para este caso de uso.
Ben
15

Si desea detectar todo lo que se parece sintácticamente a una función: una función, método, diversión / metanfetamina incorporada, lambda ... pero excluye los objetos invocables (objetos con __call__método definido), intente este:

import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))

Comparé esto con el código de is*()verificaciones en el inspectmódulo y la expresión anterior es mucho más completa, especialmente si su objetivo es filtrar cualquier función o detectar propiedades regulares de un objeto.

Marcin Wojnarski
fuente
Gracias por indicarme el typesmódulo. Estaba probando una make_stemmer()fábrica que a veces devolvía una función y otras una Stemmerinstancia invocable , y necesitaba detectar la diferencia.
placas
7

Intenta usarlo callable(x).

maxyfc
fuente
6

Si ha aprendido C++, debe estar familiarizado con function objecto functor, significa cualquier objeto que puedabe called as if it is a function .

En C ++, an ordinary functiones un objeto de función, y también lo es un puntero de función; más generalmente, también es un objeto de una clase que define operator(). En C ++ 11 y superior, the lambda expressiones el functortambién.

Similitud, en Python, esos functorsson todos callable. An ordinary functionpuede ser invocable, a lambda expressionpuede invocarse, functional.partialpuede invocarse, las instancias de class with a __call__() methodpueden invocarse.


Ok, vuelve a la pregunta: I have a variable, x, and I want to know whether it is pointing to a function or not.

Si desea juzgar el clima, el objeto actúa como una función, entonces el callablemétodo sugerido por @John Feminellaestá bien.

Si lo desea judge whether a object is just an ordinary function or not(no una instancia de clase invocable o una expresión lambda), entonces xtypes.XXXsugerido por @Ryanes una mejor opción.

Luego hago un experimento usando esos códigos:

#!/usr/bin/python3
# 2017.12.10 14:25:01 CST
# 2017.12.10 15:54:19 CST

import functools
import types
import pprint

Definir una clase y una función ordinaria.

class A():
    def __call__(self, a,b):
        print(a,b)
    def func1(self, a, b):
        print("[classfunction]:", a, b)
    @classmethod
    def func2(cls, a,b):
        print("[classmethod]:", a, b)
    @staticmethod
    def func3(a,b):
        print("[staticmethod]:", a, b)

def func(a,b):
    print("[function]", a,b)

Definir los functores:

#(1.1) built-in function
builtins_func = open
#(1.2) ordinary function
ordinary_func = func
#(1.3) lambda expression
lambda_func  = lambda a : func(a,4)
#(1.4) functools.partial
partial_func = functools.partial(func, b=4)

#(2.1) callable class instance
class_callable_instance = A()
#(2.2) ordinary class function
class_ordinary_func = A.func1
#(2.3) bound class method
class_bound_method = A.func2
#(2.4) static class method
class_static_func = A.func3

Defina la lista de functores y la lista de tipos:

## list of functors
xfuncs = [builtins_func, ordinary_func, lambda_func, partial_func, class_callable_instance, class_ordinary_func, class_bound_method, class_static_func]
## list of type
xtypes = [types.BuiltinFunctionType, types.FunctionType, types.MethodType, types.LambdaType, functools.partial]

Juez si el funtor es invocable. Como puede ver, todos son invocables.

res = [callable(xfunc)  for xfunc in xfuncs]
print("functors callable:")
print(res)

"""
functors callable:
[True, True, True, True, True, True, True, True]
"""

Juzgue el tipo de functor (types.XXX). Entonces, los tipos de functores no son todos iguales.

res = [[isinstance(xfunc, xtype) for xtype in xtypes] for xfunc in xfuncs]

## output the result
print("functors' types")
for (row, xfunc) in zip(res, xfuncs):
    print(row, xfunc)

"""
functors' types
[True, False, False, False, False] <built-in function open>
[False, True, False, True, False] <function func at 0x7f1b5203e048>
[False, True, False, True, False] <function <lambda> at 0x7f1b5081fd08>
[False, False, False, False, True] functools.partial(<function func at 0x7f1b5203e048>, b=4)
[False, False, False, False, False] <__main__.A object at 0x7f1b50870cc0>
[False, True, False, True, False] <function A.func1 at 0x7f1b5081fb70>
[False, False, True, False, False] <bound method A.func2 of <class '__main__.A'>>
[False, True, False, True, False] <function A.func3 at 0x7f1b5081fc80>
"""

Dibujo una tabla de tipos de functor invocables utilizando los datos.

ingrese la descripción de la imagen aquí

Luego puede elegir los tipos de functors que convengan.

como:

def func(a,b):
    print("[function]", a,b)

>>> callable(func)
True
>>> isinstance(func,  types.FunctionType)
True
>>> isinstance(func, (types.BuiltinFunctionType, types.FunctionType, functools.partial))
True
>>> 
>>> isinstance(func, (types.MethodType, functools.partial))
False
Kinght 金
fuente
6

Como la respuesta aceptada, John Feminella declaró que:

La forma correcta de verificar las propiedades de los objetos con tipo de pato es preguntarles si graznan, no para ver si caben en un contenedor del tamaño de un pato. El enfoque "compárelo directamente" dará la respuesta incorrecta para muchas funciones, como las incorporadas.

Aunque hay dos bibliotecas para distinguir las funciones estrictamente, dibujo una tabla exhaustiva comparable:

8.9. tipos - Creación dinámica de tipos y nombres para tipos incorporados - Documentación de Python 3.7.0

30.13. inspeccionar - Inspeccionar objetos vivos - Documentación de Python 3.7.0

#import inspect             #import types
['isabstract',
 'isasyncgen',              'AsyncGeneratorType',
 'isasyncgenfunction', 
 'isawaitable',
 'isbuiltin',               'BuiltinFunctionType',
                            'BuiltinMethodType',
 'isclass',
 'iscode',                  'CodeType',
 'iscoroutine',             'CoroutineType',
 'iscoroutinefunction',
 'isdatadescriptor',
 'isframe',                 'FrameType',
 'isfunction',              'FunctionType',
                            'LambdaType',
                            'MethodType',
 'isgenerator',             'GeneratorType',
 'isgeneratorfunction',
 'ismethod',
 'ismethoddescriptor',
 'ismodule',                'ModuleType',        
 'isroutine',            
 'istraceback',             'TracebackType'
                            'MappingProxyType',
]

La "tipificación de pato" es una solución preferida para fines generales:

def detect_function(obj):
    return hasattr(obj,"__call__")

In [26]: detect_function(detect_function)
Out[26]: True
In [27]: callable(detect_function)
Out[27]: True

En cuanto a la función incorporada

In [43]: callable(hasattr)
Out[43]: True

Cuando vaya un paso más para verificar si la función integrada o la función definida por el usuario

#check inspect.isfunction and type.FunctionType
In [46]: inspect.isfunction(detect_function)
Out[46]: True
In [47]: inspect.isfunction(hasattr)
Out[47]: False
In [48]: isinstance(detect_function, types.FunctionType)
Out[48]: True
In [49]: isinstance(getattr, types.FunctionType)
Out[49]: False
#so they both just applied to judge the user-definded

Determinar si builtin function

In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False

Resumen

Emplee callablepara esquivar el tipo que verifica una función.
Úselo types.BuiltinFunctionTypesi tiene una demanda más específica.

Cálculo
fuente
5

Una función es solo una clase con un __call__método, por lo que puede hacer

hasattr(obj, '__call__')

Por ejemplo:

>>> hasattr(x, '__call__')
True

>>> x = 2
>>> hasattr(x, '__call__')
False

Esa es la "mejor" forma de hacerlo, pero dependiendo de por qué necesita saber si es invocable o una nota, puede ponerlo en un bloque try / execpt:

try:
    x()
except TypeError:
    print "was not callable"

Es discutible si try / except es más Python'y que hacerlo if hasattr(x, '__call__'): x()... Diría que hasattres más preciso, ya que accidentalmente no detectará el TypeError incorrecto, por ejemplo:

>>> def x():
...     raise TypeError
... 
>>> hasattr(x, '__call__')
True # Correct
>>> try:
...     x()
... except TypeError:
...     print "x was not callable"
... 
x was not callable # Wrong!
dbr
fuente
Utilice el manejo de excepciones para protegerse solo contra el comportamiento inesperado, nunca para el flujo lógico; eso definitivamente no es Pythonic.
gotgenes
Bueno, hasattr básicamente hace un getattr en un bloque try / except (aunque en C). blog.jancewicz.net/2007/10/reflection-hasattr.html
dbr
@dbr: Pero hasattr es más estético.
Nikhil Chelliah
5

Aquí hay un par de otras formas:

def isFunction1(f) :
    return type(f) == type(lambda x: x);

def isFunction2(f) :
    return 'function' in str(type(f));

Así es como se me ocurrió la segunda:

>>> type(lambda x: x);
<type 'function'>
>>> str(type(lambda x: x));
"<type 'function'>"
# Look Maa, function! ... I ACTUALLY told my mom about this!
Sumukh Barve
fuente
¡Esto es bonito! ¡Debería funcionar en todas las versiones de python2.xy python3.x!
Saurav Kumar
4

En lugar de comprobar '__call__'(que no es exclusivo de funciones), se puede comprobar si una función definida por el usuario tiene atributos func_name, func_docetc. Esto no funciona para métodos.

>>> def x(): pass
... 
>>> hasattr(x, 'func_name')
True

Otra forma de verificar es usar el isfunction()método del inspectmódulo.

>>> import inspect
>>> inspect.isfunction(x)
True

Para verificar si un objeto es un método, use inspect.ismethod()

Stefan van den Akker
fuente
4

Como las clases también tienen __call__método, recomiendo otra solución:

class A(object):
    def __init__(self):
        pass
    def __call__(self):
        print 'I am a Class'

MyClass = A()

def foo():
    pass

print hasattr(foo.__class__, 'func_name') # Returns True
print hasattr(A.__class__, 'func_name')   # Returns False as expected

print hasattr(foo, '__call__') # Returns True
print hasattr(A, '__call__')   # (!) Returns True while it is not a function
guneysus
fuente
1
de acuerdo con tu respuesta, la respuesta de John Feminella hasattr(obj, '__call__')es ambigua.
GoingMyWay
4

Tenga en cuenta que las clases de Python también son invocables.

Para obtener funciones (y por funciones nos referimos a funciones estándar y lambdas) use:

import types

def is_func(obj):
    return isinstance(obj, (types.FunctionType, types.LambdaType))


def f(x):
    return x


assert is_func(f)
assert is_func(lambda x: x)
Łukasz Rogalski
fuente
2

Cualquier función es una clase para que pueda tomar el nombre de la clase de instancia x y comparar:


if(x.__class__.__name__ == 'function'):
     print "it's a function"
Katsu
fuente
2

Las soluciones que se usan hasattr(obj, '__call__')y se callable(.)mencionan en algunas de las respuestas tienen un inconveniente principal: ambas también regresan Truepara clases e instancias de clases con un __call__()método. P.ej.

>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True

Una forma adecuada de verificar si un objeto es una función definida por el usuario (y nada más que eso) es usar isfunction(.):

>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True

Si necesita buscar otros tipos, eche un vistazo a inspeccionar: inspeccione objetos vivos .

Gerald Senarclens de Grancy
fuente
2

Un verificador de función exacta

invocable es una muy buena solución. Sin embargo, quería tratar esto de la manera opuesta a John Feminella. En lugar de tratarlo como este dicho:

La forma correcta de verificar las propiedades de los objetos con tipo de pato es preguntarles si graznan, no para ver si caben en un contenedor del tamaño de un pato. El enfoque "compárelo directamente" dará la respuesta incorrecta para muchas funciones, como las incorporadas.

Lo trataremos así:

La forma correcta de verificar si algo es un pato es no ver si puede graznar, sino ver si realmente es un pato a través de varios filtros, en lugar de simplemente verificar si parece un pato desde la superficie.

¿Cómo lo implementaríamos?

El módulo 'tipos' tiene muchas clases para detectar funciones, siendo las más útiles tipos.FunctionType , pero también hay muchas otras, como un tipo de método, un tipo incorporado y un tipo lambda. También consideraremos un objeto 'functools.partial' como una función.

La forma simple de verificar si es una función es mediante el uso de una condición isinstance en todos estos tipos. Anteriormente, quería hacer una clase base que herede de todo lo anterior, pero no puedo hacerlo, ya que Python no nos permite heredar de algunas de las clases anteriores.

Aquí hay una tabla de qué clases pueden clasificar qué funciones:

Tabla de funciones de kinght- 金 Tabla de funciones de arriba por kinght- 金

El código que lo hace

Ahora, este es el código que hace todo el trabajo que describimos desde arriba.

from types import BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType
from functools import partial

def is_function(obj):
  return isinstance(obj, (BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType, partial))

#-------------------------------------------------

def my_func():
  pass

def add_both(x, y):
  return x + y

class a:
  def b(self):
    pass

check = [

is_function(lambda x: x + x),
is_function(my_func),
is_function(a.b),
is_function(partial),
is_function(partial(add_both, 2))

]

print(check)
>>> [True, True, True, False, True]

El falso era is_function (parcial), porque es una clase, no una función, y esto es exactamente funciones, no clases. Aquí hay una vista previa para que pruebe el código.

Conclusión

invocable (obj) es el método preferido para verificar si un objeto es una función si quiere ir escribiendo pato sobre absolutos .

Nuestra función is_function (obj) personalizada , tal vez con algunas ediciones es el método preferido para verificar si un objeto es una función si no cuenta ninguna instancia de clase invocable como una función, sino solo funciones definidas integradas , o con lambda , def o parcial .

Y creo que eso lo envuelve todo. ¡Tenga un buen día!

Corman
fuente
1

En Python3 se me ocurrió type (f) == type (lambda x:x)qué rendimiento Truesi fes una función y Falsesi no lo es. Pero creo que prefiero isinstance (f, types.FunctionType), que se siente menos ad hoc. Quería hacerlo type (f) is function, pero eso no funciona.

Aaron
fuente
0

Después de las respuestas anteriores, se me ocurrió esto:

from pprint import pprint

def print_callables_of(obj):
    li = []
    for name in dir(obj):
        attr = getattr(obj, name)
        if hasattr(attr, '__call__'):
            li.append(name)
    pprint(li)
Jabba
fuente
0

Podrías probar esto:

if obj.__class__.__name__ in ['function', 'builtin_function_or_method']:
    print('probably a function')

o incluso algo más extraño:

if "function" in lower(obj.__class__.__name__):
    print('probably a function')
tinnick
fuente
-1

Si el código continuará realizando la llamada si el valor es invocable, solo realice la llamada y captura TypeError.

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")
Roger Dahl
fuente
44
Esto es peligroso; No tienes idea de qué efectos secundarios xtiene.
cwallenpoole
-2

La siguiente es una "forma de repr" para verificarlo. También funciona con lambda.

def a():pass
type(a) #<class 'function'>
str(type(a))=="<class 'function'>" #True

b = lambda x:x*2
str(type(b))=="<class 'function'>" #True
Vova
fuente
-3

Esto funciona para mi:

str(type(a))=="<class 'function'>"
Rafael De Acha
fuente
1
¿Y qué nos dice eso si el resultado es una cadena vacía? Para una función, obtengo "<type 'function'>", para un número entero, obtengo "<type 'int'>", así que no veo cómo te está funcionando: /
pawamoy
Ahora solo funciona para Python 3 :) También, dependiendo de la intención original de la pregunta, sería incompleto: ¿debería openconsiderarse la función incorporada? str(type(open))da <class 'builtin_function_or_method'>en Python 3.
pawamoy