11

I want this:

[foo() for _ in xrange (100)]

but beautifuller. ?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Manav
  • 10,094
  • 6
  • 44
  • 51
  • 4
    Coming from a C# background, that's pretty beautiful. It's beautifuller than `Enumerable.Range(0, 100).Select(x => foo());`. – Phil Jul 13 '11 at 19:35

6 Answers6

8

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.

kindall
  • 178,883
  • 35
  • 278
  • 309
5

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.)

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • I thought `_` was the pythonic name for an unused variable? – Davy8 Jul 13 '11 at 18:10
  • @Davy8: it seems not everyone agrees; @Sven Marnach got two upvotes went he told me [not to use `_` this way](http://stackoverflow.com/questions/5384570/whats-the-shortest-way-to-count-the-number-of-items-in-a-generator-iterator). – Fred Foo Jul 13 '11 at 18:13
  • One advantage of using `_` is that it will prevent PyLint from complaining about an unused variable. I think any variable name starting with `_` will work. – interjay Jul 13 '11 at 18:15
  • I personally prefer something like `ignored` or `_ignored`, since that actually says ignored in the name of the ignored variable. – SingleNegationElimination Jul 13 '11 at 20:13
3

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.

actionshrimp
  • 5,219
  • 3
  • 23
  • 26
2

Depending on what it does, you can make foo() a generator.

nmichaels
  • 49,466
  • 12
  • 107
  • 135
  • in my case (foo being a simple function that returns different unparameterized results on each call), making it a generator seems to be overkill. – Manav Jul 13 '11 at 18:27
2

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...

Artsiom Rudzenka
  • 27,895
  • 4
  • 34
  • 52
1

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!

mhyfritz
  • 8,342
  • 2
  • 29
  • 29
  • 1
    But if `foo` returns mutable results, even if they compare equal by `==`, this blows up in your face. – Fred Foo Jul 13 '11 at 18:14
  • this is just wrong as `foo()` is called only once, as opposed to 100 calls in OP: `[randint(1,100)]*5` gives `[26, 26, 26, 26, 26]` – davka May 08 '19 at 11:10
  • That's why I pointed out that `foo()` has to always return the same result -- `randint()` clearly does not do that. – mhyfritz May 10 '19 at 05:41