Як визначити, чи є змінна Python функцією?


687

У мене є змінна, xі я хочу знати, вказує вона на функцію чи ні.

Я сподівався, що зможу зробити щось на кшталт:

>>> isinstance(x, function)

Але це дає мені:

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

Причина, яку я вибрав, це тому, що

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

37
Мене пригнічує кількість відповідей, які вирішують проблему, шукаючи якийсь атрибут виклику або функцію дзвінка ... Чистий спосіб - це тип (a) == types.functionType, як запропонував @ryan
AsTeR

44
@AsTeR Правильний спосіб перевірити властивості об’єктів типу качок - це запитати їх, чи вони стукають, а не бачити, чи вміщуються вони в контейнер розміром з качкою. Підхід "порівняти безпосередньо" дасть неправильну відповідь для багатьох функцій, як вбудовані.
Джон Фемінелла

3
@JohnFeminella Хоча я в принципі з вами згоден. ОП не запитував, чи можна телефонувати, лише якщо це функція. Можливо, можна стверджувати, що йому потрібно розмежувати, наприклад, функції та класи?
Маккей

3
Для своїх цілей я прийшов сюди, тому що хотів використовувати insepct.getsourceрізні об'єкти, і насправді важливо не те, чи об’єкт може бути викликаний, а чи це щось, що дасть "функцію" type(obj). Оскільки google привів мене сюди, я б сказав, що коментар AsTeR був найкориснішою відповіддю (для мене). В Інтернеті є багато інших місць, щоб люди могли їх відкрити __call__чи відкрити callable.
цберталан

4
@AsTeR Це типи. FunctionType, з великою буквою F.
Ben Mares

Відповіді:


892

Якщо це для 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якщо ви не маєте дуже конкретного уявлення про те, що таке функція.


73
Це також не скаже вам, чи це функція - просто, якщо її можна викликати.
Кріс Б.

23
Залежить від програми, чи відрізняє це значення чи ні; Я підозрюю, що ви праві, що це не стосується оригінального питання, але це далеко не однозначно.
Кріс Б.

5
Класи можуть мати до нього функцію дзвінка . Тож це, безумовно, не гарний метод розрізнення. Метод Райана краще.
Брайан Брюггман

43
концепція "набору качок" робить це кращою відповіддю, наприклад, "що це має значення, якщо це функція, поки вона поводиться як одна?"
jcomeau_ictx

8
Існують випадки використання, де відмінність між дзвінками та функцією є вирішальним, наприклад, під час написання декоратора (див. Мій коментар до відповіді Райана).
Туріон

267

Типи вбудованих, які не мають конструкторів у вбудованому просторі імен (наприклад, функції, генератори, методи), є у 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

Зауважте, що тут використовується дуже специфічне поняття "функція", яке зазвичай не є тим, що вам потрібно. Наприклад, він відхиляє zip(технічно клас):

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

open (вбудовані функції мають різний тип):

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

і random.shuffle(технічно метод прихованого random.Randomпримірника):

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

Якщо ви робите щось конкретне для types.FunctionTypeекземплярів, як-от декомпілювати їх байт-код або перевіряти змінні закриття, використовуйте types.FunctionType, але якщо вам просто потрібен об'єкт для виклику, як функція, використовуйте callable.


5
+1, відповідаючи на запитання. Однак, намагання вгадати, чи є об’єкт функцією - або навіть, якщо це будь-який об'єкт, що викликається - зазвичай є помилкою. Без додаткової інформації з ОП важко відмовитись від цього, звичайно, але все ж ...
bobince

47
Він фактично поверне False для вбудованих функцій, таких як "відкрити" для напр. Отже, щоб бути конкретним, вам доведеться використовувати isin substance (f, (types.FunctionType, types.BuiltinFunctionType)). І звичайно, якщо ви строго хочете просто функцій, а не дзвінки та методи.
Лукаш Коржибський

5
@ ŁukaszKorzybski і, щоб бути більш чіткими, ви також повинні перевірити функцію functools.partial: isinstance(f, (types.FunctionType, types.BuiltinFunctionType, functools.partial))або перевірити f.funcв такому випадку.
estani

3
@bobince, як щодо цього набору: я хочу написати декоратор, @fooякий я можу використовувати як @fooі як @foo(some_parameter). Потім потрібно перевірити, з чим викликається, наприклад, функція прикраси (перший випадок) або параметр (другий випадок, у якому йому потрібно повернути подальший декоратор).
Туріон

