tags:

views:

133

answers:

4

When you want to print a bunch of variables in Python, you have quite a few options, such as:

for i in range(len(iterable)):
    print iterable[i].name

OR

map(lambda i: sys.stdout.write(i.name), iterable)

The reason I use sys.stdout.write instead of print in the second example is that lambdas won't accept print, but sys.stdout.write serves the same purpose.

You can also print conditionally with the ternary operator:

map(lambda n: None if n % 2 else sys.stdout.write(str(n)), range(1, 100))

So it would be really handy if I could check an entire sequence for a condition that would warrant an exception in such a way:

map(lambda o: raise InvalidObjectError, o.name if not o.isValid else o(), iterable)

But that doesn't work. Is there such an object for raise in Python, and if so, where is it?

+2  A: 

There is no Python "object" (built-in or in the standard library) for raise, you have to build one yourself (typical short snippet that goes in one's util.py...!):

def do_raise(exc): raise exc

typically to be called as do_raise(InvalidObjectError(o.name)).

Alex Martelli
I cringe at the name `do_raise`
Gabe
The conventional way to use a Python keyword as an identifier would be `raise_`.
jleedev
@Gabe: Perhaps you should cringe at a situation for which this is the accepted answer.
S.Lott
+1  A: 

I don't think it's possible to use raise in a lambda, like you're attempting to do. raise is a statement/expression, not an object. As @Alex Martelli has stated, you'd likely need to define a function to do the check for you. Now, the function could be declared locally, within the same context.

As far as the exception types, which is what your question seems to be aimed at: Exception types are not defined automatically. For simple exception types, where you either want just a text message, or none at all, typically exception types are defined simply at your module/file scope as:

class InvalidObjectError(Exception): pass
Nathan Ernst
Actually the first part of your answer is right, I did want to know if there was an object for the raise statement like there is for the print statement.
cory
A: 

For your first example I use form like this:

print '\n'.join(obj.name for obj in iterable)

Also I would use:

firstnotvalid = next(obj.name for obj in iterable if not obj.is_valid())

And instead of:

>>> import sys
>>> map(lambda n: None if n % 2 else sys.stdout.write(str(n)), range(1, 100))
2468101214161820222426283032343638404244464850525456586062646668707274767880828486889092949698[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]

I would do:

>>> print (', '.join(str(number) for number in range(1,100) if not number % 2))
2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98

Ignoring that there is step parameter for range, as I think the function is simplification of other more complicated functions.

Tony Veijalainen
+1  A: 

Do. Not. Do. This.

This is a dreadful idea.

map(lambda o: raise InvalidObjectError, o.name if not o.isValid else o(), iterable)

Do this.

class SomeValidatingClass( object ):
    def isValid( self ):
        try: 
            self.validate()
        except InvalidObjectError:
            return False
        return True
    def validate( self ):
        """raises InvalidObjectErorr if there's a problem."""

[ x.validate() for x in iterable ]

No map. No lambda. Same behavior.

S.Lott
What's wrong with map and lambda? It seems to me that you would also recommend using a for loop and an if statement instead of filter(), which only serves (in my eyes) to draw out the process.
cory
@cory: filter is hardly comparable to this. The use of `lambda` to attempt to raise an exception is too complex. Not a comment on filtering. Only commenting on your exact use case. The actual validation is much, much simpler here. No Map. No Lambda. `[ x.validate() for x in iterable ]`. And you have your exception raised if any object is invalid. Done. No map. No Lambda.
S.Lott