pythonic的方式做N次没有索引变量?

问题:pythonic的方式做N次没有索引变量?

我每天都越来越喜欢python。

今天,我正在编写一些代码,例如:

for i in xrange(N):
    do_something()

我必须做N次。但是每次都不依赖于i(索引变量)的值。我意识到我正在创建一个我从未使用过的变量(i),并且我想:“无疑,这是一种更加Python化的方法,不需要那个无用的索引变量。”

所以…问题是:您知道如何以更(pythonic)漂亮的方式完成此简单任务吗?

Every day I love python more and more.

Today, I was writing some code like:

for i in xrange(N):
    do_something()

I had to do something N times. But each time didn’t depend on the value of i (index variable). I realized that I was creating a variable I never used (i), and I thought “There surely is a more pythonic way of doing this without the need for that useless index variable.”

So… the question is: do you know how to do this simple task in a more (pythonic) beautiful way?


回答 0

比循环更快的方法xrange(N)是:

import itertools

for _ in itertools.repeat(None, N):
    do_something()

A slightly faster approach than looping on xrange(N) is:

import itertools

for _ in itertools.repeat(None, N):
    do_something()

回答 1

使用_变量,正如我在问这个问题时所了解到的,例如:

# A long way to do integer exponentiation
num = 2
power = 3
product = 1
for _ in xrange(power):
    product *= num
print product

Use the _ variable, as I learned when I asked this question, for example:

# A long way to do integer exponentiation
num = 2
power = 3
product = 1
for _ in xrange(power):
    product *= num
print product

回答 2

我只是使用for _ in range(n),这很重要。它会在Python 2中生成大量数字的整个列表,但是如果您使用的是Python 3,这不是问题。

I just use for _ in range(n), it’s straight to the point. It’s going to generate the entire list for huge numbers in Python 2, but if you’re using Python 3 it’s not a problem.


回答 3

由于函数是一等公民,因此您可以编写小型包装器(来自Alex的回答)

def repeat(f, N):
    for _ in itertools.repeat(None, N): f()

那么您可以将函数作为参数传递。

since function is first-class citizen, you can write small wrapper (from Alex answers)

def repeat(f, N):
    for _ in itertools.repeat(None, N): f()

then you can pass function as argument.


回答 4

_与x相同。但是,这是一个python惯用法,用于指示您不打算使用的标识符。在python中,这些标识符不会像其他语言中的变量那样占用内存或分配空间。很容易忘记这一点。它们只是指向对象的名称,在这种情况下,每次迭代都是一个整数。

The _ is the same thing as x. However it’s a python idiom that’s used to indicate an identifier that you don’t intend to use. In python these identifiers don’t takes memor or allocate space like variables do in other languages. It’s easy to forget that. They’re just names that point to objects, in this case an integer on each iteration.


回答 5

我发现各种答案确实很不错(尤其是Alex Martelli的答案),但是我想直接量化性能,因此我编写了以下脚本:

from itertools import repeat
N = 10000000

def payload(a):
    pass

def standard(N):
    for x in range(N):
        payload(None)

def underscore(N):
    for _ in range(N):
        payload(None)

def loopiter(N):
    for _ in repeat(None, N):
        payload(None)

def loopiter2(N):
    for _ in map(payload, repeat(None, N)):
        pass

if __name__ == '__main__':
    import timeit
    print("standard: ",timeit.timeit("standard({})".format(N),
        setup="from __main__ import standard", number=1))
    print("underscore: ",timeit.timeit("underscore({})".format(N),
        setup="from __main__ import underscore", number=1))
    print("loopiter: ",timeit.timeit("loopiter({})".format(N),
        setup="from __main__ import loopiter", number=1))
    print("loopiter2: ",timeit.timeit("loopiter2({})".format(N),
        setup="from __main__ import loopiter2", number=1))

我还提出了另一种解决方案,该解决方案基于Martelli的解决方案,并用于map()调用有效负载函数。好的,我有点作弊,因为我可以自由地使有效负载接受被丢弃的参数:我不知道是否有解决方法。不过,结果如下:

standard:  0.8398549720004667
underscore:  0.8413165839992871
loopiter:  0.7110594899968419
loopiter2:  0.5891903560004721

因此使用map会比loop的标准提高约30%,比Martelli的标准提高19%。

I found the various answers really elegant (especially Alex Martelli’s) but I wanted to quantify performance first hand, so I cooked up the following script:

from itertools import repeat
N = 10000000

def payload(a):
    pass

def standard(N):
    for x in range(N):
        payload(None)

def underscore(N):
    for _ in range(N):
        payload(None)

def loopiter(N):
    for _ in repeat(None, N):
        payload(None)

def loopiter2(N):
    for _ in map(payload, repeat(None, N)):
        pass

if __name__ == '__main__':
    import timeit
    print("standard: ",timeit.timeit("standard({})".format(N),
        setup="from __main__ import standard", number=1))
    print("underscore: ",timeit.timeit("underscore({})".format(N),
        setup="from __main__ import underscore", number=1))
    print("loopiter: ",timeit.timeit("loopiter({})".format(N),
        setup="from __main__ import loopiter", number=1))
    print("loopiter2: ",timeit.timeit("loopiter2({})".format(N),
        setup="from __main__ import loopiter2", number=1))

I also came up with an alternative solution that builds on Martelli’s one and uses map() to call the payload function. OK, I cheated a bit in that I took the freedom of making the payload accept a parameter that gets discarded: I don’t know if there is a way around this. Nevertheless, here are the results:

standard:  0.8398549720004667
underscore:  0.8413165839992871
loopiter:  0.7110594899968419
loopiter2:  0.5891903560004721

so using map yields an improvement of approximately 30% over the standard for loop and an extra 19% over Martelli’s.


回答 6

假设您已将do_something定义为一个函数,并且您想执行N次。也许您可以尝试以下方法:

todos = [do_something] * N  
for doit in todos:  
    doit()

Assume that you’ve defined do_something as a function, and you’d like to perform it N times. Maybe you can try the following:

todos = [do_something] * N  
for doit in todos:  
    doit()

回答 7

一个简单的while循环呢?

while times > 0:
    do_something()
    times -= 1

您已经有了变量;为什么不使用它?

What about a simple while loop?

while times > 0:
    do_something()
    times -= 1

You already have the variable; why not use it?