types.BuiltinFunctionTypeтакож є типом ("нормальних") вбудованих методів , які ви, мабуть, не бажаєте дозволити, якщо ви не збираєтесь callableмаршрутом.
user2357112 підтримує Моніку

92

З Python 2.1 ви можете імпортувати isfunctionз inspectмодуля.

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

3
Добре, але, здається, повертається False для вбудованих функцій, таких як openі hasattr.
Zecc

12
@Zecc isbuiltin для цього.
Паоло

13
Див. inspect.isfunctionDocstring: "Повернути true, якщо об'єкт є визначеною користувачем функцією."
Марк Мікофський

4
Зауважте, що "isfunction" не розпізнає functool.partial функції.
ishmael

74

Прийнята відповідь була в той момент, коли їй запропонували вважати правильною. Як з'ясовується, немає ніякої заміни для 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
Дивовижна ілюстрація підводних каменів hasattr(o, '__call__')підходу і чому callable(), якщо вони є, є вищими.
MestreLion

39

Наступне має повернути булеве значення:

callable(x)

1
Це вирішує його проблему, але він все ще створив таємницю: якщо x класу 'function' в модулі вбудований , а довідка (x .__ class__) описує «функцію класу», чому «функція», мабуть, «не визначена»?
Кен

1
"функція" не є ключовим словом або вбудованим типом. Тип функцій визначається в модулі "типи", як "types.FunctionType"
Кріс Б.

25

Інструмент 2to3 Python ( http://docs.python.org/dev/library/2to3.html ) пропонує:

import collections
isinstance(obj, collections.Callable)

Здається, це було вибрано замість hasattr(x, '__call__')методу через http://bugs.python.org/issue7006 .


1
Він також згадується у звіті про помилку щодо повернення callable()для py3.3: bugs.python.org/issue10518#msg122309
luckydonald

19

callable(x) буде повертати істину , якщо переданий об'єкт може бути викликаний в 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коли виконується, або не називається в першу чергу. Це може не мати для вас значення.


8
Називати це - погана ідея. Що робити, якщо вона має побічні ефекти, або насправді щось робить, але займає дуже довго?
асмеурер

@asmeurer - Навіщо ще потрібно знати, чи це функція, якщо ти її не викликаєш?
detly

1
@detly: для налагодження я регулярно хочу надрукувати всі змінні в об'єкті, методи мені зазвичай не корисні, тому я не хотів би їх виконувати. Врешті-решт я лише перелічу кожну власність, яка не
вимагає дзвінків,

2
Тільки тому, що ви не телефонуєте, це не означає, що його не дзвонять. Можливо, ви робите відправлення.
asmeurer

4
Існує велика проблема використання винятків, щоб дізнатись, чи можна їх називати чи ні; що робити, якщо він може дзвонити, але виклик викликає виняток? Ви обидва мовчки проігноруєте помилку та помилково будете діагностувати, чи було вона викликана. Коли ви використовуєте EAFP, ви дійсно хочете уникати занадто багато спроб, але в цьому випадку використання цього немає.
Бен

15

Якщо ви хочете виявити все, що синтаксично виглядає як функція: функцію, метод, вбудовану забаву / meth, лямбда ..., але виключати об'єкти, що викликаються (об'єкти із __call__визначеним методом), спробуйте це:

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

Я порівнював це з кодом is*()перевірок у inspectмодулі, і вираз, наведений вище, набагато повніше, особливо якщо ваша мета - фільтрація будь-яких функцій або виявлення регулярних властивостей об'єкта.


Дякую, що вказали мені на typesмодуль. Я тестував make_stemmer()завод, який інколи повертав би функцію, а іноді іменник, який може викликати Stemmer, і мені потрібно було виявити різницю.
варильні панелі


6

Якщо ви дізналися 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 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

6

Як прийнята відповідь, Джон Фемінелла заявив, що:

Правильний спосіб перевірити властивості об’єктів типу качок - це запитати, чи вони стукають, а не бачити, чи вміщуються вони в контейнер розміром з качкою. Підхід "порівняти безпосередньо" дасть неправильну відповідь для багатьох функцій, як вбудовані.

Незважаючи на те, що для чіткого розмежування функцій є два вкладки, я малюю вичерпну порівняльну таблицю:

8.9. типи - створення динамічного типу та назви вбудованих типів - документація 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якщо ви додатково вказали попит.


5

Функція - це просто клас з __call__методом, так що ви можете це робити

hasattr(obj, '__call__')

Наприклад:

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

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

