How can I define a 'do_twice' function with using '*args'? - python

I've made a code to repete a function process:
def do_twice(func, *args):
func(func(args))
def div(number):
print(number[0]/2)
do_twice(div, 8)
The expected output is:
4.0
2.0
But the output is:
4.0
TypeError: 'NoneType' object is not subscriptable
At this point I thought: Seems like number is None in the second round.
And my guess prooved as correct:
…
def div(number):
print(number) # i know, actually i shouldn't call it div NOW...
# output:
4
None
What was my fault? Thanks in advance.

Te problem is that when 'div' is called for the first time it gets args as input and it is looking for args[0]. The seconds call to 'div' will return a number and args[0] will fail.
Code below seems to work:
def do_twice(func, *args):
return func(func(args))
def div(number):
return number[0] / 2 if isinstance(number, tuple) else number / 2
print(do_twice(div, 8))

It didn't take too many changes to fix.
def do_twice(func, *args):
func(func(args[0]))
def div(number):
result = number/2
print(result)
return result # Return the result
do_twice(div, 8)
div needs to return the result of its calculation in order for it to be stored by do_twice for the second iteration. Otherwise, your intuition is correct, you're dividing None on the second execution of div.
The key takeaway is:
Returning makes values accessible outside the function.

You are forgetting to return something from the functions:
def do_twice(func, *args, **kwargs):
return func(func(*args, **kwargs))
def div2(n):
x = n / 2
print(x) # For debugging. A function like this normally would not print.
return x
do_twice(div2, 8)

In the call func(func(args)), the function func does not return any value. Hence, func(args) doesn't provide the required number argument for func in the outer call
function div should be modified as follows
def div(number):
print(number[0]/2)
return [number[0]/2]

Related

python decorator doesn't take the arguments of the function

