Is there a more elegant way to write the following piece of Python?
[foo() for i in range(10)]
I want to accumulate the results of foo() in a list, but I don't need the iterator i.
One way to do this is to use _:
[foo() for _ in range(10)]
This means exactly the same thing, but by convention the use of _ indicates to the reader that the index isn't actually used for anything.
Presumably foo() returns something different every time you call it. If it doesn't, and it returns the same thing each time, then you can:
[foo()] * 10
to replicate the result of calling foo() once, 10 times into a list.
map would be nice if foo() took an argument, but it doesn't. So instead, create a dummy lambda that takes an integer argument, but just calls foo():
map(lambda i:foo(), range(10))
If you are on Python 3.x, map returns an iterator instead of a list - just construct a list with it:
list(map(lambda i:foo(), range(10)))
By no means more elegant, but:
[x() for x in [foo]*10]
I think beyond that you have to go to Ruby ;)
map(lambda _ : foo(), range(10))
although this trades your problem with a meaningless iterator i with a new meaningless argument to the lambda expression.
Related
I tried the following in the IDLE of Python 3.6
print(value for value in range(1,100))
A message is produced in the IDLE which says
<generator object <genexpr> at 0x101b73a40>
I'm confused what this means. Have I done anything wrong?
(value for value in range(1,100)) produces generator object, if you want to print list, just wrap it in []
print([value for value in range(1,100)])
or you can simply
print(list(range(1,100)))
You can read what generators are HERE
A function which returns a generator iterator. It looks like a normal function except that it contains yield expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the next() function.
Usually refers to a generator function, but may refer to a generator iterator in some contexts. In cases where the intended meaning isn’t clear, using the full terms avoids ambiguity.
print([value for value in range(1,100)])
You should include it inside a list [] to generate the values
All you wanted is to use list comprehension here but you are not using list.
Simply it should be
for i in range(1,100):
print(i)
If you want to still use list comprehension it will be like this
[print(x) for x in range(1,100)]
this will give the output like
1
2
3
....
99
100
[None, None, None, ...97 times more]
I'm trying to learn pure functional programming. But this code is puzzling me particularly the second line. I do not understand how the value 2 is passed to the variable x. Can somebody explain this nested lambda behaviour?
>>> square_func = lambda x: x**2
>>> function_product = lambda F, m: lambda x: F(x)*m
>>> square_func(2)
4
>>> function_product(square_func, 3)(2)
12
The inner lambda creates a function when the outer lambda is called. The outer lambda returns this function. This function is then called with the argument 2.
A good place to start would be to apply type to your definitions and see if it clarifies things. Also, I can't help but remark that something like Haskell would be a nicer place to start if you are interested in functional programming, even if you do not plan on using the language. That being said, here is what you get:
In [13]: type(square_func)
Out[13]: function
In [14]: type(function_product)
Out[14]: function
In [15]: type(square_func(2))
Out[15]: int
In [16]: type(function_product(square_func, 3))
Out[16]: function
In [17]: type(function_product(square_func, 3)(2))
Out[17]: int
So the puzzling part is the return type of function_product(square_func, 3), which is a function itself, one that is presumably intended to take a single number and return a single number. You could write it as:
f = function_product(square_func, 3)
f(2)
It's kind of a rule (or convention), if you follow the style guide, not to use lambda in the context you have used. The reason for this is exactly what made you turn to the internet in confusion. The flags are:
You are giving an anonymous function a name
There are multiple lambda. For a language that does not have nested anonymous functions, this is a code smell. There must be a better way
How about writing this way and reaping the benefits:
def function_product(F, m): # returns inner, a function
def inner(x): # takes x, and closes over F and m from
return F(x)*m # outer scope, hence a closure
return inner
See, everything is clear because it's more readable now. Avoid lambda, maybe except for callbacks,like in sorted(). Normal functions are objects, just like 10 and hello are.
Always do import this. :)
function_product asks for a function and a variable, you passed square_func and 3. Then, the inner function of function_product takes the result of the function you passed (square_func) and multiply it by the variable you passed, so:
square_func(2)*3 = 12
function_product(square_func, 3) returns other lamba function which can be defined implicitly like this:
lambda x: square_func(x)*3
next by calling the other lamba function you pass 2 to the variable x
The following python code produces [(0, 0), (0, 7)...(0, 693)] instead of the expected list of tuples combining all of the multiples of 3 and multiples of 7:
multiples_of_3 = (i*3 for i in range(100))
multiples_of_7 = (i*7 for i in range(100))
list((i,j) for i in multiples_of_3 for j in multiples_of_7)
This code fixes the problem:
list((i,j) for i in (i*3 for i in range(100)) for j in (i*7 for i in range(100)))
Questions:
The generator object seems to play the role of an iterator instead of providing an iterator object each time the generated list is to be enumerated. The later strategy seems to be adopted by .Net LINQ query objects. Is there an elegant way to get around this?
How come the second piece of code works? Shall I understand that the generator's iterator is not reset after looping through all multiples of 7?
Don't you think that this behavior is counter intuitive if not inconsistent?
A generator object is an iterator, and therefore one-shot. It's not an iterable which can produce any number of independent iterators. This behavior is not something you can change with a switch somewhere, so any work around amounts to either using an iterable (e.g. a list) instead of an generator or repeatedly constructing generators.
The second snippet does the latter. It is by definition equivalent to the loops
for i in (i*3 for i in range(100)):
for j in (i*7 for i in range(100)):
...
Hopefully it isn't surprising that here, the latter generator expression is evaluated anew on each iteration of the outer loop.
As you discovered, the object created by a generator expression is an iterator (more precisely a generator-iterator), designed to be consumed only once. If you need a resettable generator, simply create a real generator and use it in the loops:
def multiples_of_3(): # generator
for i in range(100):
yield i * 3
def multiples_of_7(): # generator
for i in range(100):
yield i * 7
list((i,j) for i in multiples_of_3() for j in multiples_of_7())
Your second code works because the expression list of the inner loop ((i*7 ...)) is evaluated on each pass of the outer loop. This results in creating a new generator-iterator each time around, which gives you the behavior you want, but at the expense of code clarity.
To understand what is going on, remember that there is no "resetting" of an iterator when the for loop iterates over it. (This is a feature; such a reset would break iterating over a large iterator in pieces, and it would be impossible for generators.) For example:
multiples_of_2 = iter(xrange(0, 100, 2)) # iterator
for i in multiples_of_2:
print i
# prints nothing because the iterator is spent
for i in multiples_of_2:
print i
...as opposed to this:
multiples_of_2 = xrange(0, 100, 2) # iterable sequence, converted to iterator
for i in multiples_of_2:
print i
# prints again because a new iterator gets created
for i in multiples_of_2:
print i
A generator expression is equivalent to an invoked generator and can therefore only be iterated over once.
The real issue as I found out is about single versus multiple pass iterables and the fact that there is currently no standard mechanism to determine if an iterable single or multi pass: See Single- vs. Multi-pass iterability
If you want to convert a generator expression to a multipass iterable, then it can be done in a fairly routine fashion. For example:
class MultiPass(object):
def __init__(self, initfunc):
self.initfunc = initfunc
def __iter__(self):
return self.initfunc()
multiples_of_3 = MultiPass(lambda: (i*3 for i in range(20)))
multiples_of_7 = MultiPass(lambda: (i*7 for i in range(20)))
print list((i,j) for i in multiples_of_3 for j in multiples_of_7)
From the point of view of defining the thing it's a similar amount of work to typing:
def multiples_of_3():
return (i*3 for i in range(20))
but from the point of view of the user, they write multiples_of_3 rather than multiples_of_3(), which means the object multiples_of_3 is polymorphic with any other iterable, such as a tuple or list.
The need to type lambda: is a bit inelegant, true. I don't suppose there would be any harm in introducing "iterable comprehensions" to the language, to give you what you want while maintaining backward compatibility. But there are only so many punctuation characters, and I doubt this would be considered worth one.
I want this:
[foo() for _ in xrange (100)]
but beautifuller. ?
You can write a generator repeat like this:
def repeat(times, func, *args, **kwargs):
for _ in xrange(times):
yield func(*args, **kwargs)
Then:
list(repeat(100, foo))
It also accepts arguments to be passed on to the function, so you can:
from random import randint
list(repeat(100, randint, 1, 100)) # 100 random ints between 1 and 100
Since it's a generator, you can pipe it into any kind of iterable, be it a list (as here) or a tuple or a set, or use it in a comprehension or a loop.
I'm afraid you're not gonna get it any prettier than that in Python, except that some people would advise against _ for an "anonymous" variable. This is the Pythonic idiom for doing what you want.
(The _ can be considered confusing to novices because it can be mistaken for special syntax. I use it, but only in the "expert parts" of my code. I also encounter it more and more often, but opinion still seems a bit divided on this one.)
Depending on your definition of "beautifuller", you may prefer this:
map(lambda x: foo(), xrange(100))
Although what you have already is much nicer IMO.
Depending on what it does, you can make foo() a generator.
Your list comprehension is already beatiful and effective but if you need several options to do the same things then i think you can use map here. In case you need to call a certain function the specified number of times use:
# in case your func looks like
def func():
# do something
#then
map(func(), xrange(numberOfTimes))
In case your function need value from range then you can use map with lambda:
# in case your func looks like
def func(value):
# do something with value
#then
map(lambda val: func(val), xrange(numberOfTimes))
Or in case you need to use data from several lists of the same length:
# in case your func looks like
def func(value1, value2):
# do something with values
#then
map(lambda val: func(*val), zip(xrange(10), xrange(10,20)))
And so on...
In case foo() always returns the same result, you could use
[foo()]*100
This has the advantage that foo() is only called once.
Edit: As #larsmans points out this only makes sense though if foo() returns an immutable result.
In all other cases, your solution is fine!
This question already has answers here:
Python: Is the split function evaluated multiple times in a list comprehension?
(3 answers)
Closed 7 years ago.
Which one's a better way of doing list comprehension in python (in terms of computation time & cpu cycles).
In example (1) is the value f(r) evaluated in each iteration or is it evaluated once and cached ?
y = [x*f(r) for x in xlist]
c = f(r)
y = [x*c for x in xlist]
where
def f(r):
... some arbitrary function ...
It evaluates for every iteration. Look at this:
>>> def f():
... print("func")
...
>>> [f() for i in range(4)]
func
func
func
func
[None, None, None, None]
As you say, if f() has no side effects, storing the return value on a variable and using that variable instead is a lot faster solution.
I would probably choose the latter because the Python compiler doesn't know if the function has side-effects so it is called for each element.
Here is an easy way to find out:
>>> def f():
... print "called"
... return 1
...
>>> [1+f() for x in xrange(5)]
called
called
called
called
called
[2, 2, 2, 2, 2]
so yes, if the function is going to be the same each time then it is better to call it once outside the list comprehension.
The function f will be called for every element.
It is very complex for the compiler/interpreter to determine that the function need not to be called many times. It is then very probable that the function is called many times. Thus, using the second solution is always the best solution.
Functions have a non-trivial execution time compared to a name lookup, and caching the value is considered acceptable if the function is called many times and the same value is expected each time.
Python is probably free to do it once or many times, I'm not sure I would rely on any observed behavior. It might change in the next version.
If it's important to you to make sure the function is only called once, call it yourself and save the results.