2

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.

abc
  • 113
  • 3
  • 12
  • 2
    These are not decorators. A decorator wraps a functions possibly returning a new function. Functions are also decorated with ``@foo`` – James Mills Jun 21 '14 at 01:53
  • Mmm.. can you add a sample decorator with functions? – abc Jun 21 '14 at 01:55
  • what are you actually trying to do here, and why do you think decorators are the way to do it? – Eevee Jun 21 '14 at 02:19
  • am just trying to learn about decorators – abc Jun 21 '14 at 02:23
  • I found the best description of decorators, for those unfamiliar with them, to be this one - it builds you up in the concepts in stages. http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/ – Ajean Jun 21 '14 at 05:31
  • A long, but enlightening explanation of decorators: http://stackoverflow.com/a/1594484/1258041 – Lev Levitsky Jun 21 '14 at 11:03

2 Answers2

3

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.

Martin Konecny
  • 57,827
  • 19
  • 139
  • 159
2

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.

James Mills
  • 18,669
  • 3
  • 49
  • 62
  • What does this line do - from __future__ import print_function? – abc Jun 21 '14 at 02:04
  • Habit. I use Python 2.x normally. ``from __future__ import print_function`` brings in the new Python 3 ``print()`` function. In Python 2.x it was a statement/keyword. – James Mills Jun 21 '14 at 02:05
  • Ok. I just wanted to do an upper case to a set of inputs. I tried it in the same way you did this above but throws an error - TypeError: 'NoneType' object is not callable. Unable to debug this. – abc Jun 22 '14 at 22:01
  • Remember that decorators are just functions that wrap ohter functions possibly returning new functions. They take a function as their input. – James Mills Jun 22 '14 at 22:02