jbuddy_13
jbuddy_13

Reputation: 1276

Requirements of python decorators?

I've been trying to understand decorators. I had understood them as a function that you pass other functions through, to modify some functionality. However, the following type error is returned. Could someone explain (A) Why this is not valid? and (B) How this code should be modified such that 12 is returned?

def dec(x):
    return 2*x

@dec
def func(x,y):
    return x*y

>>>
TypeError                                 Traceback (most recent call last)
<ipython-input-89-355f941cfec0> in <module>
      3 
      4 @dec
----> 5 def func(x,y):
      6     return x*y
      7 

<ipython-input-89-355f941cfec0> in dec(x)
      1 def dec(x):
----> 2     return 2*x
      3 
      4 @dec
      5 def func(x,y):

TypeError: unsupported operand type(s) for *: 'int' and 'function'

Upvotes: 0

Views: 156

Answers (1)

eemz
eemz

Reputation: 1211

Your decorator is given a function as an argument and needs to return a function, not a value. For example:

def dec(fn):
  def newfn(x, y):
    return 2 * fn(x, y)
  return newfn

The point is that I am returning a function that if called will call fn internally, multiply that result by two and return that.

A decorator replaces one function with another. So this:

@dec
def mult(x, y):
  return x * y

is exactly the same as this:

def mult(x, y):
  return x * y
mult = dec(mult)

In both cases I am replacing mult with whatever the function dec(mult) returns. The decorator syntax is just a convenience to express that. If dec doesn't return a function then I am going to get an error when I try to call mult.

>>> def dec(fn):
...   return 12
...
>>> @dec
... def mult(x, y):
...   return x * y
...
>>> mult
12
>>> mult(9, 5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>>

mult is 12 so that last line is "12(9, 5)" and 12 is not a callable function, hence TypeError.

Upvotes: 2

Related Questions