Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Python library (or pattern) like Ruby's andand?

For example, I have an object x that might be None or a string representation of a float. I want to do the following:

do_stuff_with(float(x) if x else None)

Except without having to type x twice, as with Ruby's andand library:

require 'andand'
do_stuff_with(x.andand.to_f)
like image 790
Andres Riofrio Avatar asked Oct 26 '11 04:10

Andres Riofrio


2 Answers

We don't have one of those but it isn't hard to roll your own:

def andand(x, func):
    return func(x) if x else None

>>> x = '10.25'
>>> andand(x, float)
10.25
>>> x = None
>>> andand(x, float) is None
True
like image 122
Raymond Hettinger Avatar answered Nov 15 '22 11:11

Raymond Hettinger


Taking off on Raymond's idea, here's a factory for making conditional wrappers of this sort. Why write 'em yourself when you can have Python write 'em for you?

def makeandand(func):
    return lambda x: func(x) if x else None

andandfloat = makeandand(float)

andandfloat('10.25')
>>> 10.25

andandfloat('')
>>> None

andand isn't exactly Pythonic, but I'm at a loss for a better name. Maybe trap since you're trapping the invalid value.

It's worth noting that a common Python idiom is to go ahead and try to do what you need to do, and deal with exceptions as they come along. This is called EAFP, from the maxim "it's Easier to Ask Forgiveness than Permission." So maybe a more Pythonic way to write that is:

def maketrap(func, *exceptions):
    def trap(x):
        try:
            return func(x)
        except exceptions or (Exception,):
            return None
    return andand

trapfloat = maketrap(float)

# optionally specify the exceptions to convert to a None return
# (default is to catch anything but you may want to allow some through)
trapfloat = maketrap(float, ValueError)
trapfloat = maketrap(float, ValueError, TypeError)

# if you don't want to store it (i.e. you only need it once or twice)...
maketrap(float)(x)    # ... just call it immediately

In your use case, I think this approach is a win: it transparently deals with anything that can be converted to a float, and does "the right thing" if a falsy-but-convertible-to-float value (such as 0) is passed in.

like image 31
kindall Avatar answered Nov 15 '22 12:11

kindall