Как определить, является ли переменная 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'>
436   22  

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

следующее должно возвращать логическое значение:

callable(x)

инструмент 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 модуль и приведенное выше выражение намного полнее, особенно если ваша цель-отфильтровать любые функции или обнаружить регулярные свойства объекта.

попробуйте использовать callable(x).

функция-это просто класс __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, a functional.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>
"""

я рисую таблицу типов вызываемого функтора, используя данные.

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

любая функция является классом, поэтому вы можете взять имя класса экземпляра 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 function

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

    Ничего не найдено.