Python Forum

Full Version: Decorator vs. evaluate function in function
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi there,

in my project I use assertation functions similar to the one below to perform, for example, bounds checking:

def assert_greater_zero(x):
    if x < 0.0:
        raise ValueError('x out of bounds.')
Typically, I would use such functions to check the arguments of some __init__ function. Additionally, my interface allows for None, which should be passed through to the instance variable. Of course, the assert would fail if I passed it None, hence I have to check:

class House:
    def __init__(self, n_windows)
        if n_windows is not None:
           assert_greater_zero(x)
        self.n_windows = n_windows
Since there are lots of such checks in my project, I started to look for a way to hide them. I came up with the following two ideas:

1. A decorator
def pass_through_1_(func):
    def wrapper(arg):
        if arg is not None:
            func(arg)
        return arg
    return wrapper
Then I thought "why do I even need a decorator? I could simply evaluate the assert". So, the second approch uses only the wrapper part of the decorator.

2. A function that evaluates the assert function
def pass_through_2_(func, arg):
    if arg is not None:
        func(arg)
    return arg
So in the class, the frist approch would look like:
class House:
    def __init__(self, n_windows)
        self.n_windows = pass_through_v1_(assert_greater_zero)(n_windows)
and the second approch would be

class House:
    def __init__(self, n_windows)
        self.n_windows = pass_through_v2_(assert_greater_zero, n_windows)
This makes up three different ways to solve the same problem. The explicit one, which performs the check in __init__, the decorator version and the third one, which evaluates the assert. What I want to discuss is which way would you prefer? Personally and until now, I like the third approch the most, because it keeps my __init__ clean and I can avoid the "decorator(func)(arg)" syntax. On the other hand, it is not clear from the call that "pass_throuh" also handles the None case.

What do you think?
Why not this
def checked_none_or_greater_zero(x):
    if not (x is None or x >= 0):
        raise ValueError('Expected None value or greater than zero, got', x)
    return x

...
        self.n_windows = checked_none_or_greater_zero(n_windows)