Question

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

Was it helpful?

Solution

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.

OTHER TIPS

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.

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))

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.

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.

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])

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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top