How do I resue a function in another function? - python

I have created a function in python to print the square value of a list's elements as shown below:
def square_list(list1):
lst = []
for i in list1:
lst.append(i*i)
return lst
x = [2,4,6,8]
print(square_list(x))
This is the output [4, 16, 36, 64]
I would like to reuse this function again as shown below:
n = [2,4,6,8]
print(list(map(square_list,n)))
But it shows this type of error as shown below:
TypeError Traceback (most recent call last)
<ipython-input-80-9c542410d2fa> in <module>
1 # list=[m,n,p] + f()==> Map ==> modified list = [f(m),f(n),f(p)]
2 n = [2,4,6,8]
----> 3 print(list(map(square_list,n)))
<ipython-input-79-51bec1661935> in square_list(list1)
1 def square_list(list1):
2 lst = []
----> 3 for i in list1:
4 lst.append(i*i)
5 return lst
TypeError: 'int' object is not iterable
May you please tell me where is my mistake and explain to me?

map() iterates over the list and passes each element to the function. That means the function needs to accept the individual elements of the list, not the list itself. You can't use the same function for both. map() simplifies the function to just:
def square_list(n):
return n * n
n = [2,4,6,8]
print(list(map(square_list,n)))
# [4, 16, 36, 64]
because it takes care of the iteration as part of the process.

If you want to use the same function for both cases, you can check the type of the parameter.
def square(x):
if type(x) is list:
lst = []
for i in x:
lst.append(i*i)
return lst
return x * x
Demo

Related

optional multiple return values

I have a function that most of the time should return a single value, but sometimes I need a second value returned from the function. Here I found how to return multiple values, but as most of the time I need only one of them I would like to write something like this:
def test_fun():
return 1,2
def test_call():
x = test_fun()
print x
but calling this results in
>>> test_call()
(1,2)
and when trying to return more than two, as in
def test_fun2():
return 1,2,3
def test_call2():
x,y = test_fun2()
print x,y
I get an error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "my_module.py", line 47, in test_call2
x,y = test_fun2()
ValueError: too many values to unpack
I am thinking about something like in matlab, where x = test_fun() would result in x == 1 (while [x y] = test_fun() would also work as expected). Is something like that possible in python?
You can use star unpacking to gather all additional return values into a list:
x, *y = fun()
x will contain the first return value. y will be a list of the remaining values. y will be empty if there is only one return value. This particular example will only work if the function returns a tuple, even if there is only one value.
When fun always returns 1 or 2 values, you can just do
if y:
print(y[0])
else:
print('only one value')
If, on the other hand, you want to completely ignore the number of return values, do
*x = fun()
Now all the arguments will be gathered into the list. You can then print it with either
print(x)
or
print(*x)
The latter will pass each element as a separate argument, exactly as if you did
x, y, z = fun()
print(x, y, z)
The reason to use *x = fun() instead of just x = fun() is to get an error immediately when a function returns something that isn't a tuple. Think of it as an assertion to remind you to write fun properly.
Since this form of star unpacking only works in Python 3, your only option in Python 2 is to do
x = fun()
and to inspect the result manually.
There are several ways to get multiple return values.
Example 1:
def test_fun():
return 1,2
def test_call():
x, y = test_fun()
print x
print y
you will get correct output:
1
2
When you would like to ignore several return values, you can use * before a variable in python3.
Example 2:
def test_fun2():
return 1,2,3
def test_call2():
x, *y = test_fun2()
print x
print y
you will get the result:
1
(2, 3)

using filter in Python 3

I am pretty much copying from the example given in online docs, but using filter() in windows-based Python 3 is perplexing me. What is wrong here:
a=[1,2,3,4]
b=[1,0,1,0]
f=filter(b,a)
for fs in f : print(fs)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not callable
f=list(filter(b,a))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not callable
Online docs say to throw list() in, but that clearly helps not.
First argument of filter must be a function or lambda. You passed b which is a list.
Filter's documentation clearly states that it takes a function and an iterable as input. Perhaps if you want to check if a value is in both a and b, you could do something like:
f = filter(lambda x: x in b, a)
and then loop over f.
You are misunderstanding how filter works, filter needs a function that returns True for each item that you want to keep.
I'm assuming b describes the things in a you want to select, then you meant something like::
f = filter(lambda x: x[1], zip(a, b))
for fs, _ in f: ...
You can also replace filter with a list comprehension:
f = [x for x, y in zip(a, b) if y]
for fs in f: ...
But there is a function in itertools that does exactly this:
import itertools as it
f = it.compress(a, b)
for fs in f: ...
Basically filter takes a function and an iterable value to filter in
a = [1,2,3,4]
b = [1,0,1,0]
f = filter(lambda val: val not in b, a)
for fs in f: print(fs)
output:
2
3
4
Confusion occurs when we call filter with None
list(filter(None, [0,1,2]))
# This returns [1,2] Which is a special case
# and it is not equal to:
list(filter(1, [0,1,2])) #invalid
The reason being When we pass filter condition as None filter function checks each value in the list and sees if they qualify the if value condition.
Which roughly translates to this.
[value for value in [0,1,2] if value]

Turning any single-argument function into a generator function?