I'm learning python and I'm stuck at decorators
the way I understand it is that decorators add functionality to a function
I made a simple function that checks if a number is even
and then a decorator that adds taking the absolute value to it
def decorate(func):
def is_even_new(*args,**kwargs):
num = abs(*args,**kwargs)
func(num)
return is_even_new()
#decorate
def is_even(x):
if x%2 == 0:
return True
else:
return False
is_even(8)
but it I keep getting a TypeError: abs() takes exactly one argument (0 given)
is there is something wrong in the code or is my understanding of decorators is false?
When you decorate the function, you should return the decorated function itself:
def decorate(func):
def is_even_new(*args,**kwargs):
num = abs(*args,**kwargs)
func(num)
return is_even_new
rather than calling the decorated function and returning that:
def decorate(func):
def is_even_new(*args,**kwargs):
num = abs(*args,**kwargs)
func(num)
return is_even_new()
(notice the extra parentheses). In this last example, when you decorate a function with #decorate, the decorator defines this inner function is_even_new and then, instead of returning the latter, it tries to call it with no arguments: is_even_new(). This is also why you're getting the TypeError: abs expects (exactly) one argument, but you've given it none.
Remember that functions in Python are objects like anything else ("first-class citizens") and so you can reference them directly by their name.
Also, as a recommendation, if you know that the functions decorated with #decorate will only ever take exactly one argument (like is_even), don't use variable arguments and keyword arguments, just define the decorate function to take exactly one parameter as well:
import functools
def decorate(func):
#functools.wraps(func)
def decorated(x):
func(abs(x))
return decorated
This will make the error messages more helpful (instead of raising at the abs call,
Or, if you only want to apply abs to, say, the first argument:
def decorate(func):
#functools.wraps(func)
def decorated(x, *args, **kwargs):
func(abs(x), *args, **kwargs)
return decorated
You'll also have noticed the #functools.wraps. This is a very useful standard library utility for defining wrapper functions, such as those you return from a decorator. It sets special attributes like __name__, __module__, etc. on the wrapper function so that it essentially looks like the wrapped function.
in your code you need to return the value from the decorator in correct way and also change the input data to the decorator by keeping the limitation of other inside function in mind ie (abs take 1 positonal argument not many) and you cant directly call the return function from outside as full without provideing value as return is_new_even(), you need to pass the argument there also if want to do that way
def decorate(func):
def is_even_new(val):
num = abs(val)
return func(num)
return is_even_new
#decorate
def is_even(x):
if x%2 == 0:
return True
else:
return False
is_even(8)
I am not sure what your decorated function is trying to do as modulo is working on negative integers as well, but you basically have two problems:
like #Anakhand said you should return a function and not the function return value.
your is_even_new does not return nothing
so I guess this is the correct implemntation:
def decorate(func):
def is_even_new(*args,**kwargs):
num = abs(*args,**kwargs)
return func(num)
return is_even_new
#decorate
def is_even(x):
if x%2 == 0:
return True
else:
return False
print(is_even(-8)) # --> True

How to create a function that applies a function to the inputs of another function in Python?

I'm looking for a nice functional way to do the following:
def add(x, y):
return x + y
def neg(x):
return -x
def c(x, y):
# Apply neg to inputs for add
_x = neg(x)
_y = neg(y)
return add(_x, _y)
neg_sum = c(2, 2) # -4
It seems related to currying, but all of the examples I can find use functions that only have one input variable. I would like something that looks like this:
def add(x, y):
return x + y
def neg(x):
return -x
c = apply(neg, add)
neg_sum = c(2, 2) # -4
This is a fairly direct way to do it:
def add(x, y):
return x + y
def neg(x):
return -x
def apply(g, f):
# h is a function that returns
# f(g(arg1), g(arg2), ...)
def h(*args):
return f(*map(g, args))
return h
# or this:
# def apply(g, f):
# return lambda *args: f(*map(g, args))
c = apply(neg, add)
neg_sum = c(2, 2) # -4
Note that when you use *myvar as an argument in a function definition, myvar becomes a list of all non-keyword arguments that are received. And if you call a function with *expression as an argument, then all the items in expression are unpacked and sent as separate arguments to the function. I use these two behaviors to make h accept an unknown list of arguments, then apply function g to each one (with map), then pass all of them as arguments to f.
A different approach, depending on how extensible you need this to be, is to create an object which implements your operator methods, which each return the same object, allowing you to chain operators together in arbitrary orders.
If you can cope with it always returning a list, you might be able to make it work.
class mathifier:
def __init__(self,values):
self.values = values
def neg(self):
self.values = [-value for value in self.values]
return self
def add(self):
self.values = [sum(self.values)]
return self
print (mathifier([2,3]).neg().add().values)
And you can still get your named function for any set of chained functions:
neg_add = lambda x : mathifier(x).neg().add()
print(neg_add([2,3]).values)
From Matthias Fripp's answer, I asked myself : I'd like to compose add and neg both ways : add_neg(*args) and neg_add(*args). This requires hacking Matthias suggestion a bit. The idea is to get some hint on the arity (number of args) of the functions to compose. This information is obtained with a bit of introspection, thanks to inspect module. With this in mind, we adapt the way args are passed through the chain of funcs. The main assumption here is that we deal with real functions, in the mathematical sense, i.e. functions returning ONE float, and taking at least one argument.
from functools import reduce
from inspect import getfullargspec
def arity_one(func):
spec = getfullargspec(func)
return len(spec[0])==1 and spec[1] is None
def add(*args):
return reduce(lambda x,y:x+y, args, 0)
def neg(x):
return -x
def compose(fun1,fun2):
def comp(*args):
if arity_one(fun2): return fun1(*(map( fun2, args)))
else: return fun1(fun2(*args))
return comp
neg_add = compose(neg, add)
add_neg = compose(add, neg)
print(f"-2+(-3) = {add_neg(2, 3)}")
print(f"-(2+3) = {neg_add(2, 3)}")
The solution is still very adhoc...

Wrapping a FOR function

A python wrapper specifically for for-loops and its actions
I write a lot FOR loops that are, well, pretty generic.
For eg:
for x in y:
do something
... and error-prone. eg forgetting the ":", or indentation probs.
Could we put the FOR loop in a def, and call it, supplying it with the something?
An interesting exercise if nothing else.
A basic wrapper...
def wrapper(func,*args):
def wrapped():
return func(*args)
return wrapped
wrapper(print,"bob")
wrapper()
...which works. ie prints bob out
but I don't know how to make the below work - returning a FOR function made lots of syntax errors.
eg something like:
def for_1(y, do_something):
def wrapped():
return for x in y:
do_something
return wrapped
for_1(range(3),print("bob\n"))
for_1()
...and didn't see bob on the screen 3 times.
Could someone point me in the right direction, please? A wrapper is not doing the returned function.
Perhaps use a class for the wrapper? Then have my own methods(??)
...or maybe point me to someone's page who has done this before. I have explored wrappers and decorators but not seen something for passing parameters to a FOR loop function
You can simply restructure your code to not return too early and not call to early.
For this split up the function and parameters as two parameters to your for_1 wrapper.
If you want return value, gather them in your for loop and return them as a list.
def for_1(y, do_something, with_param):
for x in y:
do_something(with_param)
for_1(range(3), print, "bob")
Why make it complicated?
def for_1(y, to_print):
for x in range(y):
print(to_print)
for_1(3, "bob")
OUTPUT:
bob
bob
bob
EDIT:
def square(x):
print(x*x)
def for_1(y, command, param):
for x in range(y):
command(param)
for_1(1, square, 3)
OUTPUT:
9
the print is evaluated immediately and its return value passed in. what you want here is to pass in a callable, and append () to the do_something inside the loop. than you can use lambda for the passed in function.
def for_1(y, do_something):
def wrapped():
return for x in y:
do_something() # so we call whatever is passed in to be executed at this point
return wrapped
f = for_1(range(3),lambda: print("bob\n"))
f()
# or equivalent:
def print_bob():
print("bob\n")
for_1(range(3),print_bob)

how a function in python is getting called by just typing the name of function and not using brackets

First of all to find "lcm" of two numbers I made a function lcm(a, b). Then I thought of finding "hcf" too so I made a decorator decor and defined a function hcf(a, b) in it. And then I returned this function by just typing the name of the function and I didn't put brackets with it but it is still working. I cant understand why this function is working even though I didn't used brackets.
def decor(lcm_arg): # just to practice decorators
def hcf(a, b):
if a > b:
a, b = b, a
while True:
if b % a == 0:
print("hcf is", a)
break
else:
a, b = b % a, a
return lcm_arg(a, b)
return hcf # how hcf function is working without using brackets
#decor
def lcm(a, b):
if a > b:
a, b = b, a
for x in range(b, a*b+1, b):
if x % a == 0:
print("lcm is", x)
break
lcm(2, 4)
Output:
hcf is 2
lcm is 4
I don't think you understand decorators. Let's make a minimal example.
def my_decorator(some_function):
def new_function(*args, **kwargs):
'announces the result of some_function, returns None'
result = some_function(*args, **kwargs)
print('{} produced {}'.format(some_function.__name__, result))
return new_function # NO FUNCTION CALL HERE!
#my_decorator
def my_function(a, b):
return a + b
my_function(1, 2) # will print "my_function produced 3"
We have a simple function my_function which returns the sum of its two arguments and a decorator which will just print out the result of whatever function it decorates.
Note that
#my_decorator
def my_function(a, b):
return a + b
is equivalent to
def my_function(a, b):
return a + b
my_function = my_decorator(my_function)
Since my_decorator accepts a function as an argument (here we are giving it my_function) and returns a new function new_function (without calling it!), we effectively override my_function because we reassign the name to whatever my_decorator returns.
In action:
>>> my_function(1, 2)
my_function produced 3
Note that at every point in the example when a function is called, it happens with the parentheses-syntax. Here are all the function calls that happen in the first block of code I posted, in order:
my_decorator(my_function) is called and the return value is reassigned to the name my_function. This either happens through the # syntax or more explicitly in the equivalent code snippet.
my_function(1, 2) is called. At this point, my_function is the new_function that got returned by the decorator. Brain-parse it as new_function(1, 2).
Inside the body of new_function, the argument we gave to my_decorator is called (result = some_function(*args, **kwargs)) which happens to be the value of my_function before the reassignment that happened in step 1.
print is called.
If you want to understand how new_function is holding on to some_function despite my_decorator already having returned from its call, I suggest looking into the topics free variables and closures.
return hcf does not call the function because there are no parentheses, as you noticed. The decor function is used as a decorator which reassigns the name lcm to refer to the returned function. What I mean by this is that
#decor
def lcm(a, b):
// ...
is equivalent to
def lcm(a, b):
// ...
lcm = decor(lcm)
After this executes, lcm refers to the function hcf. So calling lcm(2, 4) now executes the code in hcf. I think the key here is to understand that at the line lcm(2, 4), lcm and hcf are two names which refer to the same function.

inside the function "bigger()", it has returned a value--a or b. so, why do still need "return"s before "bigger()"s in the function "median()"?

inside the function "bigger()", it has returned a value--a or b.
so, why do still need "return"s before "bigger()"s in the function "median()"?
Here is the code:
def bigger(a,b):
if a > b:
return a
else:
return b
def biggest(a,b,c):
return bigger(a,bigger(b,c))
def median(a,b,c):
if a == biggest(a,b,c):
return bigger(b,c) #the function "bigger()" above has returned a value,
#so, why still need a 'return' before bigger(b,c)?
elif b == biggest(a,b,c):
return bigger(a,c)
else:
return bigger(a,b)
I'll try to explain with examples, maybe it is simpler.
You have defined your bigger function, that returns a value, right?
def bigger(a,b):
if a > b:
return a
else:
return b
Now, you have defined a biggest function, and you are calling bigger from that function.
def biggest(a,b,c):
return bigger(a,bigger(b,c))
Now imagine the thousands of stuff that you could do with the value returned from bigger.
You could use the returned value from bigger anywhere within biggest function. For example:
def biggest(a,b,c):
some_var = bigger(a,bigger(b,c))
return some_var + 10
Or
def biggest(a,b,c):
list_of_values = []
list_of_values.append(bigger(a,bigger(b,c)))
But as you wish to use the value returned from bigger in the function that calls biggest , you should return that again so that the caller of biggest gets this value. Otherwise, it would get None which basically tells the caller "No value returned."
A function call is an expression. Consider the following:
def add(a, b):
a + b
x = add(3, 5)
Would you expect x to now have the value 8? You shouldn't because add did not return the value of the expression a+b. The correct definition would be
def add(a, b):
return a+b
Now consider this function:
def backwards_add(a, b):
add(b, a)
x = backwards_add(3, 5)
Again, would you expect that x has the value 8? Once again, you shouldn't because backwards_add did not return the value of the expression add(b, a). The correct definition is
def backwards_add(a, b):
return add(b, a)
There are some languages that implicitly return the value of the last expression executed in a function (cf. Perl
sub add {
$1 + $2;
}
my $x = add(3, 5); # x has the value 8
), but Python is not one of those languages. You must explicitly return a value, or it will return None for you.

Categories