Como detecto se uma variável Python é uma função?


686

Eu tenho uma variável, xe quero saber se está apontando para uma função ou não.

Eu esperava poder fazer algo como:

>>> isinstance(x, function)

Mas isso me dá:

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

A razão pela qual escolhi isso é porque

>>> type(x)
<type 'function'>

37
Estou deprimido com o número de respostas que trabalham em torno do problema, procurando por alguma chamada atributo ou função que pode ser chamado ... Uma maneira limpa é sobre o tipo (a) == types.functionType como sugerido por @ Ryan
— Aster

44
@AsTeR A maneira correta de verificar as propriedades de objetos do tipo pato é perguntar se eles grasnam, não para ver se eles se encaixam em um contêiner do tamanho de um pato. A abordagem "compare diretamente" fornecerá a resposta errada para muitas funções, como builtins.
— John Junella

3
@JohnFeminella Embora eu concorde com você em princípio. O OP não perguntou se era possível chamar, apenas se é uma função. Talvez se possa argumentar que ele precisava de uma distinção entre, por exemplo, funções e classes?
— McKay

3
Para meus propósitos, eu vim aqui porque queria usar insepct.getsourceem uma variedade de objetos, e na verdade não importa se o objeto era passível de chamada, mas se era algo que daria 'função' type(obj). Como o google me levou até aqui, eu diria que o comentário do AsTeR foi a resposta mais útil (para mim). Existem muitos outros lugares na internet para as pessoas descobrirem __call__ou callable.
— tsbertalan

4
@AsTeR É types.FunctionType, com maiúsculas F.
— Ben Mares

Respostas:


891

Se for para o Python 2.x ou para o Python 3.2+, você também pode usar callable(). Ele era obsoleto, mas agora não é obsoleto, para que você possa usá-lo novamente. Você pode ler a discussão aqui: http://bugs.python.org/issue10518 . Você pode fazer isso com:

callable(obj)

Se for para o Python 3.x, mas antes do 3.2, verifique se o objeto tem um __call__atributo. Você pode fazer isso com:

hasattr(obj, '__call__')

A types.FunctionTypesabordagem frequentemente sugerida não está correta porque falha em cobrir muitos casos que você provavelmente gostaria que ela passasse, como acontece com os builtins:

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

>>> callable(open)
True

A maneira correta de verificar as propriedades de objetos com tipo de pato é perguntar se eles grasnam, não para ver se eles se encaixam em um contêiner do tamanho de pato. Não use a types.FunctionTypemenos que tenha uma idéia muito específica do que é uma função.


73
Isso também não dirá se é uma função - apenas se puder ser chamada.
— Chris B.

23
Depende da aplicação se a distinção importa ou não; Eu suspeito que você esteja certo que isso não acontece com a pergunta original, mas isso está longe de ser certo.
— Chris B.

5
As classes podem ter uma função de chamada anexada a ela. Portanto, esse definitivamente não é um bom método para distinguir. O método de Ryan é melhor.
— Brian Bruggeman

43
o conceito de "digitação de pato" torna essa a melhor resposta, por exemplo, "o que importa se for uma função desde que se comporte como uma?"
— jcomeau_ictx

8
Existem casos em que a distinção entre uma função que pode ser chamada e uma função é crucial, por exemplo, ao escrever um decorador (veja meu comentário na resposta de Ryan).
— precisa

267

Tipos internos que não têm construtores no espaço de nomes interno (por exemplo, funções, geradores, métodos) estão no typesmódulo. Você pode usar types.FunctionTypeem uma isinstancechamada:

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

Observe que isso usa uma noção muito específica de "função" que geralmente não é o que você precisa. Por exemplo, ele rejeita zip(tecnicamente uma classe):

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

open (as funções incorporadas têm um tipo diferente):

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

e random.shuffle(tecnicamente, um método de uma random.Randominstância oculta ):

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

Se você estiver fazendo algo específico para types.FunctionTypeinstâncias, como descompilar seu bytecode ou inspecionar variáveis ​​de fechamento, use types.FunctionType, mas se você precisar apenas de um objeto que possa ser chamado como uma função, use callable.


5
+1 respondendo à pergunta. No entanto, tentar adivinhar se um objeto é uma função - ou mesmo se é um objeto que pode ser chamado - geralmente é um erro. Sem mais informações do OP é difícil rejeitá-lo fora de mão, é claro, mas ainda assim ...
— bobince

47
Na verdade, ele retornará False para funções internas, como 'open', por exemplo. Portanto, para ser específico, você terá que usar isinstance (f, (types.FunctionType, types.BuiltinFunctionType)). E, é claro, se você deseja estritamente apenas funções, não chamadas ou métodos.
— Lukasz Korzybski

