Python type builtin function or method

How do I detect whether a variable is a function?

I have a variable, x , and I want to know whether it is pointing to a function or not. I had hoped I could do something like:

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

I’m depressed by the number of answers working around the problem by looking for some call attribute or callable function. A clean way is about type(a) == types.functionType as suggested by @ryan

@AsTeR The proper way to check properties of duck-typed objects is to ask them if they quack, not to see if they fit in a duck-sized container. The «compare it directly» approach will give the wrong answer for many functions, like builtins.

@JohnFeminella While I agree with you in principle. The OP didn’t ask if it was callable, just if it is a function. Perhaps it could be argued that he needed a distinction between, for example, functions and classes?

For my purposes, I came here because I wanted to use insepct.getsource on a variety of objects, and it actually matters not whether the object was callable but whether it was something that would give ‘function’ for type(obj) . Since google led me here, I’d say AsTeR’s comment was the most useful answer (for me). There are plenty of other places on the internet for people to discover __call__ or callable .

30 Answers 30

If this is for Python 2.x or for Python 3.2+, you can use callable() . It used to be deprecated, but is now undeprecated, so you can use it again. You can read the discussion here: http://bugs.python.org/issue10518. You can do this with:

If this is for Python 3.x but before 3.2, check if the object has a __call__ attribute. You can do this with:

The oft-suggested types.FunctionTypes or inspect.isfunction approach (both do the exact same thing) comes with a number of caveats. It returns False for non-Python functions. Most builtin functions, for example, are implemented in C and not Python, so they return False :

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

so types.FunctionType might give you surprising results. The proper way to check properties of duck-typed objects is to ask them if they quack, not to see if they fit in a duck-sized container.

Depends on the application whether the distinction matters or not; I suspect you’re right that it doesn’t for the original question, but that’s far from certain.

Читайте также:  File diff in python

Classes can have a call function attached to it. So this is definitely not a good method for distinguishing. Ryan’s method is better.

the «duck typing» concept makes this the better answer, e.g. «what does it matter if it’s a function as long as it behaves like one?»

There are usecases where the distinction between a callable and a function is crucial, for example when writing a decorator (see my comment on Ryan’s answer).

Builtin types that don’t have constructors in the built-in namespace (e.g. functions, generators, methods) are in the types module. You can use types.FunctionType in an isinstance call:

>>> import types >>> types.FunctionType >>> def f(): pass >>> isinstance(f, types.FunctionType) True >>> isinstance(lambda x : None, types.FunctionType) True 

Note that this uses a very specific notion of «function» that is usually not what you need. For example, it rejects zip (technically a class):

>>> type(zip), isinstance(zip, types.FunctionType) (, False) 

open (built-in functions have a different type):

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

and random.shuffle (technically a method of a hidden random.Random instance):

>>> type(random.shuffle), isinstance(random.shuffle, types.FunctionType) (, False) 

If you’re doing something specific to types.FunctionType instances, like decompiling their bytecode or inspecting closure variables, use types.FunctionType , but if you just need an object to be callable like a function, use callable .

+1 answering the question. However, trying to guess whether an object is a function — or even if it is any callable object — is usually a mistake. Without further information from the OP it’s difficult to dismiss it out of hand of course, but still.

It will actually return False for builtin functions, like ‘open’ for eg. So to be specific you will have to use isinstance(f, (types.FunctionType, types.BuiltinFunctionType)). And of course if you strictly want just functions, not callables nor methods.

@ŁukaszKorzybski and to be more precdise. you should also check for functools.partial: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial)) or checking f.func in such a case.

@bobince, how about this usecase: I want to write a decorator @foo that I can use both as @foo and as @foo(some_parameter) . It then needs to check what it is being called with, e.g. the function to decorate (first case) or the parameter (the second case, in which it needs to return a further decorator).

types.BuiltinFunctionType is also the type of («normal») built-in methods, which you probably don’t want to allow, if you’re not going the callable route.

Читайте также:  hmarketing.ru

Since Python 2.1 you can import isfunction from the inspect module.

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

The entire source code of isfunction is return isinstance(object, types.FunctionType) so it comes with the caveats pointed out in @Ryan’s answer.

The accepted answer was at the time it was offered thought to be correct. As it turns out, there is no substitute for callable() , which is back in Python 3.2: Specifically, callable() checks the tp_call field of the object being tested. There is no plain Python equivalent. Most of the suggested tests are correct most of the time:

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

We can throw a monkey-wrench into this by removing the __call__ from the class. And just to keep things extra exciting, add a fake __call__ to the instance!

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

Notice this really isn’t callable:

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

callable() returns the correct result:

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

