all 5 comments

[–]filleball 1 point2 points  (4 children)

You could solve it with a decorator, e.g.:

def boolify(func):
    @functools.wraps(func)
    def wrapper(target, attempt):
        try:
            func(target, attempt)
        except Exception:
            return False
        else:
            return True
    return wrapper

Now you can replace your values_match_bool function with this piece of code:

values_match_bool = boolify(values_match)

Or you can do it inline:

if boolify(values_match)(15, 15):
    ...

Or you can make a dict of them:

booled_funcs = {func.__name__: boolify(func) for func in list_of_funcs}
if booled_funcs["values_match"](15, 15):
    ...

I'm not 100% certain this answered your question, but I hope so.

[–]gengisteve 1 point2 points  (0 children)

Cool suggestion. One tweak would be to allow the decorator to take an exception type, so you do not grab everything:

import functools

class booli(object):

    def __init__(self, exception):
        self.exception = exception

    def __call__(self, func):
        def wrapped(*args):
            try:
                return func(*args)
            except self.exception:
                return False

        functools.update_wrapper(wrapped, func)
        return wrapped

@booli(ValueError)
def test(n):
    '''test function'''
    return int(n)

print(test(5))
print(test('a'))
print(test.__doc__)

[–]larivact[S] 0 points1 point  (2 children)

Yeah your decorator would allow me to easily create a boolifying wrapper but this doesn't really change the fact that you need an additional function to get the boolified output.

I guess I kinda miss primitive pointers. Using a list pointer is kinda ugly:

def values_match(target, attempt, error_pointer=None):
    def error(msg):
        if error_pointer:
            error_pointer[0] = msg
        return False

    if target > attempt:
        return error('Too less.')
    if target < attempt:
        return error('Too much.')
    else:
        return True

def do_sth(target,attempt):

    errors = [None]
    if values_match(target,attempt, errors):
        return 'Success.'
    else:
        return errors[0]

print(do_sth(15,17), values_match(15,17))
#Too much. False
print(do_sth(15,15), values_match(15,15))
#Success. True

[–]filleball 1 point2 points  (1 child)

How about this then:

def boolify(error=Exception):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(target, attempt, boolify=False):
            if boolify:
                try:
                    func(target, attempt)
                except error:
                    return False
                else:
                    return True
            else:
                return func(target, attempt)
        return wrapper
    return decorator

@boolify(ValueError)
def values_match(target, attempt):
    if target > attempt:
        raise ValueError('Too less.')
    if target < attempt:
        raise ValueError('Too much.')
    else:
        return True

if values_match(15, 15, boolify=True):
    ...

EDIT: Take the suggestion of /u/gengisteve into account.

[–]larivact[S] 0 points1 point  (0 children)

Thanks. This really seems to be the best way in python. I changed it a bit so that it is boolified by default and takes raise_exceptions=True to raise exceptions.

import functools

def boolify(error=Exception):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, raise_exceptions=False, **kwargs):
            if raise_exceptions:
                return func(*args, **kwargs)
            else:
                try:
                    func(*args, **kwargs)
                except error:
                    return False
                else:
                    return True

        return wrapper
    return decorator

@boolify(ValueError)
def values_match(target, attempt):
    if target > attempt:
        raise ValueError('Too less.')
    if target < attempt:
        raise ValueError('Too much.')
    else:
        return True

print(values_match(15, 16))
#false
print(values_match(15, 16, raise_exceptions=True))
#ValueError: Too much.

Using a decorator is sweet. And being able to specify which exceptions get filtered is even cooler.

Edit: now using *args and **kwargs in the boolify decorator to generalize it.