Как определить, является ли переменная Python функцией?
у меня есть переменная, x, и я хочу знать, указывает ли он на функцию или нет.
Я надеялся, что смогу сделать что-то вроде:
>>> isinstance(x, function)
но это дает мне:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'function' is not defined
причина, по которой я выбрал это, потому что
>>> type(x)
<type 'function'>
22 ответов:
если это для Python 2.x или для Python 3.2+, вы также можете использовать
callable(). Раньше он был устаревшим, но теперь не является устаревшим, поэтому вы можете использовать его снова. Вы можете прочитать обсуждение здесь:http://bugs.python.org/issue10518. вы можете сделать это с помощью:callable(obj)если это для Python 3.x но перед 3.2, проверьте, если объект имеет . Вы можете сделать это с:
hasattr(obj, '__call__')часто-предложил
types.FunctionTypesподход не является правильным, потому что он не удается охватить многие случаи, которые вы, по-видимому, хотите, чтобы он прошел, например, с builtins:>>> isinstance(open, types.FunctionType) False >>> callable(open) Trueправильный способ проверить свойства объектов утиного типа-спросить их, если они крякают, а не видеть, помещаются ли они в контейнер размером с утку. Не используйте
types.FunctionTypeесли у вас очень специфическое представление о том, что такое функция.
встроенные типы, которые не имеют конструкторов во встроенном пространстве имен (например, функции, генераторы, методы) находятся в
typesмодуль. Вы можете использоватьtypes.FunctionTypeв вызове isinstance.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
Начиная С Python 2.1 можно импортировать
isfunctionСinspectмодуль.>>> from inspect import isfunction >>> def f(): pass >>> isfunction(f) True >>> isfunction(lambda x: x) True
принятый ответ был в то время, когда его предлагали считать правильным. Как это оказывается, есть никакой замены на
callable(), который вернулся в Python 3.2: в частности,callable()проверкаtp_callполе объекта проверенный. Нет простого эквивалента Python. Большинство предложенных тестов являются правильно большую часть времени:>>> 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мы можем бросить гаечный ключ в это, удалив
__call__от класс. И просто, чтобы держать вещи дополнительно захватывающие, добавить поддельные__call__к примеру!>>> del Spam.__call__ >>> can_o_spam.__call__ = lambda *args: 'OK?'обратите внимание, что это действительно не вызывается:
>>> can_o_spam() Traceback (most recent call last): ... TypeError: 'Spam' object is not callable
callable()возвращает правильный результат:>>> callable(can_o_spam) Falseно
hasattrи неправильно:>>> hasattr(can_o_spam, '__call__') True
can_o_spamимеет этот атрибут в конце концов; он просто не используется при вызове экземпляр.еще тоньше,
isinstance()также получает это неправильно:>>> isinstance(can_o_spam, collections.Callable) Trueпотому что мы использовали эту проверку ранее и позже удалил метод,
abc.ABCMetaкэширует результат. Возможно, это ошибка вabc.ABCMeta. Что сказал, это действительно невозможно может произвести более точный результат, чем результат, чем с помощью Сtypeobject->tp_callметод слота не доступен никаким другим способом.просто использовать
callable()
инструмент Python 2to3 (http://docs.python.org/dev/library/2to3.html) предлагает:
import collections isinstance(obj, collections.Callable)Кажется, это было выбрано вместо
hasattr(x, '__call__')метод из-за http://bugs.python.org/issue7006.
callable(x)будет возвращает true, если переданный объект может быть вызван в Python, но функция не существует в Python 3.0, и, собственно говоря, не будет различать: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)вы получаете
<class 'A'> Trueи<type function> Trueкак выходной.
isinstanceотлично работает, чтобы определить, является ли что-то функцией (попробуйтеisinstance(b, types.FunctionType)); если вам действительно интересно узнать, можно ли что-то назвать, вы можете использоватьhasattr(b, '__call__')или просто попробовать оно.test_as_func = True try: b() except TypeError: test_as_func = False except: passэто, конечно, не скажет вам, является ли это вызываемым, но бросает
TypeErrorкогда он выполняется, или не вызывается в первую очередь. Это может не иметь значения для вас.
если вы хотите обнаружить все, что синтаксически выглядит как функция: функция, метод, встроенный fun/meth, lambda ... но исключить вызываемые объекты (объекты с
__call__метод определен), то попробуйте этот:import types isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))Я сравнил это с кодом
is*()проверки вinspectмодуль и приведенное выше выражение намного полнее, особенно если ваша цель-отфильтровать любые функции или обнаружить регулярные свойства объекта.
функция-это просто класс
__call__метод, так что вы можете сделатьhasattr(obj, '__call__')например:
>>> hasattr(x, '__call__') True >>> x = 2 >>> hasattr(x, '__call__') Falseэто "лучший" способ сделать это, но в зависимости от того, почему вам нужно знать, можно ли его вызвать или отметить, Вы можете просто поместить его в блок try/execpt:
try: x() except TypeError: print "was not callable"это спорно, если try / except больше Python'y, чем doing
if hasattr(x, '__call__'): x().. Я бы сказалhasattrболее точно, так как вы случайно не поймаете неправильный TypeError, ибо пример:>>> def x(): ... raise TypeError ... >>> hasattr(x, '__call__') True # Correct >>> try: ... x() ... except TypeError: ... print "x was not callable" ... x was not callable # Wrong!
вот еще несколько способов:
def isFunction1(f) : return type(f) == type(lambda x: x); def isFunction2(f) : return 'function' in str(type(f));вот как я придумал второй:
>>> type(lambda x: x); <type 'function'> >>> str(type(lambda x: x)); "<type 'function'>" # Look Maa, function! ... I ACTUALLY told my mom about this!
Так как классы тоже есть
__call__метод, я рекомендую другое решение: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
обратите внимание, что классы Python также вызываются.
чтобы получить функции (а под функциями мы подразумеваем стандартные функции и лямбды) используйте:
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)
вместо проверки
'__call__'(что не является исключительным для функций), вы можете проверить, имеет ли пользовательская функция атрибутыfunc_name,func_docи т. д. Это не работает для методов.>>> def x(): pass ... >>> hasattr(x, 'func_name') Trueдругой способ проверки-это использование
isfunction()методinspectмодуль.>>> import inspect >>> inspect.isfunction(x) Trueчтобы проверить, является ли объект методом, используйте
inspect.ismethod()
если вы узнали
C++, вы должны быть знакомы сfunction objectилиfunctorозначает любой объект, который можетbe called as if it is a function.В C++,
an ordinary function- это объект функции, а также указатель на функцию; в более общем случае, это объект класса, который определяетoperator(). В C++11 и выше,the lambda expression- этоfunctorтоже.сходство, в Python, те
functorsвсеcallable.An ordinary functionможно вызвать,a lambda expressionможет быть callable, afunctional.partialможет вызываться, экземплярыclass with a __call__() methodможет вызываться.
Хорошо, вернемся к вопросу:
I have a variable, x, and I want to know whether it is pointing to a function or not.если вы хотите судить о погоде объект действует как функция, то
callableметод, предложенный@John FeminellaОК.если вы хотите
judge whether a object is just an ordinary function or not( не вызываемый экземпляр класса, или лямбда-выражение), тоxtypes.XXXпредложил@Ryan- это лучший выбор.затем я делаю эксперимент, используя те код:
#!/usr/bin/python3 # 2017.12.10 14:25:01 CST # 2017.12.10 15:54:19 CST import functools import types import pprintопределите класс и обычную функцию.
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)определить функторы:
#(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Определите список функторов и список типов:
## 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]судья ли функтор вызывается. Как вы можете видеть, все они являются вызываемыми.
res = [callable(xfunc) for xfunc in xfuncs] print("functors callable:") print(res) """ functors callable: [True, True, True, True, True, True, True, True] """судить о типе функтора( типы.XXX). Затем типы функторы не все одинаковы.
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> """
я рисую таблицу типов вызываемого функтора, используя данные.
затем вы можете выбрать типы функторов, которые подходят.
, например:
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
любая функция является классом, поэтому вы можете взять имя класса экземпляра x и сравнить:
if(x.__class__.__name__ == 'function'): print "it's a function"
решения с использованием
hasattr(obj, '__call__')иcallable(.)упомянутые в некоторых ответах имеют главный недостаток: оба также возвращаютTrueдля классов и экземпляров классов с__call__()метод. Например.>>> import collections >>> Test = collections.namedtuple('Test', []) >>> callable(Test) True >>> hasattr(Test, '__call__') Trueодин правильный способ проверить, является ли объект пользовательской функцией (и ничего, кроме этого), заключается в использовании
isfunction(.):>>> import inspect >>> inspect.isfunction(Test) False >>> def t(): pass >>> inspect.isfunction(t) TrueЕсли вам нужно проверить другие типы, посмотрите на осмотр - осмотр живых объектов.
в качестве принятого ответа Джон Феминелла заявил, что:
правильный способ проверить свойства объектов утиного типа-спросить их, если они крякают, а не видеть, помещаются ли они в контейнер размером с утку. Подход "сравнить его напрямую" даст неправильный ответ для многих функций, таких как встроенные функции.
несмотря на то, что есть две библиотеки, чтобы строго различать функции, я рисую исчерпывающую сопоставимую таблицу:
8.9. типы - Динамическое создание типов и имен для встроенных типов-Python 3.7.0 documentation
30.13. осмотреть - осмотр живых объектов - питон 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', ]"утка набрав" является предпочтительным решением для общего назначения:
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Что касается функции builtins
In [43]: callable(hasattr) Out[43]: Trueкогда идти еще один шаг, чтобы проверить, если встроенная функция или определяемая пользователем функция
#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определить, если
builtin functionIn [50]: isinstance(getattr, types.BuiltinFunctionType) Out[50]: True In [51]: isinstance(detect_function, types.BuiltinFunctionType) Out[51]: Falseрезюме
использовать
callableдля проверки типа утки функции,
Используйтеtypes.BuiltinFunctionTypeесли вы дополнительно указали требование.
в Python3 я придумал
type (f) == type (lambda x:x), который даетTrueеслиfфункция иFalseесли это не так. Но я думаю, что предпочитаюisinstance (f, types.FunctionType), который чувствует себя менее ad hoc. Я хотел сделатьtype (f) is function, но это не работает.
после предыдущих ответов, я придумал это:
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)
Если код будет продолжать выполнять вызов, если значение вызывается, просто выполните вызов и поймать
TypeError.def myfunc(x): try: x() except TypeError: raise Exception("Not callable")
ниже приведен "способ repr", чтобы проверить его. Также он работает с лямбда.
def a():pass type(a) #<class 'function'> str(type(a))=="<class 'function'>" #True b = lambda x:x*2 str(type(b))=="<class 'function'>" #True

Comments