Python Define IFERROR функция - PullRequest
1 голос
/ 02 июля 2019

Я пытаюсь определить свою собственную функцию IFERROR в python, как в Excel.(Да, я знаю, что могу написать попытку / исключение. Я просто пытаюсь создать встроенную стенографию для шаблона попытки / исключения, который я часто использую.) В текущем сценарии используется попытка получить несколько атрибутов некоторых удаленных таблиц.Модуль, используемый для подключения к ним, выдает множество ошибок, и если это произойдет, я просто хочу записать, что произошла ошибка при попытке получить этот атрибут.

Что я пробовал: Поиск выявил несколько потоков, наиболее полезными из которых были:

Часто повторяемая попытка / за исключением Python

Python: попытаться, кроме как выражение?

После прочтения этих тем я попытался написать следующее:

>>> def iferror(success, failure, *exceptions):
...     try:
...         return success
...     except exceptions or Exception:
...         return failure
...
>>> iferror(1/0,0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

Я также попытался использовать менеджер контекста(новое для меня):

>>> from contextlib import contextmanager as cm
>>> @cm
... def iferror(failure, *exceptions):
...     try:
...         yield
...     except exceptions or Exception:
...         return failure
...
>>> with iferror(0,ZeroDivisionError) as x:
...     x=1/0
...
>>> print(x)
None

Есть ли способ определить функцию, которая будет выполнять предопределенный шаблон try / кроме как IFERROR?

Ответы [ 2 ]

2 голосов
/ 03 июля 2019

Проблема с iferror(1/0,0) заключается в том, что аргументы функции оцениваются до ее ввода (это имеет место в большинстве языков программирования, за исключением одного большого исключения - Haskell). Независимо от того, что делает iferror, 1/0 запускается первым и выдает ошибку.

Мы должны как-то задержать оценку 1/0, чтобы это произошло внутри функции, в контексте блока try. Одним из способов является использование строки (iferror('1/0', 1)), которую iferror может затем eval. Но по возможности следует избегать eval, и есть более легкая альтернатива: тела функций не оцениваются до тех пор, пока не будет вызвана функция, поэтому мы можем просто обернуть наше выражение в функцию и передать следующее:

def iferror(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure

def my_expr():
    return 1/0

print(iferror(my_expr, 42))
42

Важнейшей частью здесь является то, что мы не вызываем my_expr напрямую. Мы передаем его как функцию в iferror, который затем вызывает success(), что в итоге приводит к выполнению return 1/0.

Единственная проблема заключается в том, что нам пришлось извлечь аргумент функции (1/0) из обычного потока кода в отдельное определение функции, которому мы должны были дать имя (даже при том, что оно использовалось только один раз).

Этих недостатков можно избежать, используя lambda, что позволяет нам определять встроенные функции с одним выражением:

def iferror(success, failure, *exceptions):
    try:
        return success()
        #             ^^
    except exceptions or Exception:
        return failure

print(iferror(lambda: 1/0, 42))
#             ^^^^^^^
42

[ Демо ]

По сравнению с вашей первоначальной попыткой потребовались только два изменения: обернуть выражение в lambda:, что задерживает оценку, и использовать () в try: return success() для вызова лямбда-выражения, которое запускает оценку тела функции.

1 голос
/ 02 июля 2019

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

def iferror(success: str, failure, *exceptions):
    try:
        # Test
        return eval(success)

    except exceptions or Exception:
        return failure    

iferror("1/0", "Hi there!")

Я надеюсь, что я могу надеяться на вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...