abc
abc

Reputation: 113

Decorator in python - explanation needed

I am new to python and cant understand the decorators concept. I am trying to implement two decorators, one, nonNegative which assumes an arbitrarily long list of integer arguments and throws an Exception if any is less than 0, and another, allCaps, which assumes an arbitrarily long list of string arguments, and capitalizes them. Then, write a simple function to test each, wrap it, and demonstrate that each decorator works.

I have started and have come to this point.

#!/usr/local/bin/python2.7

def NonNegative(inputs):
  for i in inputs:
    if i<0:
      raise exception

def allCaps(inputs2):
  for i in inputs2:
    a = i.upper()
    print a

def inputs
def inputs2():
  inputfile = open ("input.txt")
  sentence = inputfile.readlines()
  words = (sentence[0].split())
  return words

NonNegative(inputs)

I would be grateful if someone can explain me the concept of decorators. I tried to understand it but couldn't.

Upvotes: 2

Views: 200

Answers (2)

Martin Konecny
Martin Konecny

Reputation: 59681

Think of a decorator as a function that wraps your function.

In math you might have a function f(x). If you wrap it with decorator g you have g(f(x)).

In python the representation is

@function_g
def function_f():
    pass

Here's an example:

def entryExit(f):
    def new_f():
        print "Entering", f.__name__
        f()
        print "Exited", f.__name__
    return new_f

@entryExit
def func1():
    print "inside func1()"

You see we define a function extryExit which returns a wrapped function (and therefore takes a function as its input). It wraps this function inside of new_f.

By wrapping the function with the decorator, func1 transforms from

def func1():
    print "inside func1()"

to

def func1(f):
    print "Entering", f.__name__
    print "inside func1()"
    print "Exited", f.__name__

You can also write a class to define a decorator, but function decorators are less verbose in my opinion.

You can read more about decorators with this excellent intro here.

Upvotes: 3

James Mills
James Mills

Reputation: 19050

Here is an example subset of what you're trying to do:

#!/usr/bin/env python


from __future__ import print_function


def nonnegative(f):
    def wrapper(xs):
        for x in xs:
            if x < 0:
                raise ValueError("{} < 0".format(x))
        return f(xs)
    return wrapper


@nonnegative
def inputs(xs):
    for x in xs:
        print(x)


inputs([1, 2, 3, 4])
inputs([-1])

Output:

$ python foo.py 
1
2
3
4
Traceback (most recent call last):
  File "foo.py", line 23, in <module>
    inputs([-1])
  File "foo.py", line 11, in wrapper
    raise ValueError("{} < 0".format(x))
ValueError: -1 < 0

See: https://wiki.python.org/moin/PythonDecorators

PS: I'm not really sure what you were trying to achieve with allCaps as a decorator so I left this alone since you didn't really use it.

Upvotes: 2

Related Questions