I am having a hard time wrapping my head around
why i can make timeit.Timer() work with output from
functools.partial() but not with output from itertools.starmap().
What I basically need is starmap(func, tuples) to have the same 'attributes' as partial(func, one_arg_only)
but be more generally in the sense that I can actually pass into func multiple arguments at the same time.
What's the easiest workaround here ?
I tried timeit.Timer(starmap(func,tuples)) and obviously get the notorious error:
ValueError: stmt is neither a string nor callable
I presume this is coz starmap's output is not callable. But how do I work around this ?
The itertools.starmap() function returns an itertools.starmap iterable type whereas functools.partial() returns a functools.partial callable type. timeit.Timer() expects the first argument to be a callable (or a string it can exec()).
>>> type(itertools.starmap(lambda *args: list(args), [(1, 2)])
itertools.starmap
>>> type(functools.partial(lambda x: x+1, 1))
functools.partial
What you want to do is create a callable that will exhaust the iterable returned by itertools.starmap. One way to do this would be to call the list() function on the output of the starmap:
# This is the function to call
>>> example_func = lambda *args: len(args)
# This is the iterable that can call the example_func
>>> func_callers = itertools.starmap(example_func, [(1, 2)])
# This is the callable that actually processes func_callers
>>> execute_callers = lambda: list(func_callers)
# And finally using the timer
>>> timeit.Timer(execute_callers)
Related
Let's say I have the following function:
def add(x, y):
return x+y
I would like to bind x=2 and y=2 to the function but not actually call it. What is the correct way to do this? I've done this sometimes with add_bound=lambda: add(2,3), but I'm wondering if this is the 'pythonic' approach or there is another way to do it (perhaps binding certain arguments, and then passing other arguments later.
Often this will be done with a decorator. Here is a general example:
add = lambda x,y: x+y
def wrap(outer_func, *outer_args, **outer_kwargs):
def inner_func(*inner_args, **inner_kwargs):
args = list(outer_args) + list(inner_args)
kwargs = {**outer_kwargs, **inner_kwargs}
return outer_func(*args, **kwargs)
return inner_func
In this case you can do things such as the following:
# pass both at once
>>> x=wrap(add,2,3)
>>> x()
5
# pass one at binding, second at call
>>> x=wrap(add,2)
>>> x(3)
5
# pass both when called
>>> x=wrap(add)
>>> x(2,3)
5
Note that the above is very similar to functools.partial:
The partial() is used for partial function application which “freezes” some portion of a function’s arguments and/or keywords resulting in a new object with a simplified signature. For example, partial() can be used to create a callable that behaves like the int() function where the base argument defaults to two:
from functools import partial
basetwo = partial(int, base=2)
basetwo.__doc__ = 'Convert base 2 string to an int.'
basetwo('10010')
18
def add(x=2, y=2):
return x+y
I have the following lists:
para = ['bodyPart', 'shotQuality', 'defPressure', 'numDefPlayers', 'numAttPlayers', 'shotdist', 'angle', 'chanceRating', 'type']
value = [ 0.09786083, 2.30523761, -0.05875112,
0.07905136, -0.1663424 ,-0.73930942, -0.10385882, 0.98845481, 0.13175622]
I want to print using lambda function.
what i want to show is as follow:
coefficient for
bodyPart is 0.09786083
shotQuality is 2.30523761
defPressure is -0.05875112
numDefPlayers is 0.07905136 and so on
I use the following code:
b = lambda x:print(para[x],'is',coeff[x])
print('Coefficient for')
print(b)
and it does not work and only shows this:
Coefficient for
<function <lambda> at 0x000001A8A62A0378>
how can i use lambda function to print to show such output.
thanks
Zep
Lambda function is a function, so you need to use parentheses after the function name to actually call it, just like any other function:
for i in range(len(para)):
print(b(i))
But for the purpose of printing output it's better to use a regular function instead of a lambda function, which is meant for quick expressions rather than functions that do work and return None.
For debugging purposes it can be interesting to print from a lambda function.
You can use a list, tuple or dict to do just that:
Suppose you have lambda function containing a simple test:
lambda x: x > 10
You can then rewrite to print the incoming variable:
lambda x: [print(x), x > 10][-1]
We can now test:
mylambda = lambda x: [print(x), x > 10][-1]
mylambda(12), mylambda(8)
Which yields:
12
8
(True, False)
So, Python functions can return multiple values. It struck me that it would be convenient (though a bit less readable) if the following were possible.
a = [[1,2],[3,4]]
def cord():
return 1, 1
def printa(y,x):
print a[y][x]
printa(cord())
...but it's not. I'm aware that you can do the same thing by dumping both return values into temporary variables, but it doesn't seem as elegant. I could also rewrite the last line as "printa(cord()[0], cord()[1])", but that would execute cord() twice.
Is there an elegant, efficient way to do this? Or should I just see that quote about premature optimization and forget about this?
printa(*cord())
The * here is an argument expansion operator... well I forget what it's technically called, but in this context it takes a list or tuple and expands it out so the function sees each list/tuple element as a separate argument.
It's basically the reverse of the * you might use to capture all non-keyword arguments in a function definition:
def fn(*args):
# args is now a tuple of the non-keyworded arguments
print args
fn(1, 2, 3, 4, 5)
prints (1, 2, 3, 4, 5)
fn(*[1, 2, 3, 4, 5])
does the same.
Try this:
>>> def cord():
... return (1, 1)
...
>>> def printa(y, x):
... print a[y][x]
...
>>> a=[[1,2],[3,4]]
>>> printa(*cord())
4
The star basically says "use the elements of this collection as positional arguments." You can do the same with a dict for keyword arguments using two stars:
>>> a = {'a' : 2, 'b' : 3}
>>> def foo(a, b):
... print a, b
...
>>> foo(**a)
2 3
Actually, Python doesn't really return multiple values, it returns one value which can be multiple values packed into a tuple. Which means that you need to "unpack" the returned value in order to have multiples.
A statement like
x,y = cord()
does that, but directly using the return value as you did in
printa(cord())
doesn't, that's why you need to use the asterisk. Perhaps a nice term for it might be "implicit tuple unpacking" or "tuple unpacking without assignment".
Given the following:
(I) a = map(function, sequence)
(II) a = [function(x) for x in sequence]
When would I need to use (I)? Why choose a map object over a list when the latter is subscriptable and IMO more readable?
Also, could someone explain line 6 of the following code (Python 3):
>>>import math
>>>a = map(int,str(math.factorial(100)))
>>>sum(a)
648
>>>sum(a)
0
Why is the sum of the map object changing?
When would I need to use (I)? Why choose a map object over a list when the latter is subscriptable and IMO more readable?
map was introduced in Python 1.0, while list comprehension was not introduced until Python 2.0.
For Python 2+, you never need to use one or the other.
Reasons for still using map could include:
preference. You prefer list comprehension, not everyone agrees.
familiarity. map is very common across languages. If Python's not your native language, "map" is the function you'll look up.
brevity. map is often shorter. Compare map and lambda f,l: [f(x) for x in l].
I is an iterator -- it creates a stream of values which then vanish. II is a list -- it lasts for a while and has lots of features, like len(mylist) and mylist[-3:].
The sum changes because the iterator vanishes after you use it.
Use lists and list comprehensions. If you process tons of data, then iterators (and generators, and generator comprehensions) are awesome, but they can be confusing.
Or, use an iterator and convert into a list for further processing:
a = list( map(int,str(math.factorial(100))) )
From the docs:
Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel...
The sum changes to 0 because the iterator is iterated, so it becomes nothing. This is the same concept with .read() (Try calling x = open('myfile.txt'), and then type print x.read() twice.)
In order to preserve the iterable, surround it with list():
>>> import math
>>> a = map(int,str(math.factorial(100)))
>>> sum(a)
648
>>> sum(a)
0
>>> a = list(map(int,str(math.factorial(100))))
>>> sum(a)
648
>>> sum(a)
648
Example from the docs:
>>> seq = range(8)
>>> def add(x, y): return x+y
...
>>> map(add, seq, seq)
[0, 2, 4, 6, 8, 10, 12, 14]
primes = [2,3,5,7..] (prime numbers)
map(lambda x:print(x),primes)
It does not print anything.
Why is that?
I've tried
sys.stdout.write(x)
too, but doesn't work either.
Since lambda x: print(x) is a syntax error in Python < 3, I'm assuming Python 3. That means map returns a generator, meaning to get map to actually call the function on every element of a list, you need to iterate through the resultant generator.
Fortunately, this can be done easily:
list(map(lambda x:print(x),primes))
Oh, and you can get rid of the lambda too, if you like:
list(map(print,primes))
But, at that point you are better off with letting print handle it:
print(*primes, sep='\n')
NOTE: I said earlier that '\n'.join would be a good idea. That is only true for a list of str's.
This works for me:
>>> from __future__ import print_function
>>> map(lambda x: print(x), primes)
2
3
5
7
17: [None, None, None, None]
Are you using Python 2.x where print is a statement, not a function?
Alternatively, you can unpack it by putting * before map(...) like the following
[*map(...)]
or
{*map(...)}
Choose the output you desire, a list or a dictionary.
Another reason why you could be seeing this is that you're not evaluating the results of the map function. It returns a generator (an iterable) that evaluates your function lazily and not an actual list.
primes = [2,3,5,7]
map(print, primes) # no output, because it returns a generator
primes = [2,3,5,7]
for i in map(print, primes):
pass # prints 2,3,5,7
Alternately, you can do list(map(print, primes)) which will also force the generator to be evaluated and call the print function on each member of your list.