Python中迭代之间状态可变的列表理解

Python中迭代之间状态可变的列表理解,python,python-2.7,list-comprehension,Python,Python 2.7,List Comprehension,我有一些东西非常像Python中的列表理解,只是它在迭代之间共享可变状态。有没有办法用列表来理解 def f(x): """ 5-bit LFSR """ return (x >> 1) ^ (0x12*(x&1)) def batch(f, x, n): result = [x] for _ in xrange(1,n): x = f(x) result.append(x) return result

我有一些东西非常像Python中的列表理解,只是它在迭代之间共享可变状态。有没有办法用列表来理解

def f(x):
    """ 5-bit LFSR """
    return (x >> 1) ^ (0x12*(x&1))

def batch(f, x, n):
    result = [x]
    for _ in xrange(1,n):
        x = f(x)
        result.append(x)
    return result

batch(f, 1, 5)
返回
[1,18,9,22,11]
。这里重要的是
batch
函数,而不是
f(x)
,这里只是一个简单的例子来说明这个问题

或者,我可以使用生成器实现:

def batch(f, x, n):
    yield x
    for _ in xrange(1,n):
        x = f(x)
        yield x

list(batch(f, 1, 5))
但闻起来有点难闻。我要找的是这样的东西

batch = [??? for _ in xrange(n)]
batch = [??? for _ in xrange(n)]

不。故意不。最终他们加入了
itertools.acculate
,这是最接近官方推荐的以函数方式实现重复关系的方法,但在2.7中并不存在。如果需要,您可以从中复制“大致相当于”Python实现。

您可以在一行中执行此操作,例如使用
reduce
(或Python 3中的
functools.reduce
):

但这不仅丑陋,而且效率低下,因为它会在每次迭代中创建一个新列表。或者以与Stefan方法类似的方式,不创建中间列表:

>>> functools.reduce(lambda lst, _: lst.append(f(lst[-1])) or lst, range(1, n), [x])
[1, 18, 9, 22, 11]
或者,正如在另一个答案中已经暗示的那样,您可以使用
itertools.acculate
,这要好得多,但仍然有点误用,因为它实际上需要一个二进制函数,而在这里,除了第一个值外,我们既不使用第二个参数,也不使用传递到函数中的实际iterable

>>> list(itertools.accumulate([x] * n, lambda y, _: f(y)))
[1, 18, 9, 22, 11]
有没有办法用列表来理解

def f(x):
    """ 5-bit LFSR """
    return (x >> 1) ^ (0x12*(x&1))

def batch(f, x, n):
    result = [x]
    for _ in xrange(1,n):
        x = f(x)
        result.append(x)
    return result

batch(f, 1, 5)
我要找的是这样的东西

batch = [??? for _ in xrange(n)]
batch = [??? for _ in xrange(n)]
当然,没问题:

>>> x = 1
>>> n = 5
>>> [prev.append(f(prev[0])) or prev.pop(0) for prev in [[x]] for _ in xrange(n)]
[1, 18, 9, 22, 11]

注意:这是个坏主意。(我这么做几乎只是因为用户2357112说没有办法)如果我能理解的话,这闻起来有点像那些讨厌的Haskell单子中的一个会有用。“除了它在迭代之间共享可变状态。有没有任何方法可以通过列表理解来实现它”可能有一些黑客的方法,但是如果它涉及到变异状态,那么它可能不应该是一个列表理解。同样,“在迭代之间共享可变状态”听起来不像Haskell中的任何东西。不,但是有状态的monads做了。你可以使用<代码>从<代码>中获得的收益来定义递归生成器。天哪,这是鬼鬼祟祟的。虽然这可能是最干净的,我见过的列表理解中状态变量的最佳封装形式(至少在Python3上,状态变量没有泄漏到周围的范围中),我没有发布这样的内容仍然有一个原因:这种代码的每一个实例都在堆栈溢出上,获得了更新投票,增加了人们认为这类事情是个好主意并在代码中实际使用它的风险。@user2357112现在更好了吗?:-)@juanpa.arrivillaga刚刚想出了另一个简洁的方法,它只是没有结尾处带有
xrange
的所需格式:
[q.append(f(x))或x代表q in[[x]]代表x in q if len(q)有点晚了,但是有没有人能知道为什么使用这样的代码会是不好的做法?我考虑使用<代码>迭代器。累积< /COD>这是丑陋的,递归关系被明确地列为示例代码中的用例。@斯蒂芬波奇曼好点,固定的,但这使得它更丑。如果你遵循文档,你会使用
repeat(x,n)
。既然你愿意创建一个列表,你可以简单地使用
[x]*n
。对于
reduce
你也可以使用
lst.\uu iadd_uf(lst[-1])
,尽管我更喜欢
append
+
或lst
(尽管它长了三个字符!:-)哈,怎么样:
reduce(lambda lst,:lst.append(f(lst[-1])或lst,[[x]]*n)
。我真的笑了这一个…使用常见的
[[x]]*n
2D列表得到了…但这里没问题,因为重复的引用被忽略了…我认为这很漂亮。