首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实现xrange

实现xrange
EN

Code Review用户
提问于 2015-10-15 07:37:47
回答 3查看 1.2K关注 0票数 7

我想学习IterableIterators,因此我想把我的手弄脏,而不是读理论而忘记它。

我很好奇如何提高代码的可读性和错误处理。我还想练习并包括测试用例。

代码语言:javascript
复制
class foo_range(object):
    """ Custom range iterator which mimics native xrange. """

    def __init__(self, start, stop, step=1):
        try:
            self.current = int(start)
            self.limit = int(stop)
            self.step = int(step)
        except ValueError:
            raise
        if step == 0:
            raise ValueError("Step can't be 0")

    def __iter__(self):
        return self

    def next(self):
        if self.step > 0 and self.current >= self.limit:
            raise StopIteration()
        if self.step < 0 and self.current <= self.limit:
            raise StopIteration()
        oldvalue = self.current
        self.current += self.step
        return oldvalue



import unittest

class TestXRange(unittest.TestCase):

  def test_invalid_range(self):
    with self.assertRaises(ValueError) as ve:
      foo_range(0, 5, 0)

  def test_valid_range(self):
    expected = [0, 1, 2]
    actual = []
    for _ in foo_range(0, 3):
        actual.append(_)
    self.assertEqual(actual, expected)

    expected = [0, -1, -2, -3]
    actual = []
    for _ in foo_range(0, -4, -1):
        actual.append(_)
    self.assertEqual(actual, expected)

    expected = []
    actual = []
    for _ in foo_range(0, 5, -1):
        actual.append(_)
    self.assertEqual(actual, expected)

    expected = []
    actual = []
    for _ in foo_range(0, -5, 1):
        actual.append(_)
    self.assertEqual(actual, expected)


if __name__ == '__main__':
    unittest.main()
EN

回答 3

Code Review用户

回答已采纳

发布于 2015-10-15 09:49:15

请注意,xrange是可迭代的。可以在单个xrange实例上多次迭代。相反,foo_range是一个迭代器,因此只能迭代一次。

代码语言:javascript
复制
>>> xr = xrange(5)
>>> list(xr)
[0, 1, 2, 3, 4]
>>> list(xr)
[0, 1, 2, 3, 4]
>>> fr = foo_range(0,5)
>>> list(fr)
[0, 1, 2, 3, 4]
>>> list(fr)
[]

要解决这个问题,__iter__应该返回一个新的迭代器对象。实现这一目标的一个简单方法是使__iter__成为值的生成器。或者,将类重命名为foo_range_iterator,并添加一个新的foo_range类,其__iter__返回一个新的foo_range_iterator实例。

票数 5
EN

Code Review用户

发布于 2015-10-15 08:32:49

问题

我不知道为何要这样做:

代码语言:javascript
复制
    except ValueError:
        raise

列表理解

您有以下模式:

代码语言:javascript
复制
actual = []
for _ in foo_range(XXX):
    actual.append(_)

在一些地方。

它可以很容易地被以下所取代:

代码语言:javascript
复制
actual = [_ for _ in foo_range(XXX)].

另外,_通常用作抛出值的变量名(不使用的值)。在您的示例中,由于实际使用了该值,因此最好将其命名为(aevali等)。

此外,我认为这相当于:

代码语言:javascript
复制
actual = list(foo_range(XXX))

我让你考虑一下。

单元测试组织

您的def test_valid_range(self):测试测试了多个方面。最好将其分成多个较小的测试。在其他方面,如果出了问题就更容易理解,但它也帮助您思考实际要测试的内容(迭代向前,向后迭代等等)。

建议

尝试使用用yield定义的生成器来实现这一点可能很有趣。

票数 6
EN

Code Review用户

发布于 2015-10-15 14:31:30

缺失特征

所有这些中缺少的一个特性可能是xrange()最常见的用法:

xrange(停止) xrange(开始,停止步进)

你错过了第一个案子!我不能写这样的东西:

代码语言:javascript
复制
for i in foo_range(10):
    # stuff

你应该增加对此的支持。

缺失类型检查

xrange()类型检查它的输入。例如,如果我尝试执行xrange(10.1),它会抛出一个TypeError。由于支持浮点范围的浮点比较的所有问题,您可能希望或不希望添加此内容。

测试

对于步骤的值有0、1和-1的测试。对于类似于5的步骤值,您可能至少应该有一个测试。

停止迭代

这是次要的,但你有:

代码语言:javascript
复制
if self.step > 0 and self.current >= self.limit:
    raise StopIteration()
if self.step < 0 and self.current <= self.limit:
    raise StopIteration()

这些不是独立的检查,这表明第二个至少应该是一个elif。但既然身体是一样的,我建议把它们结合起来:

代码语言:javascript
复制
if (self.step > 0 and self.current >= self.limit or
    self.step < 0 and self.current <= self.limit):
    raise StopIteration()
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/107639

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档