5
@ ŁukaszKorzybski e para ser mais preciso ... você também deve procurar functools.partial: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial))ou verificar f.funcnesse caso.
— estani

3
@ Bobince, que tal este caso de usuário: eu quero escrever um decorador @fooque eu possa usar como @fooe como @foo(some_parameter). Ele precisa verificar como está sendo chamado, por exemplo, a função para decorar (primeiro caso) ou o parâmetro (o segundo caso, no qual ele precisa retornar um decorador adicional).
— precisa

types.BuiltinFunctionTypetambém é o tipo de métodos internos ("normais") , que você provavelmente não deseja permitir, se não estiver seguindo o callablecaminho.
— User2357112 suporta Monica

92

Desde o Python 2.1, você pode importar isfunctiondo inspectmódulo.

>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True

3
Bom, mas parece retornar False para funções internas como opene hasattr.
— Zecc

12
@Zecc isbuiltin é para isso.
— Paolo

13
Consulte a inspect.isfunctiondocumentação: "Return true se o objeto for uma função definida pelo usuário".
— Mark Mikofski

4
Observe que 'isfunction' não reconhece funções functool.partial.
— Ishmael

74

A resposta aceita foi no momento em que foi oferecida, considerada correta. Como se vê, há nenhum substituto para callable(), que está de volta em Python 3.2: Especificamente, callable()verifica o tp_callcampo do objecto a ser testado. Não existe um equivalente simples em Python. A maioria dos testes sugeridos está correta na maioria das vezes:

>>> 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 jogar uma chave de macaco nisso removendo o __call__da classe. E apenas para manter as coisas ainda mais emocionantes, adicione uma farsa __call__à instância!

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

Observe que isso realmente não é exigível:

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

callable() retorna o resultado correto:

>>> callable(can_o_spam)
False

Mas hasattrestá errado :

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

can_o_spamafinal tem esse atributo; simplesmente não é usado ao chamar a instância.

Ainda mais sutil, isinstance()também se engana:

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

Como usamos essa verificação anteriormente e depois excluímos o método, abc.ABCMeta o resultado é armazenado em cache. Indiscutivelmente, isso é um bug abc.ABCMeta. Dito isso, não há realmente nenhuma maneira possível de produzir um resultado mais preciso do que o resultado do que usar callable()ele próprio, já que o typeobject->tp_call método do slot não é acessível de nenhuma outra maneira.

Apenas use callable()


5
Ilustração surpreendente das armadilhas da hasattr(o, '__call__')abordagem e por que callable(), se disponível, é superior.
— MestreLion

39

O seguinte deve retornar um booleano:

callable(x)

1
Isso resolve seu problema, mas ele ainda criou um mistério: se x é da 'função' da classe no módulo embutido e a ajuda (x .__ class__) descreve a "função da classe", por que a "função" aparentemente "não está definida"?
— Ken

1
"function" não é uma palavra-chave ou um tipo interno. O tipo de funções é definida no módulo "tipos", como "types.FunctionType"
— Chris B.


19

callable(x) irá retornar true se o objeto passado pode ser chamado em Python, mas a função não existe no Python 3.0, e propriamente falando não vai 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)

Você obterá <class 'A'> Truee <type function> Truecomo saída.

isinstancefunciona perfeitamente bem para determinar se algo é uma função (tentativa isinstance(b, types.FunctionType)); se você estiver realmente interessado em saber se algo pode ser chamado, você pode usar hasattr(b, '__call__')ou apenas tentar.

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

Isso, é claro, não informará se é possível chamar, mas lança um TypeErrorquando é executado ou se não é chamado em primeiro lugar. Isso pode não lhe interessar.


8
Chamá-lo é uma má ideia. E se tiver efeitos colaterais, ou realmente fizer alguma coisa, mas levar um tempo muito longo?
— Asmeurer # 15/13

@asmeurer - Por que mais você precisaria saber se é uma função se você não está chamando?
— detly

1
@detly: para depuração, eu regularmente quero imprimir todas as variáveis ​​em um objeto, os métodos geralmente não são úteis para mim, então eu não gostaria de executá-los. No final, eu apenas listar todas as propriedades não pode ser chamado com os valores correspondentes :)
— Wolph

2
Só porque você não está ligando, isso não significa que não está sendo chamado. Talvez você esteja fazendo despachos.
— asmeurer

4
Há um grande problema com o uso de exceções para saber se é possível chamar ou não; e se for possível chamar, mas chamá-lo gera uma exceção que você está procurando? Os dois ignoram silenciosamente um erro e diagnosticam incorretamente se é possível chamar. Quando você está usando o EAFP, você realmente deseja evitar tentar demais, mas não há como fazer isso neste caso de uso.
— Ben

