【问题标题】:Circular Range in PythonPython中的循环范围
【发布时间】:2016-12-05 08:48:45
【问题描述】:

如何在 Python 中实现圆形范围对象

例如

令 S 是一个以 2^3 为模的圆形空间(范围 [0, 2^3))。 我想生成一个像这样的范围对象:

crange(3, 7, 2 ** 3) => a range object [3, 4, 5, 6]
crange(7, 3, 2 ** 3) => a range object [7, 0, 1, 2]

我试过这个:

def crange(start, stop, modulo):
    if start > stop:
        return range(start, modulo) or range(stop)
    else:
        return range(start, stop)

但我不能输入 bigint 到 crange 例如crange(8, 2, 2 ** 160).

OverflowError: Python int too large to convert to C ssize_t

【问题讨论】:

  • 你已经尝试了什么?发布它,以便我们提供帮助。 SO 不是代码编写服务
  • 在您给出的示例中,您希望crange(0, 8) 得到什么结果?
  • 有趣的是,您的代码提高了OverflowError,因为评估大range 的真实性显然提高了OverflowError(即使范围本身是可表示的)。这可以说是一个错误。我打开了bugs.python.org/issue28876
  • @sira:它是相关的,但它是一个不同的问题(lrange() 将无济于事,除非它会定义 __bool__ 方法——这很容易,但它会破坏与范围的兼容性( ) 来自 Python 3)。没有 range() 对象会生成 7, 0, 1, 2。具体错误是由于 bool(range()) 被实现为 len(range()) 并且由于实现历史 len() 被限制为 C ssize_t 大小。这是Guido said about it in 2008

标签: python


【解决方案1】:

您可以通过创建自己的生成器来避免使用范围和在内存中存储大量列表:

def crange(start, end, modulo):
    if start > end:
        while start < modulo:
            yield start
            start += 1
        start = 0

    while start < end:
        yield start
        start += 1

print list(crange(3, 7, 2 ** 3))
print list(crange(7, 3, 2 ** 3))
print next(crange(8, 2, 2 ** 160))

此代码输出:

[3, 4, 5, 6]
[7, 0, 1, 2]
8

【讨论】:

  • crange(2, 2 ** 100, 2 ** 160) 占用这么多内存。我该如何解决?
  • 它没有。除了局部变量,生成器不会在内存中存储任何内容。
  • 我明白了。谢谢。
【解决方案2】:

试试这个:

def crange(start, stop, modulo):
    result = []
    index = start
    while index != stop:
        result.append(index)
        index = (index + 1) % modulo
    return result

如果您知道您的列表可能太长,您可以使用生成器来生成必需序列:

def crange(start, stop, modulo):
    index = start
    while index != stop:
        yield index
        index = (index + 1) % modulo

【讨论】:

    【解决方案3】:

    非常感谢大家。

    我实现了我想要的crange(参考@Ni 和@J.F.Sebastian)。

    import math
    
    
    class crange:
        def __init__(self, start, stop, step=None, modulo=None):
            if step == 0:
                raise ValueError('crange() arg 3 must not be zero')
    
            if step is None and modulo is None:
                self.start = 0
                self.stop = start
                self.step = 1
                self.modulo = stop
            else:
                self.start = start
                self.stop = stop
                if modulo is None:
                    self.step = 1
                    self.modulo = step
                else:
                    self.step = step
                    self.modulo = modulo
    
        def __iter__(self):
            n = self.start
            if n > self.stop:
                while n < self.modulo:
                    yield n
                    n += 1
                n = 0
            while n < self.stop:
                yield n
                n += 1
    
        def __contains__(self, n):
            if self.start >= self.stop:
                return self.start <= n < self.modulo or 0 <= n < self.stop
            else:
                return self.start <= n < self.stop
    

    我得到以下输出:

    >>> print(list(crange(start=7, stop=3, modulo=2 ** 4)))
    [7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2]
    >>> print(3 in crange(start=7, stop=3, modulo=2 ** 4))
    False
    >>> print(7 in crange(start=7, stop=3, modulo=2 ** 4))
    True
    >>> print(list(crange(start=3, stop=7, modulo=2 ** 4)))
    [3, 4, 5, 6]
    >>> print(3 in crange(start=3, stop=7, modulo=2 ** 4))
    True
    >>> print(7 in crange(start=3, stop=7, modulo=2 ** 4))
    False
    

    【讨论】:

      猜你喜欢
      • 2022-12-16
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-07
      • 1970-01-01
      相关资源
      最近更新 更多