Как определить, является ли переменная 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'>
Ответы
Ответ 1
Если это для Python 2.x или для Python 3.2+, вы также можете использовать callable()
. Раньше оно было устаревшим, но теперь оно не учитывается, поэтому вы можете использовать его снова. Вы можете прочитать обсуждение здесь: http://bugs.python.org/issue10518. Вы можете сделать это с помощью:
callable(obj)
Если это для Python 3.x, но до 3.2, проверьте, имеет ли объект атрибут __call__
. Вы можете сделать это с помощью:
hasattr(obj, '__call__')
Предлагаемый подход types.FunctionTypes
неверен, поскольку он не охватывает многие случаи, которые вы, вероятно, хотите передать, например, со встроенными:
>>> isinstance(open, types.FunctionType)
False
>>> callable(open)
True
Правильный способ проверки свойств объектов с утиным типом - спросить их, могут ли они крякать, а не видеть, подходят ли они в контейнере размером с утку. Не используйте types.FunctionType
, если у вас нет конкретной идеи о том, что такое функция.
Ответ 2
Встроенные типы, которые не имеют конструкторов во встроенном пространстве имен (например, функции, генераторы, методы), находятся в модуле 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
Ответ 3
Начиная с Python 2.1 вы можете импортировать isfunction
из модуля inspect
.
>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True
Ответ 4
Принятый ответ был в то время, когда он был предложен, считался правильным. Как оказалось, ничто не заменит 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
. Тем не менее, на самом деле нет никакого возможного способа, которым он мог бы дать более точный результат, чем результат, чем при использовании самого callable()
, поскольку метод слота typeobject->tp_call
недоступен каким-либо другим способом.
Просто используйте callable()
Ответ 5
Следующее должно возвращать логическое значение:
callable(x)
Ответ 6
Инструмент Python 2to3 (http://docs.python.org/dev/library/2to3.html) предлагает:
import collections
isinstance(obj, collections.Callable)
Кажется, это было выбрано вместо метода hasattr(x, '__call__')
из-за http://bugs.python.org/issue7006.
Ответ 7
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
отлично работает, чтобы определить, является ли что-то функцией (try isinstance(b, types.FunctionType)
); если вам действительно интересно узнать, можно ли что-то вызвать, вы можете использовать hasattr(b, '__call__')
или просто попробовать.
test_as_func = True
try:
b()
except TypeError:
test_as_func = False
except:
pass
Это, конечно, не скажет вам, является ли оно вызываемым, но выбрасывает TypeError
при его выполнении или не может быть вызвано в первую очередь. Это может не иметь значения для вас.
Ответ 8
Если вы хотите обнаружить все, что синтаксически выглядит как функция: функция, метод, встроенный метод fun/meth, lambda..., но исключить вызываемые объекты (объекты с методом __call__
), затем попробуйте следующее:
import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))
Я сравнил это с кодом проверки is*()
в модуле inspect
, и приведенное выше выражение намного более полно, особенно если ваша цель заключается в фильтрации любых функций или обнаружении регулярных свойств объекта.
Ответ 9
Вот несколько других способов:
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!
Ответ 10
Попробуйте использовать callable(x)
.
Ответ 11
Функция - это просто класс с методом __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, чем делать 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!
Ответ 12
Если вы узнали 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
может вызываться, functional.partial
может вызываться, экземпляры class with a __call__() method
могут вызываться.
Хорошо, вернемся к вопросу: у I have a variable, x, and я 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]
"""
Оцените тип функтора (types.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>
"""
Я рисую таблицу типов вызываемых функторов, используя данные.
![enter image description here]()
Затем вы можете выбрать типы функторов, которые подходят.
такие как:
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
Ответ 13
В качестве принятого ответа Джон Феминелла заявил, что:
Правильный способ проверить свойства объектов типа "утка" - это спросить их, если они крякают, а не посмотреть, помещаются ли они в контейнер размером с утку. Подход "сравните это напрямую" даст неправильный ответ для многих функций, например для встроенных.
Несмотря на то, что есть две библиотеки, чтобы строго различать функции, я рисую исчерпывающую сопоставимую таблицу:
8.9. types - Создание динамических типов и имен для встроенных типов - Документация по Python 3.7.0
30,13. осматривать - проверять живые объекты - документация по 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',
]
"Утиная печать" является предпочтительным решением для общего назначения:
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
Что касается встроенной функции
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 function
In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False
Резюме
Используйте callable
для проверки типа функции утки,
Используйте types.BuiltinFunctionType
, если у вас есть дополнительные требования.
Ответ 14
Поскольку классы также имеют метод __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
Ответ 15
Обратите внимание, что классы 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)
Ответ 16
Вместо проверки на '__call__'
(что не является исключением для функций) вы можете проверить, имеет ли пользовательская функция атрибуты func_name
, func_doc
и т.д. Это не работает для методов.
>>> def x(): pass
...
>>> hasattr(x, 'func_name')
True
Другой способ проверки - использовать метод isfunction()
из модуля inspect
.
>>> import inspect
>>> inspect.isfunction(x)
True
Чтобы проверить, является ли объект методом, используйте inspect.ismethod()
Ответ 17
Любая функция - это класс, поэтому вы можете взять имя класса экземпляра x и сравнить:
if(x.__class__.__name__ == 'function'):
print "it a function"
Ответ 18
Решения с использованием 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
Если вам нужно проверить другие типы, просмотрите проверить - проверить живые объекты.
Ответ 19
Проверка точных функций
callable - это очень хорошее решение. Однако я хотел относиться к этому противоположно Джону Феминелле. Вместо того, чтобы относиться к этому так:
Правильный способ проверить свойства объектов типа "утка" - это спросить их, если они крякают, а не посмотреть, помещаются ли они в контейнер размером с утку. Подход "сравните это напрямую" даст неправильный ответ для многих функций, например для встроенных.
Мы будем относиться к этому так:
Правильный способ проверить, является ли что-то уткой, - это не посмотреть, может ли она крякать, а посмотреть, действительно ли это утка, через несколько фильтров, а не просто проверить, выглядит ли она как утка с поверхности.
Как бы мы это реализовали
Модуль 'types' имеет множество классов для обнаружения функций, наиболее полезными из которых являются types.FunctionType, но есть и множество других, таких как тип метода, встроенный тип и лямбда-тип. Мы также будем рассматривать объект functools.partial как функцию.
Простой способ проверить, является ли это функцией, заключается в использовании условия isinstance для всех этих типов. Ранее я хотел создать базовый класс, который наследует все вышеперечисленное, но я не могу этого сделать, так как Python не позволяет нам наследовать от некоторых из вышеперечисленных классов.
Вот таблица того, какие классы могут классифицировать, какие функции:
Над таблицей функций kinght- 金
Код, который делает это
Теперь этот код выполняет всю работу, описанную выше.
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]
Ложным был is_function (частичный), потому что это класс, а не функция, и это именно функции, а не классы. Вот предварительный просмотр для вас, чтобы попробовать код из.
Заключение
callable (obj) - это предпочтительный метод для проверки того, является ли объект функцией, если вы хотите ввести утку, набирающую абсолютные значения.
Наш пользовательский is_function (obj), возможно, с некоторыми правками, является предпочтительным методом проверки, является ли объект функцией, если вы не учитываете экземпляр вызываемого класса как функцию, а только функции, определенные встроенными или с лямбдой, определением или частичным.
И я думаю, что это все завершает. Хорошего дня!
Ответ 20
В Python3 я придумал type (f) == type (lambda x:x)
, который дает True
, если f
- это функция и False
, если это не так. Но я думаю, что предпочитаю isinstance (f, types.FunctionType)
, который чувствует себя менее ad hoc. Я хотел сделать type (f) is function
, но это не сработает.
Ответ 21
Следуя предыдущим ответам, я придумал следующее:
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)
Ответ 22
Если код будет выполнен для выполнения вызова, если это значение является вызываемым, просто выполните вызов и поймайте TypeError
.
def myfunc(x):
try:
x()
except TypeError:
raise Exception("Not callable")
Ответ 23
Ниже приведен "способ 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
Ответ 24
Это работает для меня:
str(type(a))=="<class 'function'>"