First of all, I'm super new to python and I actually search for my problem but the examples were to heavy to understand.
Here is my homework; I need a function which takes two functions as an argument and returns if the results of the two functions are same or not? Basically, it will give either TRUE of FALSE.
For that I wrote:
def f(x,y,z):
k=x(*z)
l=y(*z)
return k == l
The previos code I wrote for single function was working but when I modified it for two function as above, it gives an error as following :
import math
>>> f(math.sqrt,math.cos,5)
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <module>
f(math.sqrt,math.cos,5)
File "D:/Users/karabulut-ug/Desktop/yalanmakinesi.py", line 2, in f
k=x(*z)
TypeError: sqrt() argument after * must be a sequence
>>>
I could not figured it out since the error giving function is normally does not take a sequence. So I dont think it makes a sense :) Any help is appreciated.. Thanks :)
z is just a single number, but the * argument expansion syntax requires that you pass in a sequence (like a list, tuple or str, for example).
Either remove the * (and make your function work for just single arguments), or use *z in the function signature to make z a tuple of 0 or more captured arguments:
def f(x, y, z):
k = x(z)
l = y(z)
return k == l
or
def f(x, y, *z):
k = x(*z)
l = y(*z)
return k == l
The latter now works for functions with more than one argument too:
f(math.pow, math.log, 10, 10)
If you added a **kw argument to the signature, then keyword arguments could be handled too:
def f(x, y, *args, **kwargs):
k = x(*args, **kwargs)
l = y(*args, **kwargs)
return k == l
Here I renamed z to args to better reflect its purpose.
The syntax *z invokes argument unpacking on z. When z is just an integer, there is no iterator behavior defined, and so you see this error. Try:
>>> f(math.sqrt, math.cos, [5])
You need to remove the *. Its for unpacking. So:
def f(x,y,z):
k=x(z)
l=y(z)
return k == l
You use the * operator when you want to pass in an iterable object, like a list or tuple as something thats split up. So, for example:
a = [1,2,3,4,5]
So, for an arbitrary function, f:
f(*a) = f(1,2,3,4,5)
Related
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...
According to this, I can call a function that takes N arguments with a tuple containing those arguments, with f(*my_tuple).
Is there a way to combine unpacking and unpacked variables?
Something like:
def f(x,y,z):...
a = (1,2)
f(*a, 3)
The code you supplied (f(*a, 3)) is valid for python 3. For python 2, you can create a new tuple by adding in the extra values. Then unpack the new tuple.
For example if you had the following function f:
def f(x, y, z):
return x*y - y*z
print(f(1,2,3))
#-4
Attempting your code results in an error in python 2:
a = (1,2)
print(f(*a,3))
#SyntaxError: only named arguments may follow *expression
So just make a new tuple:
new_a = a + (3,)
print(f(*new_a))
#-4
Update
I should also add another option is to pass in a named argument after the * expression (as stated in the SyntaxError):
print(f(*a, z=3))
#-4
A little heavy, but you can use functools.partial to partially apply f to the arguments in a before calling the resulting callable on 3.
from functools import partial
partial(f, *a)(3)
This is more useful if you plan on making a lot of calls to f with the same two arguments from a, but with different 3rd arguments; for example:
a = (1,2)
g = partial(f, *a)
for k in some_list:
g(k) # Same as f(1,2,k)
as #pault said - you can create a new tuple , and you can do another thing which is:
pass the *a as the last variable to a function, for example :
def f(x,y,z):...
a = (1,2)
f(3, *a)
worked for me in Python 2.7
import math
def square(*args):
return math.pow(args,2)
a=[]
for i in range(1,101):
a.append(i)
print(list(map(square,a)))
Is there something wrong about this code? I am getting this error:
TypeError: must be real number, not tuple
As #heemayl mentioned in the comments, args is a tuple. Therefore, to access a single element of the tuple you need to use an indexer:
def square(*args):
return math.pow(args[0], 2)
Alternatively, if you are only providing one argument you can pass it straight through with the need to unpack a tuple:
def square(x):
return math.pow(x, 2)
The below assignment is taken from here:
Q5. Define the repeated function from Homework 2 by calling reduce with compose1 as the first argument. Add only a single expression to the starter implementation below:
def square(x):
return x*x
def compose1(f, g):
"""Return a function of x that computes f(g(x))."""
return lambda x: f(g(x))
from functools import reduce
def repeated(f, n):
"""Return the function that computes the nth application of f, for n>=1.
f -- a function that takes one argument
n -- a positive integer
>>> repeated(square, 2)(5)
625
>>> repeated(square, 4)(5)
152587890625
"""
assert type(n) == int and n > 0, "Bad n"
return reduce(compose1, "*** YOUR CODE HERE ***" )
To complete this assignment, I would like to understand, to what does g bind to? f binds to the square function.
First, what should repeated(f, 4) return?
A function that, when called on some arbitrary arg, will return f(f(f(f(arg)))).
So, if you want to build that with compose1, you'll need to return either compose1(compose1(compose1(f, f), f), f) or compose1(f, compose1(f, compose1(f, f))).
Now, look at what reduce does, and figure out what it's going to pass to compose1 each time. Clearly your iterable argument has to either start or end with f itself. But what else do you want there to make sure you get one of the two acceptable results?
And meanwhile, inside each call to compose1 except the last, one of the two arguments has to be the repeated function's f, while the other will be the result of another call to compose1. (The last time, of course, they'll both be f.) Figure out which of those is f and which is g, and how you get reduce to pass the right values for each, and you've solved the problem.
I'd like to learn how to pass an arbitrary number of args in a python function, so I wrote a simple sum function in a recursive way as follows:
def mySum(*args):
if len(args) == 1:
return args[0]
else:
return args[-1] + mySum(args[:-1])
but when I tested mySum(3, 4), I got this error:
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'
Does anyone have an idea about this and gimme some clue to correct it?
This line:
return args[-1] + mySum(args[:-1])
args[:-1] returns a slice of the arguments tuple. I assume your goal is to recursively call your function using that slice of the arguments. Unfortunately, your current code simply calls your function using a single object - the slice itself.
What you want to do instead is to call with those args unrolled.
return args[-1] + mySum(*args[:-1])
^---- note the asterisk
This technique is called "unpacking argument lists," and the asterisk is sometimes (informally) called the "splat" operator.
If you don't want to do it recursively:
def mySum(*args):
sum = 0
for i in args:
sum = sum + i
return sum
args[:-1] is a tuple, so the nested call is actually mySum((4,)), and the nested return of args[0] returns a tuple. So you end up with the last line being reduced to return 3 + (4,). To fix this you need to expand the tuple when calling mySum by changing the last line to return args[-1] + mySum(*args[:-1]).
In your code, args[:-1] is a tuple, so mySum(args[:-1]) is being called with the args being a tuple containing another tuple as the first argument. You want to call the function mySum with args[:-1] expanded to the arguments however, which you can do with
mySum(*args[:-1])
The arbitrary arguments are passed as tuple (with one asterisk*) to the function, (you can change it to a list as shown in the code) and calculate the sum of its elements, by coding yourself using a for loop; if don't want to use the sum() method of python.
def summing(*arg):
li = list(*arg)
x = 0
for i in range((len(li)-1)):
x = li[i]+x
return x
#creating a list and pass it as arbitrary argument to the function
#to colculate the sum of it's elements
li = [4, 5 ,3, 24, 6, 67, 1]
print summing(li)
Option1:
def mySum(*args):
return sum(args)
mySum(1,2,3) # 6
mySum(1,2) # 3
Option 2:
mySum2 = lambda *args: sum(args)
mySum2(1,2,3) # 6
mySum2(1,2) # 3