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...
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.
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.
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.
__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.
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']
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With