2010-03-17 4 views
6

Поскольку функции являются значениями в Python, как определить, является ли переменная функцией?Как определить, является ли переменная функцией в Python?

Например:

boda = len # boda is the length function now 
if ?is_var_function(boda)?: 
    print "Boda is a function!" 
else: 
    print "Boda is not a function!" 

Здесь гипотетическая ?is_var_function(x)? должен возвращать истину, если x является вызываемой функцией, и ложь, если это не так.

+0

Вы хотите, чтобы это возвращало true для классов, так как они могут быть вызваны? – Javier

+4

Лучшим решением является прекращение желания сделать это. –

+1

Что мешает вам читать код? –

ответ

11

callable встроенный, упомянутый в других ответах, не отвечает на ваш вопрос как поставленный, потому что он также возвращает True, помимо функций, для методов, классов, экземпляров классов, которые определяют метод __call__. Если заголовок и текст вашего вопроса ошибочны, и вам все равно, если что-то на самом деле является функцией, но только если это вызываемый, то используйте этот встроенный. Но лучший ответ на поставленный вами вопрос: импортируйте метод inspect стандартной библиотеки Python и используйте inspect.isfunction. (Существуют другие способы с более низкой абстракцией, но всегда полезно использовать функциональность модуля inspect для самоанализа, когда он есть, вместо подходов более низкого уровня: inspect помогает сохранить код коротким, ясным, надежным и будущим -доказательство).

+1

Другой неверный ответ принят на SO. Я должен начать список. Это не работает для встроенных функций и методов класса, как я уже упоминал в нескольких других ответах. Вам также нужно будет проверить check.isbuiltin() и inspect.ismethod(), и нет ничего «надежного будущего» о том, что у вас есть много особых случаев. –

+0

И почему бы не напечатать (a) == types.functionType? – AsTeR

7

В python есть функция callable.

if callable(boda): 
+0

Функция/метод - это каждый объект, который реализует метод '__call__'. callable() - хороший способ проверить существование такого метода вызова. – tux21b

+0

Но callable также вернет true для класса, не так ли? Неясно, хотел ли это ОП. – Javier

+1

Я подозреваю, что ОП не знает разницы и действительно хочет, чтобы что-то вызывало. Скорее всего, если вы не знаете, как проверить, есть ли что-то в Python, вы на самом деле не хотите этого делать. –

4

Использование callable(boda), чтобы определить, является ли boda является вызываемым или нет.

Вызываемые здесь функции - это функция, метод или даже класс. Но поскольку вы хотите различать только переменные и функции, он должен работать хорошо.

Ваш код будет выглядеть так:

boda = len # boda is the length function now 
if callable(boda): 
    print "Boda is a function!" 
else: 
    print "Boda is not a function!" 
1

Это не 100% идеальным решением а, но вы можете проверить «отзывные» встроенную функцию:

http://docs.python.org/library/functions.html

+0

Идеальное решение, конечно, ничего. –

2
>>> import types 
>>> def f(): pass 
... 
>>> x = 0 
>>> type(f) == types.FunctionType 
True 
>>> type(x) == types.FunctionType 
False 

Это проверяет, является ли это функцией. callable() проверяет, может ли он быть вызванным (то есть он имеет метод __call__), поэтому он вернет true для класса, а также функцию или метод.

+0

'isinstance' обычно предпочтительнее для проверки типов. 'is' обычно предпочитается над' == 'для проверки одиночных чисел.Требование функции, а не что-то другое, действующее точно так же, как функция, является плохой политикой. –

+1

'type (sys.exit) == types.FunctionType' и' type ((1.0) .hex) == types.FunctionType' являются ложными. (Он по-прежнему не справляется с isinstance, я не знаю, почему BuiltinFunctionType и MethodType не являются подклассами FunctionType.) –

11

Вы можете использовать inspect.isfunction(object). См.: docs.python.org

При этом вы должны избегать использования этой техники в своем ежедневном коде. Иногда вам действительно нужно использовать отражение - например, для структуры MVC может потребоваться загрузить класс и проверить его элементы. Но обычно вы должны возвращать/передавать/обрабатывать объекты, имеющие один и тот же «интерфейс». Например, не возвращайте объект, который может быть целым числом или функцией - всегда возвращайте один и тот же «тип» объекта, чтобы ваш код мог быть последовательным.

+0

@Justin Ethier - похоже, кто-то забросил каждый ответ. – kgrad

+1

Он дает советы о том, как сделать что-то, что обычно плохо, без контекста, о том, как создать хороший, надежный идиоматический код Python. –

+3

Также возникает ответ на вопрос, который является целью этого сайта. – harto

0

И что он должен вернуть для property, к которому вы обращаетесь как атрибут value, но фактически вызывает функцию? Ваш, казалось бы, простой вопрос фактически открывает целую банку червей в Python. Это означает, что такие вещи, как callable и isfunction, полезны для вашего образования и самоанализа, но, вероятно, не то, на что вы хотите положиться, при взаимодействии с другим кодом.

Тангенциально: см. Презентацию Turtles All The Way Down для получения дополнительной информации о том, как скомпонован Python.

+1

Свойство - странный пример. Свойства не очень похожи на функции и, более того, в нормальной ситуации, когда вы не обращаетесь к фактическому объекту свойства, вы должны получить доступ к объекту, который он получил для вас. –

1

Философия использования различных объектов в программе Python называется утка, набирая -если она выглядит как утка, шарлатанцы, как утка, и ходит как утка, это утка. Объекты сгруппированы не по типу их типа, а в том, что они способны делать, и это даже распространяется на функции. При написании программы Python вы всегда должны знать, что могут делать все ваши объекты и использовать их без проверки.

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

def add_three(a, b c): 
    return a + b + c 

и означает для его использования с тремя поплавками. Но, не проверяя это, у меня есть гораздо более полезная функция - я могу использовать ее с ints, с decimal.Decimals или с фракциями. Например, фракции.

То же самое касается наличия функции. Если я знаю, что у меня есть функция, и я хочу назвать ее, я должен просто позвонить ей. Возможно, что у меня есть функция, и, возможно, у меня есть другой вызываемый (например, связанный метод или экземпляр произвольного класса, который определяет __call__), который может быть таким же хорошим. Не проверяя ничего, я делаю свой код в состоянии справиться с широким кругом обстоятельств, о которых я, возможно, даже не думал заранее.

В случае с вызывающими, я могу довольно уверенно определить, есть ли у меня один или нет, но ради простоты моего кода я не хочу этого делать. Если кто-то передает что-то, что не подлежит вызову, вы получите сообщение об ошибке, когда вы его вызываете. Если я пишу код, который принимает параметр, который может быть вызываемым или нет, и я делаю разные вещи в зависимости от него, похоже, что я должен улучшить свой API, определив две функции для этих двух разных вещей.

Если у вас есть способ обработать случай, когда вызывающий передал что-то, что не является функциональным (и это было не просто результатом безумного API), правильным решением было бы поймать TypeError, который возникает при попытке вызвать то, что нельзя назвать. В общем, лучше попытаться что-то сделать и восстановить, если это не удастся, а не проверять заранее. (Вспомните клише: «Проще просить прощения, чем разрешение».) Проверка загодя может привести к неожиданным проблемам, основанным на тонких ошибках в логике и может привести к условиям гонки.

Почему, по-вашему, вам нужно иметь дело с typecheck?

Смежные вопросы