can_o_spam does have that attribute after all; it’s just not used when calling the instance.

Even more subtle, isinstance() also gets this wrong:

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

Because we used this check earlier and later deleted the method, abc.ABCMeta caches the result. Arguably this is a bug in abc.ABCMeta . That said, there’s really no possible way it could produce a more accurate result than the result than by using callable() itself, since the typeobject->tp_call slot method is not accessible in any other way.

Amazing illustration of the pitfalls of hasattr(o, ‘__call__’) approach and why callable() , if available, is superior.

To be fair, the correct use of hasattr would check type(o) , not o itself, and you can just as easily fool callable by patching Spam.__call__ instead of shadowing it with an instance attribute. Set Spam.__call__ = 3 , and callable(Spam()) still returns True . Ultimately, the only definitive test for when an object is callable is to try calling it.

The following should return a boolean:

That solves his problem, but he’s still created a mystery: if x is of class ‘function’ in module builtin, and help(x.__class__) describes «class function», why is «function» apparently «not defined»?

Читайте также:  Preview

«function» isn’t a keyword or a built-in type. The type of functions is defined in the «types» module, as «types.FunctionType»

Result

callable(x) hasattr(x, ‘__call__’) inspect.isfunction(x) inspect.ismethod(x) inspect.isgeneratorfunction(x) inspect.iscoroutinefunction(x) inspect.isasyncgenfunction(x) isinstance(x, typing.Callable) isinstance(x, types.BuiltinFunctionType) isinstance(x, types.BuiltinMethodType) isinstance(x, types.FunctionType) isinstance(x, types.MethodType) isinstance(x, types.LambdaType) isinstance(x, functools.partial)
print × × × × × × × × ×
func × × × × × × × ×
functools.partial × × × × × × × × × ×
× × × × × × × ×
generator × × × × × × ×
async_func × × × × × × ×
async_generator × × × × × × ×
A × × × × × × × × × × ×
meth × × × × × × × ×
classmeth × × × × × × × × ×
staticmeth × × × × × × × ×
import types import inspect import functools import typing def judge(x): name = x.__name__ if hasattr(x, '__name__') else 'functools.partial' print(name) print('\ttype(<>)=<>'.format(name, type(x))) print('\tcallable(<>)=<>'.format(name, callable(x))) print('\thasattr(<>, \'__call__\')=<>'.format(name, hasattr(x, '__call__'))) print() print('\tinspect.isfunction(<>)=<>'.format(name, inspect.isfunction(x))) print('\tinspect.ismethod(<>)=<>'.format(name, inspect.ismethod(x))) print('\tinspect.isgeneratorfunction(<>)=<>'.format(name, inspect.isgeneratorfunction(x))) print('\tinspect.iscoroutinefunction(<>)=<>'.format(name, inspect.iscoroutinefunction(x))) print('\tinspect.isasyncgenfunction(<>)=<>'.format(name, inspect.isasyncgenfunction(x))) print() print('\tisinstance(<>, typing.Callable)=<>'.format(name, isinstance(x, typing.Callable))) print('\tisinstance(<>, types.BuiltinFunctionType)=<>'.format(name, isinstance(x, types.BuiltinFunctionType))) print('\tisinstance(<>, types.BuiltinMethodType)=<>'.format(name, isinstance(x, types.BuiltinMethodType))) print('\tisinstance(<>, types.FunctionType)=<>'.format(name, isinstance(x, types.FunctionType))) print('\tisinstance(<>, types.MethodType)=<>'.format(name, isinstance(x, types.MethodType))) print('\tisinstance(<>, types.LambdaType)=<>'.format(name, isinstance(x, types.LambdaType))) print('\tisinstance(<>, functools.partial)=<>'.format(name, isinstance(x, functools.partial))) def func(a, b): pass partial = functools.partial(func, a=1) _lambda = lambda _: _ def generator(): yield 1 yield 2 async def async_func(): pass async def async_generator(): yield 1 class A: def __call__(self, a, b): pass def meth(self, a, b): pass @classmethod def classmeth(cls, a, b): pass @staticmethod def staticmeth(a, b): pass for func in [print, func, partial, _lambda, generator, async_func, async_generator, A, A.meth, A.classmeth, A.staticmeth]: judge(func) 

Time

Pick the three most common methods:

import typing from timeit import timeit def x(): pass def f1(): return callable(x) def f2(): return hasattr(x, '__call__') def f3(): return isinstance(x, typing.Callable) print(timeit(f1, number=10000000)) print(timeit(f2, number=10000000)) print(timeit(f3, number=10000000)) # 0.8643081 # 1.3563508 # 12.193492500000001 

Источник

Оцените статью