I find this design pattern comes up a lot:
try: year = int(request.GET['year'])
except: year = 0
The try block can either fail because the key doesn't exist, or because it's not an int, but I don't really care. I just need a sane value in the end.
Shouldn't there be a nicer way to do this? Or at least a way to do it on one line? Something like:
year = int(request.GET['year']) except 0
Or do you guys use this pattern too?
Before you answer, I already know about request.GET.get('year',0) but you can still get a value error. Wrapping this in a try/catch block to catch the value error just means the default value appears twice in my code. Even worse IMO.
You're probably better off to use get()
year = int(request.GET.get("year", 0))
This will set year to what ever request.GET['year'] is, or if the key doesn't exist, it will return 0. This gets rid of your KeyError, but you could still have a ValueError from request.GET['year'], if it is not convert'able to an int.
Regarding your question (the try/except), a common idiom in Python is EAFP.
EDIT:
If you're really concerned, why not write your own method to do this:
def myGet(obj, key, type, defaultval):
try:
return type(obj.get(key, defaultval))
except ValueError:
return defaultval
# In your code
year = myGet(request.GET, 'year', int, 0)
Shouldn't there be a nicer way to do
this?
There is -- it's known as "a function"...:
def safeget(adict, key, type, default):
try: return type(adict.get(key, default))
except (ValueError, TypeError): return default
year = safeget(request.GET, 'year', int, 0)
FWIW, I don't think I've ever used this "pattern" -- the various error cases you're ignoring seem like they should be handled separately for UI reasons (a missing optional field defaulting is fine, but if somebody's mistakenly typed, say, 201o (the 0 and o keys being closed and, in some fonts, their results appearing similar), it generally doesn't seem nice to silently turn their input into 0. So, I don't think it's so frequent, nor highly advisable, to warrant anything like a special syntax form in the language, or even a built-in function.
But the nice thing about helper functions like safeget is that you and I can peacefully agree to disagree on the design issues involved (maybe we're just used to doing different kinds of software, for example!-) while letting each of us easily have exactly the helper functions each desires in their personal "utilities" modules!-)
I'd use a helper function:
def get_int(request, name, default=0):
try:
val = int(request.GET[name])
except (ValueError, KeyError):
val = default
return val
then:
year = get_int(request, 'year')
It keeps the complexity of the try/catch in one place, and makes for tidy functions, where you have one line per parameter in your view functions.
No way to do it in one line (that I can think of), but I'd do it like this, using get():
try:
year = int(request.GET.get("year", 0))
except ValueError:
year = 0
Also, it's generally better to catch a specific exception, not all exceptions.
Related
I have some code below that is meant to check if a list of lists contains an empty string. In context, the user of my application will fill out survey questions, but if they leave one of the survey questions empty, then I want to alert them that they need to go back and fill out the survey. I need to perform this check in a bunch of different places, so I thought that a class would be a good use-case to improve the readability and portability of my program.
However, I have come to learn of try-except blocks and thought maybe it would be a better place for the essence of my code. But I am having some issues converting my simple class into a try-except block, and would like to try and implement it this way if I can. However, I think what I want to do might not be appropriate for a try-test block, so I was hoping to get some feedback.
class ErrorCheck():
def __init__(self, survey_responses):
self.survey_responses = survey_responses
def check_empty(self):
for item in self.survey_responses:
if '' in item:
print('One of these is empty')
x = ErrorCheck([['abc'],[2],['apples'],['']])
x.check_empty()
The code that you're trying to implement is pretty much correct. Except for the fact that if you want to highlight an error, instead of just using a print function, use raise Exception() and in the parentheses insert a string, in your case 'One of these is empty'.
This will result in output like this:
Exception: One of these is empty
which is probably what you're looking for.
As others already pointed out, what you want do is probably raise an exception, after you raise it you can catch it in a try...except block and do something about it:
survey_responses = ['a','','c']
def check_empty(responses):
for response in responses:
if response == '':
raise Exception('Missing Answer: One or more answers are empty')
try:
check_empty(survey_responses)
except Exception as exc:
print(exc)
This question already has answers here:
`if key in dict` vs. `try/except` - which is more readable idiom?
(11 answers)
Closed 6 years ago.
Often, I come across cases where I find both if-else and try-except clauses can be used to solve a problem. As a result, I have some confusion deciding(and justifying) the use of a particular clause to accomplish the task at hand.
For example, let us consider a trivial situation:
In []: user = {"name": "Kshitij", "age": 20 }
# My motive is to print the user's email if it is available.
# In all other cases, a warning message needs to be printed
# Method-01 : Using try clause
In []: try:
...: print(a["email"])
...: except KeyError:
...: print("No EMAIL given")
...:
No EMAIL given
# Method-02 : Using if-else clause
In []: if "email" in a:
print(a["email"])
...: else:
...: print("No EMAIL given")
...:
No EMAIL given
I would like to know how can I decide a more Pythonic method among the two and justify it. Also, some pointers to how can one differentiate among several methods to solve similar scenarios would be really helpful.
try/catch and if/else are not interchangeable. the former is for catching errors that might be thrown. no if statement can do that. if/else is for checking if a condition is true or false. errors thrown in an if/else block will not be caught and the program will crash.
You should use exceptions if this case is an exception and not the normal case.
if/then: for internal application flow control. Errors are unlikely to be fatal
vs
try/except: for system calls and API calls where the state of the receiver is external to the code. Failures are likely to be fatal and need to handled explicitly
If you're looking for "Pythonic", neither of those is.
print a["email"] if "email" in a else "No EMAIL given"
Now that's Pythonic. But, back to the question: First of all, you decide what to do - I'm not aware of any writing conventions between those two. But, as I see it:
if-else is used mainly for detecting expectable behaviour - I mean, if "email" is not in a, it's excpectable. So we will use if-else.
An example would be your code.
But, for example, if we want to check if a string contains a numeric value, we will try to convert it to a number. If it failed, well, it's a bit harder to predict it using an if statement, so we will use try-except.
Here's a short example for that:
def is_numeric(string):
try:
a = float(string)
return True
except:
return False
of course there is a better way to check if a string is numeric, that was just an example use of try-except.
I'm writing some software in python and had a question on the preferred coding style of python.
Imagine you have a function that takes some raw data, decodes it to a dict and prints the key-value pairs
def printdata(rawdata):
data = decode(rawdata)
for key, value in data.items():
print(key, value)
This is all fine until decode starts throwing exceptions everywhere and the whole program comes crashing down. So, we use a try/catch block. But there are a couple ways of doing this and I'm wondering what method is preferred.
Everything inside try
def printdata(rawdata):
try:
data = decode(rawdata)
for key, value in data.items():
print(key, value)
except ValueError:
print("error")
Only decode inside try with return
def printdata(rawdata):
data = None
try:
data = decode(rawdata)
except ValueError:
print("error")
return
for key, value in data.items():
print(key, value)
Only decode inside try with if
def printdata(rawdata):
data = None
try:
data = decode(rawdata)
except ValueError:
print("error")
if data is not None:
for key, value in data.items():
print(key, value)
All of these methods have some advantages and disadvantages and I don't know which one to pick, and whether it really matters.
The first one is clearly the simplest, but it has a problem: If anything else in the rest of the suite could possibly raise a ValueError, it's not clear whether you caught the ValueError you expected and wanted to handle, or an unexpected one that probably means a bug in your code so you probably should have let abort and print a traceback.
When you know for sure that's not an issue, go for it.
Although really, you should almost certainly be handling the error like this:
except ValueError as e:
print("error: {!r}".format(e))
… or something similar. That way, if you do get that impossible unexpected ValueError, you'll be able to tell from the unexpected message, instead of not knowing that you've been throwing away valid data because of a bug for the last 3 months of runs.
When that isn't appropriate, the other two ideas both work, but it's usually more idiomatic to use an else block.
def printdata(rawdata):
try:
data = decode(rawdata)
except ValueError:
print("error")
else:
for key, value in data.items():
print(key, value)
If you do need to do #2 (maybe you've got, say, a mess of try statements inside try statements or something…), you don't need the data = None at the top, and shouldn't have it. There should be no way you could have gotten past the return without assigning to data. So, if somehow the impossible has happened, you want to get an exception and see that, not silently treat it as None.
In #3, the None actually is necessary. Which is a problem. The whole idea of "predeclaring" variables before setting them, then checking whether they've been set, is not only not idiomatic, it also often disguises bugs—e.g., what if None is a valid return from decode?
The "prefered coding style" is to not "handle" errors unless you can really handle them. This means that at the library level, you should have almost none error handling - just let errors propagate to the application level. At the application level you want
a top-level error handler that will properly log unhandled errors with the full traceback (logging.exception() is your friend), present the user a user-friendly error message and crash.
where you actually can ask the user for a correction (try again, select another file, whatever), do it.
Just printing the error message - without teh full traceback etc - is just a waste of everyone time.
In Objective-C you can do [variable valueForKeyPath:#"abc.def"] or [[variable abc] def] and if abc doesn't exist on variable you'll get a nil value in the end and will not get an error or exception. This is really convenient. Is there something like this in Python? I know you can do (for dictionaries at least)
abc = variable.get('abc', None)
if abc:
def = abc.get('def', None)
or
try:
def = variable.get('abc').get('def')
except:
pass
which seems incredibly verbose. Is there an easier way when I just want to access an object's attribute or get a None value back?
what about
def = variable.get('abc', {}).get('def',None)
well, this will only work for dict..
You can use nested calls to getattr:
def = getattr( getattr(variable, 'abc', None), 'def', None)
You can also dispense with the methods, and just catch the AttributeError
try:
def = variable.abc.def
except AttributeError:
def = None
There is no short built-in syntax for what you want. You might want to write a helper function that does this for you, or a collections.defaultdict might be useful.
Python avoids this behavior by design because it can lead to bugs that are difficult to diagnose. By raising an exception, the programmer is forced to either explicitly request a default value with dict.get(), getattr(), etc. or otherwise handle the case that the lookup fails. The program stops exactly where the error occurred in the program.
In the case of Objective C (as well as PHP, which is notoriously unpleasant to debug), the program may continue for a long time before you realize that your variable has been set incorrectly. Generally the longer it has been since the error occurred, the more difficult it will be to find the cause. THIS is inconvenient.
This question already has answers here:
How to properly ignore exceptions
(12 answers)
Closed 9 years ago.
I have try-except block in python, and I want to do nothing when exception occurs. My code is as follows:
for i in range(len(grid)):
for j in range(len(grid[i])):
try:
count = count > int(grid[i][j]) ? count : int(grid[i][j])
except:
//Do nothing here
How do I do nothing when exception is caught.
Thanks.
pass is the keyword you are looking for.
Let us write the code properly.
We want to iterate over each cell of the grid. So do that. Don't create lists of numbers (range) that you iterate over and then use to index back in. Python's for-loops work directly with the container. It is convenient and easy to understand and good. Don't fight that.
There is no ?: construct in Python. There is a x if y else z construct, but that is not appropriate here. You are clearly trying to set count to the maximum of its current value and the cell value. There is a built-in function for that.
You really want the maximum of all of those cells. So ask for that directly; don't assume that you have to implement the high-water-mark algorithm yourself. You don't. (This also protects you from having to pick an initial value for count, which might be wrong.) We don't need to iterate with an explicit loop for this. We can specify the list of values to pass to max with a generator expression.
You want to "ignore" values that can't be converted to integers. Notwithstanding that there probably is something wrong with your other code if the existence of such values could possibly occur in the first place: we can simply make a test, and filter out the values that fail the test.
Thus:
def is_integral(value):
try:
int(value)
return True
except:
return False
# Now, get the maximum of all the integral values:
count = max(
int(cell) for row in grid for cell in row
if is_integral(cell)
)
You can use pass, but also ... is synonymous in Python 3.x, which can be nice for writing psuedocode.
I see a lot of people use pass where they truly need to do nothing, while using ... where they are using it as a placeholder.
class SomeInterface:
def do_something(self):
pass
class SomeImplementation(SomeInterface):
def do_something(self)
...
This makes it easy to search for ... and find areas where you have unimplemented code, without the false positives from pass.
Note that passing on an exception is generally a bad practice, as you will virtually always want to act on exceptions. You should definitely, at the very least, specify the exact exception(s) you want to catch, as otherwise you will catch all exceptions, potentially causing bugs you can't detect if a different exception rears it's head.
for i in range(len(grid)):
for j in range(len(grid[i])):
try:
count = count > int(grid[i][j]) ? count : int(grid[i][j])
except:
pass
result = x if a > b else y
Is the ternary operator
The do nothing statement is
pass