15

Se você deseja detectar tudo o que sintaticamente se parece com uma função: uma função, método, diversão / metanfetamina incorporada, lambda ... mas exclui objetos que podem ser chamados (objetos com __call__método definido), tente o seguinte:

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

Comparei isso com o código de is*()verificações no inspectmódulo e a expressão acima é muito mais completa, especialmente se seu objetivo é filtrar quaisquer funções ou detectar propriedades regulares de um objeto.


Obrigado por me indicar o typesmódulo. Eu estava testando uma make_stemmer()fábrica que, às vezes, retornava uma função e, às vezes, uma Stemmerinstância solicitável , e precisava detectar a diferença.
— 21416 hobs


6

Se você aprendeu C++, deve estar familiarizado com function objectou functorsignifica qualquer objeto que possabe called as if it is a function .

Em C ++, an ordinary functioné um objeto de função, assim como um ponteiro de função; de maneira mais geral, também é um objeto de uma classe que define operator(). Em C ++ 11 e superior, the lambda expressioné ofunctor também.

Semelhança, em Python, essas functorssão todas callable. An ordinary functionpode ser chamado, a lambda expressionpode ser chamado, um functional.partialpode ser chamado, as instâncias de class with a __call__() methodpodem ser chamadas.


Ok, volte à pergunta: I have a variable, x, and I want to know whether it is pointing to a function or not.

Se você deseja julgar o clima, o objeto age como uma função, então o callablemétodo sugerido por@John Feminella é ok.

Se você desejar judge whether a object is just an ordinary function or not(não uma instância de classe que possa ser chamada ou uma expressão lambda), o xtypes.XXXsugerido por @Ryané uma escolha melhor.

Então eu faço um experimento usando esses 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

Defina uma classe e uma função comum.

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)

Defina os 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 a lista de functores e a 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]

Julgue se o functor é exigível. Como você pode ver, todos eles são chamados.

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

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

