Python itertools 计数器的当前值是多少

What is the current value of a Python itertools counter

Python (2.7.9) 中的 itertools.count 计数器对于线程安全计数非常方便。我怎样才能得到计数器的当前值?

每次您调用 next():

时,计数器都会递增 returns 最后一个值
import itertools
x = itertools.count()
print x.next()  # 0
print x.next()  # 1
print x.next()  # 2

到目前为止,还不错。

我找不到不调用 next() 来获取计数器当前值的方法,调用 next() 会产生增加计数器或使用 repr() 函数的不良副作用.

接上文:

print repr(x)  # "count(3)"

所以你可以解析 repr() 的输出。像

current_value = int(repr(x)[6:-1])

可以解决问题,但真的很难看。

有没有更直接获取计数器当前值的方法?

根据 documentation,无法访问函数的当前值。 itertools.count() 是来自 itertools 模块的 generator 方法。因此,通常的做法是简单地 将生成器的当前值赋值 给一个变量。

简单存储下一次调用的结果:

current_value = x.next()

或(Python版本≥2.6的内置python方法)

current_value = next(x)

如果您想要添加一些语法糖,您可以制作一个包装函数或实用装饰器 class,但赋值是标准的。

It是个生成器,想怎么弄都不容易

如果您想在多个地方使用它的值,我建议您通过 .next() 获取一个值并将其存储在一个变量中。如果您担心计数器可能会在这两次使用之间递增,您需要将它们都放在 critical section 中。

如果您不想用这些检查生成的额外“+1”污染该计数器,您可以再使用一个计数器来对检查进行计数(也将其放在关键部分)。从前者中减去后者会得到你所需要的。

还有,你真的确定线程安全吗?文档页面没有关于线程的内容。

使用来源,卢克!

根据module implementation,这是不可能的。

typedef struct {
    PyObject_HEAD
    Py_ssize_t cnt;
    PyObject *long_cnt;
    PyObject *long_step;
} countobject;

当前状态存储在 cntlong_cnt 成员中,它们都没有暴露在对象 API 中。正如您所建议的,唯一可以检索它的地方是对象 __repr__

请注意,在解析字符串时,您必须考虑非奇异增量情况。 repr(itertools.count(123, 4)) 等于 'count(123, 4)' - 您所建议的逻辑在这种情况下会失败。

运行 今天也是一样。这是我最终得到的结果:

class alt_count:

    def __init__(self, start=0, step=1):
        self.current = start - step
        self.step = step

    def __next__(self):
        self.current = self.current + self.step
        return self.current

应该给你几乎所有的 itertools.count 功能加上 current 属性.

i = alt_count()
print(next(i))  # 0
print(next(i))  # 1
print(i.current)  # 1

如果不需要当前值,我发现使用这个简单的 closure also works. Note that nonlocal 仅适用于 Python 版本 > 3。

def alt_next_maker(start=0, step=1):
    res = start - step

    def alt_next():
        nonlocal res, step
        res = res + step
        return res

    return alt_next

如果您不想使用 itertools 模块,可以用作简单的替代方法。

alt_next = alt_next_maker()
print(alt_next())  # 0
print(alt_next())  # 1

文档还提到了以下等效内容:

def count(start=0, step=1):
    # count(10) --> 10 11 12 13 14 ...
    # count(2.5, 0.5) -> 2.5 3.0 3.5 ...
    n = start
    while True:
        yield n
        n += step

另一种在不推进迭代器的情况下获取下一个值的技巧是滥用复制协议:

>>> c = itertools.count()
>>> c.__reduce__()[1][0]
0
>>> next(c)
0
>>> c.__reduce__()[1][0]
1

或者直接从对象副本中获取:

>>> from copy import copy
>>> next(copy(c))
1