【问题标题】:Does Python have any for loop equivalent (not foreach)Python是否有任何等效的for循环(不是foreach)
【发布时间】:2010-12-29 08:05:08
【问题描述】:

Python 的迭代器非常棒,但有时我确实想要 C 风格的 for 循环——而不是 foreach 循环。例如,我有一个开始日期和一个结束日期,我想在这个范围内的每一天做一些事情。当然,我可以使用 while 循环来做到这一点:

    current = start
    while current <= finish:
        do_stuff(current)
        current += timedelta(1)

这可行,但它是 3 行而不是 1 行(在 C 或基于 C 的语言中)而且我经常发现自己忘记编写递增行,尤其是在循环体非常复杂的情况下。在 Python 中是否有更优雅且不易出错的方式来执行此操作?

【问题讨论】:

    标签: python loops for-loop


    【解决方案1】:

    仅出于迭代的目的,您实际上应该在 range 上使用 xrange,因为 xrange 将简单地返回一个迭代器,而 range 将创建一个包含从 first 到 last 的整个整数范围的实际列表对象-1(当你想要的只是一个简单的for循环时,显然效率较低):

    for i in xrange(current,finish+1, timedelta(1)):
        do_stuff(i)
    

    此外,还有枚举,它返回一个枚举对象,该对象将产生一个递增的计数和集合的值,即:

    l = ["a", "b", "c"]
    for ii, value in enumerate(l):
        print ii, value
    

    结果:

    0 a
    1 b
    2 c
    

    【讨论】:

    • -1 在发布之前测试答案。结果是TypeError: an integer is requiredxrange() 的所有参数必须是整数。
    • xrange 应该被命名为irange,因为它返回一个迭代器,而range 应该总是返回一个列表;对xrange 的唯一约束应该是next=start; next=next+step; until next==end,即start 必须是__add__able 到step,结果必须是__cmp__able 到end
    【解决方案2】:

    优雅的 Pythonic 方法是将日期范围的概念封装在它自己的生成器中,然后在您的代码中使用该生成器:

    import datetime
    
    def daterange(start, end, delta):
        """ Just like `range`, but for dates! """
        current = start
        while current < end:
            yield current
            current += delta
    
    start = datetime.datetime.now()
    end = start + datetime.timedelta(days=20)
    
    for d in daterange(start, end, datetime.timedelta(days=1)):
        print d
    

    打印:

    2009-12-22 20:12:41.245000
    2009-12-23 20:12:41.245000
    2009-12-24 20:12:41.245000
    2009-12-25 20:12:41.245000
    2009-12-26 20:12:41.245000
    2009-12-27 20:12:41.245000
    2009-12-28 20:12:41.245000
    2009-12-29 20:12:41.245000
    2009-12-30 20:12:41.245000
    2009-12-31 20:12:41.245000
    2010-01-01 20:12:41.245000
    2010-01-02 20:12:41.245000
    2010-01-03 20:12:41.245000
    2010-01-04 20:12:41.245000
    2010-01-05 20:12:41.245000
    2010-01-06 20:12:41.245000
    2010-01-07 20:12:41.245000
    2010-01-08 20:12:41.245000
    2010-01-09 20:12:41.245000
    2010-01-10 20:12:41.245000
    

    这类似于关于range 的答案,除了内置的range 不适用于日期时间,因此我们必须创建自己的,但至少我们可以在封装中只做一次方式。

    【讨论】:

    • +1 不仅因为它是真正有效的唯一答案,还因为它是正确的答案。说真的,不要投票只是看起来不错的答案
    【解决方案3】:

    在 Python 中以紧凑的方式进行操作并不容易,因为该语言背后的基本概念之一是无法在比较时进行分配。

    对于复杂的事情,比如日期,我认为 Ned 的答案很棒,但对于更简单的情况,我发现 itertools.count() 函数非常有用,它返回连续的数字。

    >>> import itertools
    >>> begin = 10
    >>> end = 15
    >>> for i in itertools.count(begin):
    ...   print 'counting ', i
    ...   if i > end:
    ...     break
    ...
    counting  10
    counting  11
    counting  12
    counting  13
    counting  14
    counting  15
    counting  16
    

    我发现它不太容易出错,因为正如您所说,忘记“当前 += 1”很容易。对我来说,创建一个无限循环然后检查结束条件似乎更自然。

    【讨论】:

    • WTF?为什么不直接使用for i in xrange(begin, end):
    【解决方案4】:

    这将在紧要关头起作用:

    def cfor(start, test_func, cycle_func):
        """A generator function that emulates the most common case of the C for
        loop construct, where a variable is assigned a value at the begining, then
        on each next cycle updated in some way, and exited when a condition
        depending on that variable evaluates to false. This function yields what
        the value would be at each iteration of the for loop.
    
        Inputs:
            start: the initial yielded value
            test_func: called on the previous yielded value; if false, the
                       the generator raises StopIteration and the loop exits.
            cycle_func: called on the previous yielded value, retuns the next
                        yielded value
        Yields:
            var: the value of the loop variable
    
        An example:
    
        for x in cfor(0.0, lambda x: x <= 3.0, lambda x: x + 1.0):
            print x    # Obviously, print(x) for Python 3
    
        prints out
    
        0.0
        1.0
        2.0
        3.0
    
        """
        var = start
        while test_func(var):
            yield var
            var = cycle_func(var)
    

    【讨论】:

      猜你喜欢
      • 2015-03-14
      • 2014-09-01
      • 1970-01-01
      • 2012-01-27
      • 2020-09-21
      • 2022-01-12
      • 2013-05-21
      • 1970-01-01
      • 2016-07-05
      相关资源
      最近更新 更多