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'
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.
Related
I have a piece of code as follows:
def range_print(n, *args):
for i in range(n):
func(i)
#range_print(n=10)
def func(i):
print(i)
I get:
TypeError Traceback (most recent call last)
<ipython-input-4-b13e44263521> in <module>
2 for i in range(n):
3 func(i)
----> 4 #range_print(n=10)
5 def func(i):
6 print(i)
<ipython-input-4-b13e44263521> in range_print(n, *args)
1 def range_print(n, *args):
2 for i in range(n):
----> 3 func(i)
4 #range_print(n=10)
5 def func(i):
TypeError: 'NoneType' object is not callable
Later I solved the problem, but I don't know if there is a better way?
I want to use decorators to make my code look cleaner.
def range_print(n, *args):
def inner(func): # <----Why do I need this def to load func?
for i in range(n):
func(i)
return inner
#range_print(n=10)
def func(i):
print(i)
The reason why the function inner takes a function as a parameter, is that this is how the mechanics of Python work when you add a decorator like #range_print(n=10) to your function.
When you call your function, Python passes the function itself, together with its arguments, to the range_print decorator.
So in your case, the parameter named n in the range_print function signature is actually a function.
Here's a simple function with a local function:
def raise_to(exp):
def raise_to_exp(x, exp):
return pow(x, exp)
return raise_to_exp
Now I expect the local function to close over exp, but somehow it doesn't. When I run this:
square = raise_to(2)
print(square.__closure__)
I get None. What am I missing?
There is no closure, no, because the inner function has it's own local exp variable; you gave it a parameter by that name. The parameter masks the name in the outer scope, so no closure is created for it. The function that is returned requires two arguments, and the argument to raise_to() is simply ignored:
>>> from inspect import signature
>>> def raise_to(exp):
... def raise_to_exp(x, exp):
... return pow(x, exp)
... return raise_to_exp
...
>>> signature(raise_to(2))
<Signature (x, exp)>
>>> square = raise_to(2)
>>> square(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: raise_to_exp() missing 1 required positional argument: 'exp'
>>> square(5, 3)
125
>>> raise_to('This is ignored, really')(5, 3)
125
Remove the exp parameter from the inner function if you wanted that to be taken from the outer function:
def raise_to(exp):
def raise_to_exp(x):
return pow(x, exp)
return raise_to_exp
Now exp is a closure:
>>> def raise_to(exp):
... def raise_to_exp(x):
... return pow(x, exp)
... return raise_to_exp
...
>>> raise_to(2).__closure__
(<cell at 0x11041a978: int object at 0x10d908ae0>,)
>>> raise_to.__code__.co_cellvars
('exp',)
The co_cellvars attribute on a code object gives you the names of any closed-over variable in the outer scope.
The function that is returned takes one argument, and the argument to raise_to() is now actually used:
>>> raise_to(2)(5)
25
>>> raise_to('Incorrect type for pow()')(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in raise_to_exp
TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'str'
I'm python user and I'm evaluate combination in python.
For two integers m,n, nCm=n!/(m!*(n-m)!)
So, I defined factorial and combination function.
factorial function is working, but combination function does not working.
What is the error?
1> Factorial Function
def factorial(a):
f=1
for i in range(1,a+1):
f=f*i
print(f)
2> Combination Function
def Combination(n,m):
fn=factorial(n)
fm=factorial(m)
fnm=factorial(n-m)
ncm=factorial(n)/(factorial(m)*factorial(n-m))
print(ncm)
In factorial function, For example, factorial(4)=24 is working in python.
But, In combination function,
When I typing Combination(4,2),
24
2
2
24
2
2
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-18-daae2b10838c> in <module>()
----> 1 Combination(4,2)
<ipython-input-17-76c6e425ad35> in Combination(n, m)
3 fm=factorial(m)
4 fnm=factorial(n-m)
----> 5 ncm=factorial(n)/(factorial(m)*factorial(n-m))
6 print(ncm)
7
TypeError: unsupported operand type(s) for *: 'NoneType' and 'NoneType'
What's the matter in my coding?
Instead of printing the output of a function, you should return the result.
def factorial(a):
f=1
for i in range(1,a+1):
f=f*i
return f
def combination(n,m):
return = factorial(n)/(factorial(m)*factorial(n-m))
print combination(4,2)
One more remark: after calculating factorial(n), it will be stored in your fn variable. You shouldn't calculate it again, but rather take that value and "recycle" it.
def factorial(a):
f=1
for i in range(1,a+1):
f=f*i
return f
def Combination(n,m):
fn=factorial(n)
fm=factorial(m)
fnm=factorial(n-m)
ncm=fn/(fm*fnm)
print(ncm)
Combination(4,2)
In your code there is missing return statement in factorial function.
I defined a function which takes 2 arguments. When I call the function, I get an error saying not enough argument:
>>> def fib(self, a,b):
... self.i=a, self.j=b
... print self.i+self.j
...
>>> fib(4,8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fib() takes exactly 3 arguments (2 given)
>>> fib(4,8,9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fib
AttributeError: 'int' object has no attribute 'i'
I passed with both 2 and 3 arguments. What should be the third argument?
I am assuming you don't understand self very well in python. Its heading towards OOP (Object oriented programming).
non-OOP approach (doing the same thing with static methods)
def fib(a,b):
print a+b
fib(4,8)
OOP approach
class Test():
i = 0
j = 0
def fib(self, a,b):
self.i=a
self.j=b
print self.i+self.j
t = Test() # create an object of Test class
t.fib(2, 3) # make the function call
NOTE : python considers a function to be a static function if it does not have the keyword self as the first parameter
You function has 3 arguments: self, a and b.
self is traditionally used for methods.
You write (simplified example):
class A:
def multiply(self, b): # method called with one argument
return 2 * b
a = A()
a.multiply(3)
or
def multiply(b): # this is a function with one argument
return 2*b
mutiply(3)
from celery.task import Task
class Decayer(Task):
def calc_decay_value(self, x):
y = (1.0/(2^x))
return y
def calc_decay_time(self, x):
y = 2^x
return y
def run(self, d, **kwargs):
#do stuff.
return 0
>>> decayer = tasks.Decayer(r)
Traceback (most recent call last):
File "scanDecay.py", line 31, in <module>
decayer = tasks.Decayer(r)
TypeError: object.__new__() takes no parameters
Two errors
1) Your class doesn't have an __init__ function. Either add one, or use this instead:
decayer = tasks.Decayer()
2) You are trying to raise an integer to the power of a float, but ^ means xor and cannot be used on floats. Use ** instead of ^:
y = 2 ** x
The problem seems due to decayer = tasks.Decayer(r) call and tasks.Decayer is not designed to take a argument, because Task does not define a __init__ method which can take one.