lovemysql
lovemysql

Reputation: 285

using exception with for loop in python

hey guys am new to python app development..i have been trying to fetch only numbers from a list using a for loop..But am confused with the correct syntax..The code i have been used.is like below.

babe = [10,11,13,'vv']
int(honey) [for honey in babe]:
    print honey

When i run this i got syntax error.i have tried many situations.But it didnt helped me at all.Sorry for the silly question..

do i wanna add square brackets or something on the second line ??

Am really stuck.Hope you guys can help me out..Thanks in advance

Upvotes: 1

Views: 141

Answers (2)

Jim Dennis
Jim Dennis

Reputation: 17500

You seem to be conflating the syntax for for loops (a statement followed by a suite of statements ... otherwise known as a "block of code") and a list comprehension (an expression).

Here's a list comprehension:

#!/usr/bin/python
# Given:
b = [1,2,3,'vv']
a = [int(x) for x in b]

... that's syntactically valid. However, the semantics of that example will raise an exception because 'vv' is not a valid literal (string). It cannot be interpreted as a decimal integer.

Here's a for loop:

#!/usr/bin/python
# Given:
b = [1,2,3,'vv']
a = list()
for x in b:
    try:
        a.append(int(x))
    except ValueError:
        pass

In this case we explicitly loop over the given list (b) and ignore any ValueError exceptions raised when we try to convert each of those entries into an integer.

There is no reasonable way to handle exceptions from within a list comprehension. You could write a function which returned some sentinel value (from the expression) for any invalid input value. That would look something like this:

#/usr/bin/python
# Given:
b = [1, 2, 3, 'vv']

def mk_integer_if_possible(n):
    '''Returns an integer or the sentinel value None
    '''
    results = None
    try:
        results = int(n)
    except ValueError:
        pass
    return results

# Use that function:
a = [mk_integer_if_possible(x) for x in b if mk_integer_if_possible(x) is not None]

Note: the absurd function name is deliberate. This is an ugly way to do this and the awkwardness of having to call this putative function TWICE for each element of b is an indication that you should NOT use a list comprehension for this situation. (You have to call it once to make the conversion but again for the conditional. Saving the results from one call would, of course, be a STATEMENT, which we can't have embedded within an EXPRESSION).

Statements contain one or more expressions. Expressions are components of statements. Python strictly delineates between statements and expressions. Assignments are statements in Python. These distinctions can be nuanced and there are other programming languages where assignments are expressions rather than being strictly defined, by the language's syntax, as statements.

So, use the for loop whenever you have to handle possible exceptions while iterating over any sort of data set and usually when you need to filter on the results generated by mapping a function over a list comprehension.

Incidentally the explicit use of the expression is not None is necessary in this example. If I attempted to shorten that test to simply be if mk_integer_if_possible(x) using Python's implicit boolean handling then we'd be inadvertently filtering out any entries from b that evaluated to integer 0 as well as any that were returned as the None sentinel by my ill-advised function.

In Python it's often fine to use implicit boolean values as conditions. None and False as well as any numerically zero value, any empty string or any sort of empty list, tuple or dictionary, are all treated as "false" in a boolean context. However, when dealing with sentinel values it's best to use the is operator and explicitly test for object identity. Otherwise you'll have corner cases where your condition might be matched by values other than your sentinel.

(Handy trick: if you ever come across the need to allow None through some sort of filter or pass it along, but you need some other sentinel ... just use sentinel = object() ... you can create (instantiate) a generic Pythonobject and use is to match it for your sentinel handling. That will be unique to your code and no other Python object or type will match it. Guaranteed).

By the way ... I should note that this code it technically not "fetching only numbers from a list." It is returning integers for all entries in the list which can be converted thereto. This is a nitpick; but it's a distinction that any good engineer will notice. Do you want to return all integers from the input list? Or do you want to return all entries as integers if that can be so converted? Your code suggested that you're trying to accomplish the latter; so that's how I implemented my working examples for you. However, to implement the later semantics you'd probably want to use either the (mathematical) additive or multiplicative identity property like so:

# ... from within some function:
try:
    results = x == x + 0  # Additive identity
except (TypeError, ValueError):
    results = None
return results

Upvotes: 1

pts
pts

Reputation: 87241

babe = [10,11,13,'vv']
a = [honey for honey in babe if isinstance(honey, int)]
print a

See more here about list comprehension: https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions

Upvotes: 0

Related Questions