альтернатива callable(), для использования в Python 3

Я просмотрел эту тему, но некоторые концепции выше моего текущего уровня. В Python 2.x существует встроенный метод callable(); есть ли простой способ проверить, можно ли что-то вызвать или не использовать Python 3?


person Sophia    schedule 08.12.2010    source источник
comment
Я не согласен с вашим выбором принятого ответа. Я думаю, что ответ Джофоркера лучше.   -  person Андрей Беньковский    schedule 25.01.2016
comment
Я согласен. Мой ответ устарел - было бы неплохо, если бы ОП изменил ответ на один из действующих на данный момент.   -  person Chinmay Kanchi    schedule 03.02.2016


Ответы (3)


Вместо этого вы можете просто сделать hasattr(object_name, '__call__'). В отличие от Python 2.x, это работает для всех вызываемых объектов, включая классы.

person Chinmay Kanchi    schedule 08.12.2010
comment
В Python 2.x это работает для классов нового стиля, но не для старых. Помните, однако, что __call__, вызываемый для класса (нового стиля), является type (или метаклассом класса), а не классом. - person kindall; 08.12.2010
comment
@kindall: Хорошее замечание, о котором стоит помнить. Хотя, конечно, было бы довольно странно, если бы было иначе. Это также позволяет вам делать причудливые вещи, такие как class_name()() - person Chinmay Kanchi; 08.12.2010
comment
Имейте в виду, что это даст ложное срабатывание в следующем крайнем случае: class C(object): pass; c = C(); c.__call__ = lambda self: None. Несмотря на то, что c теперь имеет функцию атрибута call, c() завершится ошибкой, даже если проверка hasattr завершится успешно. Я не уверен, но я не могу исключить возможность ложноотрицательного углового случая, хотя, если это возможно, для его запуска, вероятно, потребуются объекты, реализованные в C-коде. - person mtraceur; 01.02.2018

Оно вернулось. Python 3.2 имеет callable(); больше нет необходимости использовать одну из менее удобных альтернатив.

person joeforker    schedule 06.04.2012

callable() вернулся в Python 3.2.

Если вам нужно использовать Python 3.1 (крайне маловероятно), то в дополнение к проверке на __call__ есть также следующие решения:

  • 2to3 изменяет callable(x) на isinstance(x, collections.Callable)

  • шесть применений

      any("__call__" in klass.__dict__ for klass in type(x).__mro__)
    

    Т.е. проверяет наличие __call__ в базовых классах. Это напоминает мне, что я должен спросить Бенджамина, почему. :)

И, наконец, вы можете, конечно, просто попробовать:

try:
    x = x()
except TypeError:
    pass
person Lennart Regebro    schedule 08.12.2010
comment
Отличная ссылка 2to3... это убедительный аргумент в пользу использования collections.Callable. Азбуки сейчас везде, кажется. - person Russ; 03.11.2011
comment
Блестящий. Но попробовать/кроме совета страшно. - person Shekhar; 10.11.2011
comment
@Shekhar: обработка исключений не страшна, если вы к ней привыкли. - person Lennart Regebro; 12.11.2011
comment
@LennartRegebro Речь шла о вызове, чтобы проверить, является ли рассматриваемый объект вызываемым или нет. Часть моего кода чувствительна к этому. На самом деле это было не о попытке/кроме. Надеюсь, мой комментарий теперь более понятен. - person Shekhar; 13.11.2011
comment
@Shekhar: Нет, на самом деле совсем наоборот. try/except не страшны, и они относятся к коду, который чувствителен к тому, является ли что-то вызываемым или нет. Попытка/исключение - это очень питонический способ справиться с этим. - person Lennart Regebro; 14.11.2011
comment
@LennartRegebro Дело не в попытке/кроме :). Речь идет о выполнении x, чтобы увидеть, является ли x вызываемым. попробуй: взорвать(), кроме: пройти - person Shekhar; 14.11.2011
comment
@LennartRegebro Извините, что слишком долго, но я не согласен. У меня есть несколько вызываемых объектов в моем коде (вызов с более чем несколькими строками кода, несколько вызовов базы данных и иногда изменение состояния объекта). Возможно, я не предпочитаю вызывать их, чтобы увидеть, можно ли их вызывать. - person Shekhar; 14.11.2011
comment
@Shekhar: Нет, может быть, я не совсем понимаю. Дело не в том, чтобы вызвать его, чтобы увидеть, можно ли его вызвать. Дело в том, что вы просто делаете все, что хотите, как если бы это можно было вызвать. Вам вообще не нужно проверять. Если вызов вызывает ошибку типа, вы делаете все, что делаете, если они не вызываются. Это известно как EAFP, в отличие от того, что вы делаете, что называется LBYL, который считается непитоновским. См. sayspy.blogspot.com/2008/12. / - person Lennart Regebro; 14.11.2011
comment
Это старый разговор, но я должен отметить: что произойдет, если x сам попытается что-то вызвать и не перехватит полученное исключение TypeError? Тогда вы не определили, что x нельзя вызывать, а скорее что какая-то цепочка вызовов в x выдала TypeError. Чуть другой, но другой. - person twooster; 10.03.2012
comment
Преимущество использования проверки isinstance(x, collections.Callable) заключается в том, что ABCMeta.__subclasscheck__ кэширует свои вызовы. - person forivall; 21.03.2013
comment
@LennartRegebro: я думаю, что EAFP хорош в целом, но не для этого конкретного случая. Если x является вызываемым, но вызываемая функция вызывает TypeError, то это будет ошибочно распознано как не вызываемое. - person olivecoder; 28.10.2015