Search code examples
python-2.7urwid

what does @ code construct mean in python?


i was looking at a file wicd-curses.py from the wicd application available with urwid. there is a function named as wrap_exceptions and then at several other places in the file i find some code like this @wrap_exceptions which occurs just before several other functions. What does it mean ?


Solution

  • These are called decorators.

    Decorators are methods that accept another method as input. The decorator will then do something to the given function in order to change the output.

    In mathematical terms, decorators can be looked at somewhat like g(f(x)) where g is the decorator and f is the original function to be decorated. Decorators can do anything to the given function, but usually they wrap them in some sort of validation or error management.

    This blog has an excellent explanation of decorators; an example from this is a wrapper method that checks parameters in a simple coordinate system:

    class Coordinate(object):
        def __init__(self, x, y):
            self.x = x
            self.y = y
        def __repr__(self):
            return "Coord: " + str(self.__dict__)
    
    def inputChecker(func):
        def checker(a, b): # 1
            if a.x < 0 or a.y < 0:
                a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
            if b.x < 0 or b.y < 0:
                b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
            ret = func(a, b)
            if ret.x < 0 or ret.y < 0:
                ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
            return ret
        return checker
    
    # This will create a method that has automatic input checking.
    @inputChecker
    def addChecked(a, b):
        return Coordinate(a.x + b.x, a.y + b.y)
    
    # This will create a method that has no input checking
    def addUnchecked(a, b):
        return Coordinate(a.x + b.x, a.y + b.y)
    
    one = Coordinate(-100, 200) # Notice, negative number
    two = Coordinate(300, 200)
    
    addChecked(one, two)
    addUnchecked(one, two)
    

    When the coordinates are added together with addChecked, it ignores the negative number and assumes it is zero; the result of it is: Coord: {'y': 400, 'x': 300}. However, if we do addUnchecked, we get Coord: {'y': 400, 'x': 200}. This means that in addChecked, the negative value was ignored by the decorator's input checking. The variables passed in are not changed - only the local a and b inside checker(a, b) are corrected temporarily.

    Edit: I added a small explanation and expanded on one of the examples in the blog in response to dkar.