简体   繁体   English

关于迭代我做错了什么

[英]What am I doing wrong regarding iteration

I want to print out all the odd numbers given in the call: o = Odds(10) , the output should be 1, 3, 5, 7, 9 but I'm doing something wrong in the commented area, it should be relatively simple but I can't see it. 我想打印出呼叫中给定的所有奇数: o = Odds(10) ,输出应为1, 3, 5, 7, 9但我在注释区域做错了,它应该相对很简单,但我看不到。

class Odds:
    def __init__(self, arg):
        self.num = arg

    def __iter__(self):
        return OddsIterator(self.num)

class OddsIterator:
    def __init__(self, arg):
        self.high = arg
        self.low = 1

    def __next__(self):
        if self.low <= self.high:
            if (self.low % 2) == 0: #somethings wrong around here
                self.low += 1 
            else:
                self.low += 1
                return self.low - 1
        raise StopIteration

Your if branch doesn't return anything , so you always reach raise StopIteration at that point. 您的if分支不会返回任何内容 ,因此您始终raise StopIteration在此时达到raise StopIteration Say low is 2 and high is 10: 假设low为2, high为10:

if self.low <= self.high:  # true, 2 <= 10
    if (self.low % 2) == 0:  # true, 2 is even
        self.low += 1 
    # else branch is skipped, so we come to the next line
raise StopIteration  # iterator ends

You need to create larger steps in __next__ , because that method always returns something. 您需要在__next__创建更大的步骤,因为该方法总是返回某些内容。 Instead of not returning when a number is even, you need to return the next number in the sequence, always, so increment self.low by 2 each time, and the first time make sure you start with an odd number: 您需要始终返回序列中的下一个数字,而不是在偶数时不返回,因此每次将self.low递增2,并且第一次确保以奇数开头:

def __next__(self):
    if self.low > self.high:
        raise StopIteration
    if self.low % 2 == 0:
        self.low += 1  # ensure we get an odd number first
    retval = self.low
    self.low += 2
    return retval

I inverted testing for the StopIteration condition here to make it clearer that the function always returns something when there is still a value to return from the iterable. 我在这里反转了StopIteration条件的测试,以更清楚地表明,当仍有可迭代对象返回的值时,该函数总是返回某些内容。

Just to re-iterate, __next__ always returns something, you can't expect it to not return something, so it'll at the very least return None . 仅重申一下, __next__ 总是返回某些内容,您不能指望它不返回任何内容,因此它至少会返回None The iterator is not counting . 迭代器没有计数 Python doesn't go lets ask what the result is for 1, then for 2, then for 3 . Python不走了, 让我们问一下1,2,3的结果是什么 Python simply asks what the next value in the sequence of odd numbers is . Python只是问奇数序列中下一个值是什么 After 1, comes 3, but Python doesn't know that, your code needs to produce that . 1之后是3,但是Python不知道, 您的代码需要产生那个

Your specific problem is that the first even number will fall through to the StopIteration line, rendering your sequence rather short: { 1 } . 您的特定问题是,第一个偶数将落入StopIteration行,从而使序列变得很短: { 1 }

It seems to me that generating all the odd numbers should be substantially easier. 在我看来,生成所有奇数应该实质上更容易。 Start with -1 then, on every call: -1开始,然后在每个通话中:

  • add two. 加两个。
  • if it's too high, stop. 如果太高,停下来。
  • otherwise return the current value. 否则返回当前值。

That can be achieved with: 可以通过以下方法实现:

class Odds:
    def __init__(self, arg):
        self.num = arg

    def __iter__(self):
        return OddsIterator(self.num)

class OddsIterator:
    def __init__(self, arg):
        self.high = arg
        self.curr = -1

    def __next__(self):
        self.curr += 2
        if self.curr > self.high:
            raise StopIteration
        return self.curr

o = Odds(10)
for i in o:
    print (i)

Having said that, I'm not sure I'd implement it the same way you did. 话虽如此,我不确定我会采用与您相同的方式来实现它。 It seems unnecessary to have two separate classes when you can combine them into a single one: 当您可以将它们组合成一个类时,似乎没有必要拥有两个单独的类:

class Odds:
    def __init__(self, end):
        self.curr = -1
        self.lim = end

    def __next__(self):
        self.curr += 2
        if self.curr > self.lim:
            raise StopIteration
        return self.curr

    def __iter__(self):
        return self

o = Odds(10)
for i in o:
    print (i)

In addition, you can make it far more general by providing start and step values as well: 另外,您还可以通过提供start值和step值使它更加通用:

class XFor:
    def __init__(self, start, end, step):
        self.curr = start - step
        self.lim = end
        self.step = step

    def __next__(self):
        self.curr += self.step
        if self.curr > self.lim:
            raise StopIteration
        return self.curr

    def __iter__(self):
        return self

o = XFor(1,10,2)
for i in o:
    print (i)

Although it's then encroaching dangerously on what range() does so I'd just use that. 尽管它然后危险地侵犯了range()功能,所以我只用它。 Unless your intent is self-education, in which case have fun. 除非您的目的是自我教育,否则请自娱自乐。

How about using a simple generator for this purpose, unless you need the Odds class for other purposes - 除非您需要Odds类用于其他目的,否则如何为此目的使用简单的生成器-

def odds(num):
    for i in range(1, num + 1):
        if i % 2 != 0:
            yield i

print(list(odds(11)))

If you do want to use class Odds for specific reason - 如果您确实出于特定原因想要使用类别Odds -

class Odds:

    def __init__(self, num):
        self.high = num

    def __iter__(self):
        return odds(self.high)

print(list(Odds(10))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM