4

Okay lets say I have a list, and I want to check if that list exists within another list. I can do that doing this:

all(value in some_map for value in required_values)

Which works fine, but lets say I want to the raise an exception when a required value is missing, with the value that it is missing. How can I do that using list comprehension?

I'm more or less curious, all signs seem to point to no.

EDIT Argh I meant this:

for value in required_values:
 if value not in some_map:
  raise somecustomException(value)

Looking at those I cant see how I can find the value where the error occurred

hlovdal
  • 26,565
  • 10
  • 94
  • 165
UberJumper
  • 20,245
  • 19
  • 69
  • 87
  • very similar to: http://stackoverflow.com/questions/1528237/how-can-i-handle-exceptions-in-a-list-comprehension-in-python – Ruggero Turra May 08 '12 at 18:58

7 Answers7

14

lets say i want to the raise an exception when a required value is missing, with the value that it is missing. How can i do that using list comprehension?

List comprehensions are a syntactically concise way to create a list based on some existing list—they're not a general-purpose way of writing any for-loop in a single line. In this example, you're not actually creating a list, so it doesn't make any sense to use a list comprehension.

Miles
  • 31,360
  • 7
  • 64
  • 74
2

If you don't want to consider duplicates and the values are hashable, use sets. They're easier, faster, and can extract "all" elements missing in a single operation:

required_values = set('abc') # store this as a set from the beginning
values = set('ab')
missing = required_values - values
if missing:
    raise SomeException('The values %r are not in %r' % 
                        (missing, required_values))
tzot
  • 92,761
  • 29
  • 141
  • 204
nosklo
  • 217,122
  • 57
  • 293
  • 297
2

You can't use raise in a list comprehension. You can check for yourself by looking at the grammar in the Python Language Reference.

You can however, invoke a function which raises an exception for you.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
0

I was wondering about tonight. My use case is iterating over a list of objects and raising an error when the object was not of a specific type. My solution is to use a generator.

def iter_my_class(my_class_list):
    for c in my_class_list:
        if not isinstance(c, MyClass):
            raise ValueError('Expected MyClass')
        yield c

Then used as

classes = [c for c in iter_my_class(my_class_list)]

I wrote this on my phone. If that runs without errors you all owe me a beer.

Allie Fitter
  • 1,689
  • 14
  • 18
0

You can certainly hack something together, but it is not particularly readable.

(_ for _ in ()) defines a generator, from which you can use the throw method to raise any exception you want.

all((_ for _ in ()).throw(somecustomException(value)) for value in required_values if value not in some_map)

That said, readability aside, it doesn't make sense to use a list comprehension unless you're actually going to use the list. This might make more sense as something like:

map_values=[some_map[value] if value in some_map else (_ for _ in ()).throw(somecustomException(value)) for value in required_values]

But even then it probably makes more sense to handle the exception outside the loop. If you want to raise a custom exception for some reason you can just catch the KeyError and raise your own exception.

try:
    found_values=[some_map[value] for value in required_values]
except KeyError as e:
    raise somecustomException(e.args[0])
Chris
  • 1,613
  • 17
  • 24
0

Another (ugly) possibility would be the error_on_false function:

def error_on_false(value)
    if value:
        return value
    else:
        raise Exception('Wrong value: %r' % value)

if all(error_on_false(value in some_map) for value in required_values):
    continue_code()
    do_something('...')

That's ugly. I'd use the set instead.

nosklo
  • 217,122
  • 57
  • 293
  • 297
-2

While I think using sets (like nosklo's example) is better, you could do something simple like this:

def has_required(some_map, value):
  if not value in some_map:
    raise RequiredException('Missing required value: %s' % value)

all(has_required(some_map, value) for value in required_values)
mattkemp
  • 363
  • 1
  • 4