попробуйте python кроме как функцию для оценки выражений - PullRequest
0 голосов
/ 18 января 2019

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

def try_or_zero(exp):
    try:
        exp
        return exp
    except:
        return 0

Что, очевидно, не работает. Кажется, проблема в том, что у python нет никакой формы отложенной оценки, поэтому выражение вычисляется до того, как оно передается в функцию, и поэтому возникает ошибка, прежде чем он попадает в функцию и поэтому никогда не проходит через логику попытки. Кто-нибудь знает, можно ли это сделать в Python? Приветствия

Ответы [ 4 ]

0 голосов
/ 18 января 2019

Кажется, проблема в том, что в python нет ленивых вычислений

Да ... да, но не в той форме, которую вы ожидаете. Аргументы функции действительно перед вычислением передаются функции eval'd, поэтому

try_or_zero(foo.bar())

действительно будет выполняться как:

param = foo.bar()
try_or_zero(param)

Теперь функции Python являются простыми объектами (их можно использовать в качестве переменных, передавать в качестве аргументов функций и т. Д.), И они вызываются только при применении оператора вызова (парены, с аргументами или без них), поэтому вы можете передать функция try_or_zero и пусть try_or_zero вызовет функцию:

def try_or_zero(func):
    try:
        return func()
    except Exception as e:
        return 0

Теперь вы возразите, что 1 / это не будет работать, если функция ожидает аргументы, а 2 / необходимость написать функцию только для этого - PITA - и оба возражения верны. Надеемся, что в Python также есть ярлык для создания простых анонимных функций, состоящих из одного (даже если оно сколь угодно сложного) выражения: lambda. Кроме того, функции python (включая «лямбда-функции», которые, технически, являются простыми функциями) закрывают - они захватывают контекст, в котором они определены, - так что все это довольно легко обернуть вместе:

a = 42
b = "c"

def add(x, y):
    return x + y

result = try_or_zero(lambda: add(a, b))

Дополнительная информация об обработке исключений:

Во-первых, не используйте голые, за исключением, по крайней мере, улова Exception (иначе вы можете помешать некоторому исключению - например, SysExit - работать как положено).

Также желательно ловить только те исключения, которые вы ожидаете в данной точке. В вашем случае вы можете передать кортеж исключений, которые вы хотите игнорировать, например:

def try_or_zero(func, *exceptions):
    if not exceptions:
        exceptions = (Exception,)  
    try:
        return func()
    except exceptions as e:
        return 0


a = 42
b = "c"

def add(x, y):
    return x + y

result = try_or_zero(lambda: add(a, b), TypeError))

, который не позволит вашему коду маскировать непредвиденные ошибки.

И, наконец: вы также можете добавить поддержку для возвращаемого значения, отличного от нуля, в случае исключения (не все выражения должны возвращать int):

# XXX : python3 only, python2 doesn't accept
# keyword args after *args

def try_or(func, *exceptions, default=0):
    if not exceptions:
        exceptions = (Exception,)  
    try:
        return func()
    except exceptions as e:
        return 0

# adding lists is legit too,
# so here you may want an empty list as the return value
# instead
a = [1, 2, 3]
# but only to lists
b = ""

result = try_or(lambda: a + b, TypeError, default=[]))
0 голосов
/ 18 января 2019

Не нужно беспокоиться о exec и прочем, используйте тот факт, что функции python являются объектами и, следовательно, могут быть переданы в качестве аргументов

def try_or_zero(exp):
    try:
       return exp()
    except:
       return 0

И просто вызовите try_or_zero(my_awesome_func) (без () для вашего метода)

0 голосов
/ 18 января 2019

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

def ErrorTest():
    # the expression you want to try
    raise Exception

Также ваша функция try должна выглядеть так:

 def try_catch(exp):
    try :
        exp()  # note the paranthesis
    except:
        return 0

И поместите его в функцию

try_or_zero(ErrorTest)

OutPut: 0

Вы также можете сделать это с помощью функции eval (), но вам придется поместить свой код в строку.

try_or_zero(exp):
    try:
        eval(exp)  # exp must be a string, for example 'raise ValueError'
    except:
        return 0
0 голосов
/ 18 января 2019

Передайте аргумент функции в str и выполните exec внутри функции

def try_or_zero(exp):
    try:
        exec(exp)
        return exp
    except:
        return 0

поэтому ваш вызов функции будет таким, как показано ниже try_or_zero ( '1 == 2')

...