Це "найкращий" спосіб зробити це, але залежно від того, чому вам потрібно знати, чи він може дзвонити чи відзначати, ви можете просто помістити його в блок try / execpt:

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

Це сперечається, якщо спробувати / за винятком більше 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!

Використовуйте обробку винятків лише для захисту від несподіваної поведінки, ніколи для логічного потоку - це, безумовно, не піфонічно.
gotgenes

Ну, hasattr в основному робить getttr у спробу / крім блоку (хоча і в С). blog.jancewicz.net/2007/10/reflection-hasattr.html
dbr

@dbr: Але hasattr є більш естетичним.
Nikhil Chelliah

5

Ось кілька інших способів:

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!

Це добре! Має працювати над усіма версіями python2.x та python3.x!
Саурав Кумар

4

Замість перевірки '__call__'(яка не є винятковими функції), ви можете перевірити , чи є певний користувач функції атрибути func_name, func_docі т.д. Це не працює для методів.

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

Ще один спосіб перевірки - це використання isfunction()методу з inspectмодуля.

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

Щоб перевірити, чи є об’єктом метод, використовуйте inspect.ismethod()


4

Оскільки в класах також є __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

1
згоден з вашою відповіддю, відповідь Джона Фемінелли hasattr(obj, '__call__')неоднозначна.
GoingMyWay

4

Зауважте, що класи 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)

2

Яка б функція не була класом, тому ви можете взяти назву класу екземпляра x і порівняти:


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

2

Рішення, що використовуються 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

Якщо вам потрібно перевірити інші типи, подивіться на огляд - Огляньте живі об’єкти .


2

Точна перевірка функцій

callable - це дуже хороше рішення. Однак я хотів ставитися до цього навпаки Джона Фемінелла. Замість того, щоб трактувати це так:

Правильний спосіб перевірити властивості об’єктів типу качок - це запитати, чи вони стукають, а не бачити, чи вміщуються вони в контейнер розміром з качкою. Підхід "порівняти безпосередньо" дасть неправильну відповідь для багатьох функцій, як вбудовані.

Ми будемо ставитися до цього так:

Правильний спосіб перевірити, чи є щось каченя, - це не бачити, чи може вона стукати, а краще перевірити, чи справді це качка через кілька фільтрів, а не просто перевірити, чи здається вона качкою з поверхні.

Як би ми це здійснили

Модуль 'types' має безліч класів для виявлення функцій, найбільш корисними є типи.FunctionType , але також є багато інших, наприклад тип методу, вбудований тип і лямбда-тип. Ми також розглянемо функцію 'functools.partial' як функцію.

Найпростіший спосіб перевірити, чи є це функцією, - використовуючи умову щодо речовин у всіх цих типах. Раніше я хотів створити базовий клас, який успадковує все вищезазначене, але я не в змозі зробити це, оскільки Python не дозволяє нам успадкувати деякі з перерахованих вище класів.

Ось таблиця, на які класи можна класифікувати функції:

Таблиця функцій від kinght- 金 Над таблицею функцій від 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) , можливо, за допомогою деяких редагувань є кращим методом перевірити, чи є об'єкт функцією, якщо ви не вважаєте будь-який екземпляр класу, що можна викликати, як функцію, а лише функції, визначені вбудованим , або з лямбда , def або частково .

І я думаю, що це все завершує. Гарного дня!


1

У Python3 я придумав, type (f) == type (lambda x:x)що прибутковість, Trueякщо fце функція, а Falseякщо ні. Але я вважаю, що віддаю перевагу isinstance (f, types.FunctionType), що відчуває себе менш спеціально. Я хотів це зробити type (f) is function, але це не виходить.


0

Після попередніх відповідей я придумав це:

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

Ви можете спробувати це:

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

або навіть щось більш химерне:

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

-1

Якщо код буде продовжувати виконувати дзвінок, якщо значення можна викликати, просто виконайте виклик і вловіть TypeError.

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

4
Це небезпечно; Ви поняття не маєте, які побічні ефекти xє.
cwallenpoole

-2

Далі йде "спосіб повторного", щоб перевірити це. Також працює з лямбда.

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

Це працює для мене:

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

1
І що це нам говорить, якщо результат - порожній рядок? Для функції я отримую "<type 'function'>", для цілого числа я отримую "<type 'int'>", тому я не бачу, як це працює для вас: /
pawamoy

Зараз працює лише для Python 3 :) Також залежно від початкового наміру питання було б неповним: чи варто openвважати вбудовану функцією? str(type(open))дає <class 'builtin_function_or_method'>в Python 3.
pawamoy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.