[英]Simulating C-style for loops in python
(even the title of this is going to cause flames, I realize) (即使这个标题会导致火焰,我意识到)
Python made the deliberate design choice to have the for
loop use explicit iterables, with the benefit of considerably simplified code in most cases. Python做出了深思熟虑的设计选择,让
for
循环使用显式迭代,在大多数情况下,代码大大简化了。
However, sometimes it is quite a pain to construct an iterable if your test case and update function are complicated, and so I find myself writing the following while loops: 但是,如果你的测试用例和更新函数很复杂,有时候构造一个iterable会很麻烦,所以我发现自己编写了以下while循环:
val = START_VAL
while <awkward/complicated test case>:
# do stuff
...
val = <awkward/complicated update>
The problem with this is that the update is at the bottom of the while
block, meaning that if I want to have a continue
embedded somewhere in it I have to: 这个问题是更新位于
while
块的底部,这意味着如果我想在其中嵌入一个continue
,我必须:
use duplicate code for the complicated/awkard update, AND 使用重复代码进行复杂/ awkard更新,AND
run the risk of forgetting it and having my code infinite loop 冒着忘记它并让我的代码无限循环的风险
I could go the route of hand-rolling a complicated iterator: 我可以去手动滚动一个复杂的迭代器:
def complicated_iterator(val):
while <awkward/complicated test case>:
yeild val
val = <awkward/complicated update>
for val in complicated_iterator(start_val):
if <random check>:
continue # no issues here
# do stuff
This strikes me as waaaaay too verbose and complicated. 这让我感到震惊,因为waaaaay太冗长和复杂。 Do folks in stack overflow have a simpler suggestion?
堆栈溢出中的人有一个更简单的建议吗?
Response to comments: 回复评论:
@Glenn Maynard: Yes, I dismissed the answer. @Glenn Maynard:是的,我驳回了答案。 It's bad to write five lines if there is a way to do it in one... especially in a case that comes up all the time (looping being a common feature of Turing-complete programs).
如果有一种方法可以在一个方法中编写五行,那就太糟糕了......特别是在一直出现的情况下(循环是图灵完成程序的一个共同特征)。
For the folks looking for a concrete example: let's say I'm working with a custom date library. 对于寻找具体示例的人:假设我正在使用自定义日期库。 My question would then be, how would you express this in python:
那么我的问题是,你将如何在python中表达这一点:
for (date = start; date < end; date = calendar.next_quarter_end(date)):
if another_calendar.is_holiday(date):
continue
# ... do stuff...
This is the best I can come up with: 这是我能想到的最好的:
def cfor(first,test,update):
while test(first):
yield first
first = update(first)
def example(blah):
print "do some stuff"
for i in cfor(0,lambda i:i<blah,lambda i:i+1):
print i
print "done"
I wish python had a syntax for closured expressions. 我希望python有一个闭包表达式的语法。
Edit: Also, note that you only have to define cfor once (as opposed to your complicated_iterator
function). 编辑:另外,请注意,您只需要定义一次cfor(而不是您的
complicated_iterator
函数)。
I'm a little confused: you have a complicated while expression, and a complicated next expression, but they fit nicely into a C for loop? 我有点困惑:你有一个复杂的while表达式,一个复杂的下一个表达式,但它们很适合C for循环? That doesn't make sense to me.
这对我来说没有意义。
I recommend the custom iterator approach. 我推荐自定义迭代器方法。 You will likely find other uses for the iterator, and encapsulating the iteration is good practice anyway.
您可能会发现迭代器的其他用途,无论如何封装迭代都是很好的做法。
UPDATE: Using your example, I would definitely make a custom iterator. 更新:使用您的示例,我肯定会创建一个自定义迭代器。 It seems perfectly natural to me that a calendar would be able to generate a series of quarterly dates:
对我来说,日历能够产生一系列季度日期似乎是很自然的:
class Calendar:
# ...
def quarters(self, start, end):
"""Generate the quarter-start dates between `start` and `end`."""
date = start
while date < end:
yield date
date = self.next_quarter_end(date)
for date in calendar.quarters(start, end):
if another_calendar.is_holiday(date):
continue
# ... do stuff...
This seems like a wonderful abstraction for your calendar class to provide, and I bet you'll use it more than once. 这似乎是您的日历类提供的一个很棒的抽象,我打赌你会不止一次地使用它。
What about: 关于什么:
date = start
while date < end:
if not another_calendar.is_holiday(date):
# ... do stuff...
date = calendar.next_quarter_end(date)
But if you use that particular construct often, you're better off defining the generator once and re-using it as you did in your question. 但是如果你经常使用那个特定的构造,你最好定义一次生成器并像你在问题中那样重新使用它。
(The fact is, since they're different languages, you can't possibly have every construct in C map to a more compact construct in Python. It's like claiming to have a compression algorithm that works equally well on all random inputs.) (事实是,由于它们是不同的语言,你不可能将C映射中的每个构造都用于Python中更紧凑的构造。它就像声称有一个压缩算法在所有随机输入上同样有效。)
You could use a try/finally clause to execute the update: 您可以使用try / finally子句来执行更新:
val = START_VAL
while <awkward/complicated test case>:
try:
# do stuff
continue
finally:
val = <awkward/complicated update>
Caveat: this will also execute the update statement if you do a break
. 警告:如果你
break
这也会执行更新语句。
I often do 我经常这样做
while True:
val = <awkward/complicated update>
if not val:
break
etc.
Heh: 嘿:
def forre(a,i,c,top,increment,run):
increment = increment.replace("++","+=1").replace("--","-=1").replace("; ","")
while i != top:
try: exec(run)
except: print "error: "; print run
try: exec(increment)
except: print "error: "; print increment
forre("int i=",0,"; i<",6,"; i++",
"print i"
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.