I am learning Python and I am reading the "Think Python" and doing some simple exercises included in the book.
I am asked "Define a new function called do_four that takes a function object and a value and calls the function four times, passing the value as a parameter."
I am trying to compose this function with one statement by calling a function already defined called do_twice() and test it with a function called print_double(). Here is the code:
def do_twice(f, x):
f(x)
f(x)
def do_four(f, v):
do_twice(do_twice(f, v), v)
def print_twice(s):
print s
print s
s = 'abc'
do_four(print_twice, s)
This code produces an error:
abc
abc
abc
abc
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-41-95b513e5e0ee> in <module>()
----> 1 do_four(print_twice, s)
<ipython-input-40-100f8587f50a> in do_four(f, v)
1 def do_four(f, v):
----> 2 do_twice(do_twice(f, v), v)
<ipython-input-38-7143620502ce> in do_twice(f, x)
1 def do_twice(f, x):
----> 2 f(x)
3 f(x)
TypeError: 'NoneType' object is not callable
In trying to understand what is happening I tried to construct a Stack Diagram as described in the book. Here it is:
Could you explain the error message and comment on the Stack Diagram?
Your advice will be appreciated.
do_twice gets a function on the first argument, and doesn't return anything. So there is no reason to pass do_twice the result of do_twice. You need to pass it a function.
This would do what you meant:
def do_four(f, v):
do_twice(f, v)
do_twice(f, v)
Very similar to how you defined do_twice by f
do_twice(do_twice(f, v), v)
^^^^^^^^^^^^^^
Slightly rewritten:
result = do_twice(f, v)
do_twice(result, v)
You're passing the return value of do_twice(...) as the first parameter to do_twice(...). That parameter is supposed to be a function object. do_twice does not return anything, so result is None, which you're passing instead of the expected function object.
There's no point in nesting the two do_twice in any way here.
Related
function namesScores(arr) {
// Good luck!
arr.sort();
return arr.reduce((acc, v, i) => acc + wordWorth(v) * (i + 1), 0);
}
In the above code written in javascript the callable function that I have given to the reduce function uses three parameters accumulator, currentItem, currentIndex.
from functools import reduce
def nameScores(arr):
arr.sort()
return reduce(lambda acc, v, i: acc + wordWorth(v) * (i + 1), arr, 0)
While writing the same code in python, I am getting an error:
Traceback (most recent call last):
File "/home/cyogian/practicePython/ProjectEuler/p022/p022.py", line 22, in <module>
print(nameScores(test1))
File "/home/cyogian/practicePython/ProjectEuler/p022/p022.py", line 18, in nameScores
return reduce(lambda acc, v, i: acc + wordWorth(v) * (i + 1), arr, 0)
TypeError: <lambda>() missing 1 required positional argument: 'i'
This says that the currentIndex parameter is missing. Is it that the reduce function in python functools does not give access to the currentIndex?
Is there any other version of reduce in python that give access to the index of current item in the iterable?
Or should I go with simple forLoop in the case where I need access to Index?
You don't need a special form of reduce to access the index: just use the enumerate function on the iterable you want to reduce.
>>> a = ['foo', 'bar', 'baz']
>>> from functools import reduce
>>> reduce(lambda acc, iv: acc + str(iv[0]) + iv[1], enumerate(a), '')
'0foo1bar2baz'
Here, iv is one pair from enumerate, so iv[0] is the index and iv[1] is the value.
Explanation:
The reduce function in Python indeed does not pass the index to the callback. The Javascript Array.reduce method does, and can get away with this because if you pass more arguments than a Javascript function expects, they are just ignored; so your callback function in Javascript can be like (acc, v) => acc + v and it will ignore the index when it's called with (acc, v, i) as its arguments.
Python functions don't silently ignore extra arguments; if you call a function in Python with too many arguments, it raises a TypeError. This means if reduce called your callback function with the arguments (acc, v, i), then you would be required to provide a callback function which accepts the index, even though in the vast majority of cases, you don't need to use the index for anything. That is, if you could ever call reduce(lambda acc, v, i: ..., ..., ...) where the callback takes three arguments, then you would always have to call reduce like that in Python.
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.
Suppose I have the following example:
class foo:
...
def bar(self, w, x, y, z, ...):
self.w = w
self.x = x
self.y = y
self.z = z
...
I wish to reduce the n-number of attribute assignment lines in bar() to one assignment line set using a setattr() cycle through the arguments. Is there a good way to cycle through said arguments for this purpose?
I wish to retain the defined parameter names so as to limit the number of parameters passed to the function as well as the order in which they are passed. I also understand that functions can be handled like objects; so is it possible to obtain a list of the defined parameters as an attribute of the function and iterate through that?
Use locals() and you can get all the arguments (and any other local variables):
class foo:
def bar(self, w, x, y, z):
argdict = {arg: locals()[arg] for arg in ('w', 'x', 'y', 'z')}
for key, value in argdict.iteritems():
setattr(self, key, value)
...
Might be possible to do it more efficiently, and you could inline argdict if you prefer less lines to readability or find it more readable that way.
So you don't have to actually name the arguments explicitly use:
class foo:
def __init__(self, w, x, y, z):
args = locals()# gets a dictionary of all local parameters
for argName in args:
if argName!='self':
setattr(self, argName, args[argName])
The __setattr__ attribute only assigns one attribute at a time, if you want to assign multiple attribute, you can use **kwargs in your function header and for limiting the number of arguments you can simply check the length of kwargs within your function. and call the __setattr__ for each each of the arguments one by one. One good reason for this recipe is that basically assigning attribute to an object without considering anything is not a correct and desirable job, due to a lot of reasons. Thus you have to assign each attribute one at a time by considering all the required conditions.
You can also do this manually by updating the instance dictionary but you should handle the exceptions too.
In [80]: class foo:
def bar(self, **kwargs):
if len(kwargs) != 4:
raise Exception("Please enter 4 keyword argument")
for k, v in kwargs.items():
foo.__setattr__(self, k, v)
....:
In [81]: f = foo()
In [82]: f.bar(w=1, x=2, y=3, z=4)
In [83]: f.w
Out[83]: 1
In [84]: f.bar(w=1, x=2, y=3, z=4, r=5)
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-84-758f669d08e0> in <module>()
----> 1 f.bar(w=1, x=2, y=3, z=4, r=5)
<ipython-input-80-9e46a6a78787> in bar(self, **kwargs)
2 def bar(self, **kwargs):
3 if len(kwargs) != 4:
----> 4 raise Exception("Please enter 4 keyword argument")
5 for k, v in kwargs.items():
6 foo.__setattr__(self, k, v)
Exception: Please enter 4 keyword argument
By using __setatter__ it will take care of the exception automatically:
In [70]: f.bar(1, 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-70-07d1f3c9e27f> in <module>()
----> 1 f.bar(1, 2)
<ipython-input-65-1049e26120c1> in bar(self, *args)
2 def bar(self, *args):
3 for item in args:
----> 4 foo.__setattr__(self, item, item)
5
TypeError: attribute name must be string, not 'int'
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)
I'm trying to build a python class that parses a string and if it matches a regex that looks
like a function call attempt to call that function on the class, passing in any parameters.
For example a string like "foo("a", 20")" would translate to something like self.foo("a", 20).
Here is the code that I have so far..
class FooTranslate(object):
def create_string(self, letter, size):
return letter*size
def run_function(self, func_str):
match = re.match("([\w_]+)\((|[\W\d\w\,]+)\)", func_str)
if match == None:
print "Couldn't match a regex!"
return False
else:
func, fargs = match.groups()
try:
if fargs == "":
return self.__getattribute__(func)()
else:
return self.__getattribute__(func)(eval(fargs))
except AttributeError, e:
print "Invalid function call: %s" % (func)
return False
This code works in the basic cases...
In [1018]: foot = FooTranslate()
In [1019]: foot.run_function("foo()")
Foo!
In [1020]: foot.run_function("bar(2)")
FooFoo
However in the case of using 2 argument functions:
In [1021]: foot.run_function("create_string('a', 2)")
in run_function(self, func_str)
24 return self.__getattribute__(func)()
25 else:
---> 26 return self.__getattribute__(func)(eval(fargs))
27 except AttributeError, e:
28 print "Invalid function call: %s" % (func)
TypeError: create_string() takes exactly 3 arguments (2 given)
The reason why is that the eval() call returns fargs as a tuple, which create_string()
takes as only a single argument. Any idea how I can pass a variable number of arguments
through to a function call? Or have a better alternative way to do this?
You can use the * operator to explode a tuple into separate arguments to a function. For example:
def f(a, b, c):
print a, b, c
If I call f(...) like this:
f((1,2,3))
I get an error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 3 arguments (1 given)
But if I call it like this:
f(*(1,2,3))
I get:
1 2 3
The * operator will even work if the function takes a variable number of arguments. For example, given the following function:
def f2(a, b, *args):
print a, b,
for x in args:
print x,
print
If I call f2(*(1,2,3,4,5)) it prints:
1 2 3 4 5