Кажется, проблема в том, что в 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=[]))