In David Beazley's talk on generators, he shows how to create a generator function from any single-argument function thus:
def generate(func):
def gen_func(s):
for item in s:
yield func(item)
return gen_func
and illustrates it with math.sqrt:
gen_sqrt = generate(math.sqrt)
for x in gen_sqrt(xrange(100)):
print x
So why does:
gen_sum = generate(sum)
for x in gen_sum([1,2,3,4,5]):
print x
produce:
TypeError Traceback (most recent call last)
<ipython-input-73-ef521f2bbfc8> in <module>()
1 gen_sum = generate(sum)
----> 2 for x in gen_sum(1):
3 print x
<ipython-input-50-3c0ba12c2429> in gen_func(s)
1 def generate(func):
2 def gen_func(s): # closure
----> 3 for item in s:
4 yield func(item)
5 return gen_func
TypeError: 'int' object is not iterable
Is it more accurate to say that the function being a single-argument function is a necessary but insufficient condition for this approach to work? And that the other necessary condition is that the single argument must be a single item (and not a sequence)?
You're passing a list whose elements are the wrong type. Of course it's not going to work, for the same reason that gen_sqrt(['a', 's', 'd', 'f']) wouldn't have worked.
You need to pass gen_sum a list of things it makes sense to call sum on, such as other lists:
for x in gen_sum([[1, 2], [3, 4]]):
print x
Output:
3
7
You are correct, both are necessary requirements:
def generate(func):
def gen_func(s):
for item in s: # <--- requires s to be interable
yield func(item) # <--- requires func to accept a single argument
return gen_func
So in
gen_sum = generate(func)
for x in gen_sum(s):
print x
func must accept a single argument and s must be iterable.
generate is the generator version of map.
map(lambda x: x*2, range(5)) [0, 2, 4, 6, 8]
It takes the input range and applies the function the each of the element in the range.
generate does the same, but it doesn't return a list. It yields the result of each transformation.
Now take a look at your example. What would be the first result? sum(1).
But sum expects a list, not an integer, hence the error message.

Having trouble with classes Python

this is my assignment:
SortedStringBag(initial_list) create a new sorted string bag object and give it the initial list of strings. Sort the list. This is the only time you can sort.
print() print all the contents of the list, one per line. Remember it must be sorted at all times.
count(s) tell how many times string s occurs in this bag. Return 0 if not found at all.
insert(s) insert string s into the list using O(n) algorithm.
Hint: to sort a python list, simply do:
mylist.sort()
heres what i've done
class SortedStringBag:
def __init__(self,initial_list):
self.ilist = initial_list.sort()
def __str__(self):
for i in self:
if self[i]<self[i+1]:
print(self[i])
def insert(self, s):
for i in range(len(self.ilist)):
if self[i] > item:
self.insert(i, item)
else:
self.append(s)
def count(self, s):
i = 0
for n in self:
if s in self[n]:
i = i+1
for some reason I cant get the top of it positioned correctly but it is in my code.
I really don't understand classes, for some reason none of the methods associate with the class
Your main problem here is that you are mixing up calling self with self.ilist, giving you errors like:
>>> import StringBag
>>> mylist = StringBag.SortedStringBag([1, 8, 3, -1, 9, 3, 7, 23 , 6])
>>> print mylist
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "testt.py", line 5, in __str__
for i in self:
TypeError: iteration over non-sequence
>>>
However, you have another key error, which is assigning a variable to the value of a method. Methods do not return anything, so trying to assign them will give you a value of None:
>>> var = [1, 3, 4, 2].sort()
>>> print var
None
>>>
Here is your edited code:
class SortedStringBag:
def __init__(self,initial_list):
self.ilist = sorted(initial_list)
def __str__(self):
return '\n'.join([str(item) for item in self.ilist])
def insert(self, s):
for i in range(len(self.ilist)):
if self.ilist[i] > s:
self.ilist.insert(i, s)
break
else:
self.ilist.append(s)
def count(self, s):
i = 0
for n in self.ilist:
if s == n:
i+=1
return i
Runs as:
>>> import StringBag
>>> mylist = StringBag.SortedStringBag([1, 8, 3, -1, 9, 3, 7, 23 , 6])
>>> print mylist
-1
1
3
3
6
7
8
9
23
>>> mylist.count(3)
2
>>> mylist.count(2)
0
>>> mylist.insert(4)
>>> print mylist
-1
1
3
3
4
6
7
8
9
23
>>> mylist.count(4)
1
>>>

How to use filter function in python 33

I'm now start learning python and I'm have problem with filter function.
If I run
list=list(range(10))
def f(x): return x % 2 != 0
print(((filter(f,list))))
I will get the result is
filter object at 0x00000000028B4E10
Process finished with exit code 0
And if I modify the code to
list=list(range(10))
def f(x): return x % 2 != 0
print(list(filter(f,list)))
The result I get will be
Traceback (most recent call last):
File "C:/Users/Vo Quang Hoa/PycharmProjects/HelloWorld/Hello.py", line 6, in <module>
print(list(filter(f,list)))
TypeError: 'list' object is not callable
Process finished with exit code 1
What's happend. How to get the list 1 3 5 7 9
Thank for your help.
You renamed list, giving it a different value. Don't do that, you shadowed the built-in type. Change your code to use a different name instead:
some_list = list(range(10))
def f(x): return x % 2 != 0
print(list(filter(f, some_list)))
and then filter() works just fine.
Your main problem is that you called your list variable, um, list. You must not use the same name as other objects! Call your list something else, and/or use a naming convention like upper camel case;
Fred=list(range(10))
def f(x): return x % 2 != 0
print(list(filter(f,Fred)))
I hope this help to you
ran=range(10)
def f(x): return x % 2 != 0
res = filter(f,ran)
for i in res:
print(i,end=' ')

Categories

Resources