Julgue o tipo do functor (types.XXX). Então os tipos de functores não são todos iguais.

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>
"""

Eu desenho uma tabela de tipos de functor que podem ser chamados usando os dados.

insira a descrição da imagem aqui

Depois, você pode escolher os tipos de functores adequados.

tal 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

6

Como resposta aceita, John Feminella afirmou que:

A maneira correta de verificar as propriedades de objetos com tipo de pato é perguntar se eles grasnam, não para ver se eles se encaixam em um contêiner do tamanho de pato. A abordagem "compare diretamente" fornecerá a resposta errada para muitas funções, como builtins.

Mesmo assim, existem duas bibliotecas para distinguir estritamente as funções, eu desenho uma tabela comparável exaustiva:

8.9 types - Criação e nomes dinâmicos de tipos para tipos internos - documentação do Python 3.7.0

30.13 inspecionar - Inspecionar objetos dinâmicos - documentação do 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',
]

A "digitação de pato" é uma solução preferida para uso geral:

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

Quanto à função builtins

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

Quando avançar mais uma etapa para verificar se a função interna ou a função definida pelo usuário

#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

Determine se builtin function

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

Sumário

Empregar callablepara verificar o tipo de função,
Use types.BuiltinFunctionTypese você tiver uma demanda especificada.


5

Uma função é apenas uma classe com um __call__método, então você pode fazer

hasattr(obj, '__call__')

Por exemplo:

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

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

Essa é a "melhor" maneira de fazer isso, mas dependendo de por que você precisa saber se é possível chamar ou anotar, basta colocá-lo em um bloco try / execpt:

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

É discutível se try / except é mais Python do que fazer if hasattr(x, '__call__'): x().. Eu diria que hasattré mais preciso, já que você não pega acidentalmente o TypeError errado, por exemplo:

>>> def x():
...     raise TypeError
... 
>>> hasattr(x, '__call__')
True # Correct
>>> try:
...     x()
... except TypeError:
...     print "x was not callable"
... 
x was not callable # Wrong!

Use o tratamento de exceções para proteger apenas contra comportamentos inesperados, nunca para o fluxo lógico - isso definitivamente não é Pythonic.
— gotgenes

Bem, o hasattr basicamente faz um getattr em um bloco try / except (embora em C). blog.jancewicz.net/2007/10/reflection-hasattr.html
— dbr

@dbr: Mas o hasattr é mais estético.
— 9139 Nikhil Chelliah

5

Aqui estão algumas outras maneiras:

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

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

Aqui está como eu criei o segundo:

>>> type(lambda x: x);
<type 'function'>
>>> str(type(lambda x: x));
"<type 'function'>"
# Look Maa, function! ... I ACTUALLY told my mom about this!

Isso é legal! Deve funcionar em todas as versões do python2.xe python3.x!
— Saurav Kumar

4

Em vez de verificar para '__call__'(que não é exclusivo de funções), você pode verificar se uma função definida pelo usuário tem atributos func_name, func_docetc. Isso não funciona para métodos.

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

Outra maneira de verificar é usar o isfunction()método do inspectmódulo.

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

Para verificar se um objeto é um método, use inspect.ismethod()


4

Como as classes também têm __call__método, recomendo outra solução:

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

1
Concorde com a sua resposta, a resposta de John Feminella hasattr(obj, '__call__')é ambígua.
— GoingMyWay

4

Observe que as classes Python também são chamadas.

Para obter funções (e por funções queremos dizer funções padrão e 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)

2

Qualquer que seja a função que seja uma classe, é possível pegar o nome da classe da instância x e comparar:


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

2

As soluções usadas hasattr(obj, '__call__')e callable(.)mencionadas em algumas das respostas têm uma desvantagem principal: ambas também retornam Truepara classes e instâncias de classes com um __call__()método. Por exemplo.

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

Uma maneira adequada de verificar se um objeto é uma função definida pelo usuário (e nada além disso) é usar isfunction(.):

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

Se você precisar procurar outros tipos, dê uma olhada em Inspecionar - Inspecionar objetos ativos .


2

Um verificador exato de funções

callable é uma solução muito boa. No entanto, eu queria tratar isso da maneira oposta a John Feminella. Em vez de tratá-lo dessa maneira:

A maneira correta de verificar as propriedades de objetos com tipo de pato é perguntar se eles grasnam, não para ver se eles se encaixam em um contêiner do tamanho de pato. A abordagem "compare diretamente" fornecerá a resposta errada para muitas funções, como builtins.

Vamos tratar assim:

A maneira correta de verificar se algo é um pato não é ver se ele pode grasnar, mas sim se ele realmente é um pato através de vários filtros, em vez de apenas verificar se parece um pato da superfície.

Como o Implementaríamos

O módulo 'tipos' possui muitas classes para detectar funções, sendo as mais úteis tipos. , mas também existem muitas outras, como um tipo de método, um tipo incorporado e um tipo lambda. Também consideraremos um objeto 'functools.partial' como uma função.

A maneira simples de verificar se é uma função é usando uma condição isinstance em todos esses tipos. Anteriormente, eu queria criar uma classe base que herda todas as opções acima, mas não consigo fazer isso, pois o Python não nos permite herdar algumas das classes acima.

Aqui está uma tabela de quais classes podem classificar quais funções:

Tabela de funções de kinght- 金 Tabela de funções acima por kinght- 金

O código que faz isso

Agora, este é o código que faz todo o trabalho que descrevemos acima.

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]

A única falsa foi is_function (parcial), porque essa é uma classe, não uma função, e isso é exatamente funções, não classes. Aqui está uma prévia para você experimentar o código.

Conclusão

callable (obj) é o método preferido para verificar se um objeto é uma função se você deseja digitar o pato sobre absolutos .

Nossa função is_function (obj) personalizada , talvez com algumas edições, seja o método preferido para verificar se um objeto é uma função, se você não conta uma instância de classe que pode ser chamada como uma função, mas apenas funções definidas internas ou com lambda , def ou parcial .

E acho que isso encerra tudo. Tenha um bom dia!


1

No Python3, eu vim com o type (f) == type (lambda x:x)que produz Truese fé uma função e Falsese não é. Mas acho que prefiro isinstance (f, types.FunctionType), o que parece menos ad hoc. Eu queria fazer type (f) is function, mas isso não funciona.


0

Após respostas anteriores, eu vim com isso:

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)

0

Você pode tentar o seguinte:

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

ou até algo mais bizarro:

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

-1

Se o código continuar a executar a chamada se o valor for exigível, basta realizar a chamada e capturar TypeError.

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")

4
Isso é perigoso; você não tem idéia do que efeitos colaterais xtem.
— precisa saber é o seguinte

-2

A seguir, é uma "maneira reprovada" de verificar. Também funciona com 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

-3

Isso funciona para mim:

str(type(a))=="<class 'function'>"

1
E o que isso nos diz se o resultado for uma string vazia? Para uma função, eu recebo "<type 'function'>", por um número inteiro, eu fico "<type 'int'>", então eu não vejo como ele está funcionando para você: /
— pawamoy

Agora só funciona para Python 3 :) Também, dependendo da intenção original da pergunta, ela seria incompleta: o builtin deve openser considerado uma função? str(type(open))dá <class 'builtin_function_or_method'>em Python 3.
— pawamoy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.