Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

General decorator to wrap try except in python?

I'd interacting with a lot of deeply nested json I didn't write, and would like to make my python script more 'forgiving' to invalid input. I find myself writing involved try-except blocks, and would rather just wrap the dubious function up.

I understand it's a bad policy to swallow exceptions, but I'd rather prefer they to be printed and analysed later, than to actually stop execution. It's more valuable, in my use-case to continue executing over the loop than to get all keys.

Here's what I'm doing now:

try:     item['a'] = myobject.get('key').METHOD_THAT_DOESNT_EXIST() except:     item['a'] = '' try:     item['b'] = OBJECT_THAT_DOESNT_EXIST.get('key2') except:     item['b'] = '' try:     item['c'] = func1(ARGUMENT_THAT_DOESNT_EXIST) except:     item['c'] = '' ... try:     item['z'] = FUNCTION_THAT_DOESNT_EXIST(myobject.method()) except:     item['z'] = '' 

Here's what I'd like, (1):

item['a'] = f(myobject.get('key').get('subkey')) item['b'] = f(myobject.get('key2')) item['c'] = f(func1(myobject) ... 

or (2):

@f def get_stuff():    item={}    item['a'] = myobject.get('key').get('subkey')    item['b'] = myobject.get('key2')    item['c'] = func1(myobject)    ...    return(item) 

...where I can wrap either the single data item (1), or a master function (2), in some function that turns execution-halting exceptions into empty fields, printed to stdout. The former would be sort of an item-wise skip - where that key isn't available, it logs blank and moves on - the latter is a row-skip, where if any of the fields don't work, the entire record is skipped.

My understanding is that some kind of wrapper should be able to fix this. Here's what I tried, with a wrapper:

def f(func):    def silenceit():       try:          func(*args,**kwargs)       except:          print('Error')       return(silenceit) 

Here's why it doesn't work. Call a function that doesn't exist, it doesn't try-catch it away:

>>> f(meow()) Traceback (most recent call last):   File "<stdin>", line 1, in <module> NameError: name 'meow' is not defined 

Before I even add a blank return value, I'd like to get it to try-catch correctly. If the function had worked, this would have printed "Error", right?

Is a wrapper function the correct approach here?

UPDATE

I've had a lot of really useful, helpful answers below, and thank you for them---but I've edited the examples I used above to illustrate that I'm trying to catch more than nested key errors, that I'm looking specifically for a function that wraps a try-catch for...

  1. When a method doesn't exist.
  2. When an object doesn't exist, and is getting a method called on it.
  3. When an object that does not exist is being called as an argument to a function.
  4. Any combination of any of these things.
  5. Bonus, when a function doesn't exist.
like image 857
Mittenchops Avatar asked Mar 22 '13 14:03

Mittenchops


People also ask

What is wrapper and decorator in Python?

In Python, a function decorator is effectively a function wrapper. A function decorator extends the functionality of a function by wrapping around it without modifying its original intended behavior. As usual, let's start with the basics and slowly work our way to finally understanding what a function decorator is.

What can I use instead of try except in Python?

Moreover, if your input is allowed to contain extra spaces, you can use something like splitted[2]. strip() . Readings on SO/SE about the try-except matter.

Why you should wrap decorators in Python?

The purpose of having a wrapper function is that a function decorator receives a function object to decorate, and it must return the decorated function. before some_function() is called. some fun after some_function() is called.

What is __ wrapped __ in Python?

__wrapped__ in Python decorators As we can see from the code of the functools module 1, when decorating an object, there is an attribute named __wrapped__ that holds the reference to the original one. So now if we use this, we can access it directly without having to resort to the old quirks.


1 Answers

You could use a defaultdict and the context manager approach as outlined in Raymond Hettinger's PyCon 2013 presentation

from collections import defaultdict from contextlib import contextmanager  @contextmanager def ignored(*exceptions):   try:     yield   except exceptions:     pass   item = defaultdict(str)  obj = dict() with ignored(Exception):   item['a'] = obj.get(2).get(3)   print item['a']  obj[2] = dict() obj[2][3] = 4  with ignored(Exception):   item['a'] = obj.get(2).get(3)   print item['a'] 
like image 50
iruvar Avatar answered Sep 21 '22 13:09

iruvar