带生成器的嵌套列表理解

提图斯

我在 python 3.7 上有一些奇怪的行为,其中包含涉及生成器的嵌套列表理解。

这有效:

i = range(20)
n = [1, 2, 3]
result = [min(x + y for x in i) for y in n]

不工作,如果i是发电机:

i = (p for p in range(20))
n = [1, 2, 3]
result = [min(x + y for x in i) for y in n]

这引发了一个 ValueError: min() arg is an empty sequence

现在,即使生成器ilist包裹,仍然会产生相同的错误:

i = (p for p in range(20))
n = [1, 2, 3]
result = [min(x + y for x in list(i)) for y in n]

这是一个python错误还是预期的行为?如果这是预期的行为,你能解释为什么这不起作用吗?

金光镇

i = range(20)range(20)要产生发电机的承诺。whilei = (p for p in range(20))已经是一个生成器。

现在将您的列表表达式写为:

for y in [1, 2, 3]:
    print(min(x + y for x in i))
## 1
## ...
## ValueError: min() arg is an empty sequence 

你得到一个1打印,但是(生成器在第一次调用中用完了)然后你进入下一轮 aValueError: min() arg is an empty sequence因为生成器i已经在第一个 for 循环调用中消耗了 y 为 1。而 ifi定义为range(20),每次在for x in i被调用时,生成器一次又一次地重新创建。

您可以range(20)通过以下方式模仿正在做的事情:

def gen():
    return (p for p in range(20))

for y in [1, 2, 3]:
    print(min(x + y for x in gen())) 
    # range() like gen() is a promise to generate the generator
## 1
## 2
## 3

现在每次都会重新创建生成器。

但事实上,range更酷,如果你这样做:

i = range(20)

for y in [1, 2, 3]:
    print(min(x + y for x in i))
## 1
## 2
## 3

i该innerst发生器内不是一个函数调用。但尽管如此,它会创建 - 在评估时 - 一个新的生成器 - 至少在用作 for 循环中的可迭代对象时。

这实际上是在 Python 中使用类并通过定义__iter__()方法来实现的。它定义了交互器中的行为 - 这里特别是一种懒惰的行为。

为了模仿这种行为,我们可以生成一个惰性生成器 ( lazy_gen)。

class lazy_gen:
    def __init__(self):
        pass

    def __iter__(self):    # everytime when used as an iterator
        return self.gen()  # recreate the generator # real lazy behavior

    def gen(self):
        return (p for p in range(20))

我们可以像这样使用:

i = lazy_gen()

for y in [1, 2, 3]:
    print(min(x + y for x in i))
## 1
## 2
## 3

所以这更好地反映了range()行为。

其他语言(函数式语言),如Lisp家族语言(common-lisp、Racket、Scheme、Clojure)R,或者Haskell对评估有更好的控制 - 因此对惰性评估和承诺。但是在 Python 中,对于这样的实现和细粒度控制,必须求助于 OOP。

我的范围函数和类

最后,我弄清楚了范围函数必须是如何粗略地实现的。(为了好玩,虽然我可以在我知道的 Python 源代码中查找它 - 但有时推理很有趣。)

class Myrange:
    def __init__(self, start, end, step):
        self.start = start
        self.end = end
        self.step = step

    def __iter__(self):
        return self.generate_range()

    def generate_range(self):
        x = self.start - self.step
        while x + self.step < self.end:
            x = x + self.step
            yield x

    def __repr__(self):
        return "myrange({}, {})".format(self.start, self.end)



def myrange(start=None, end=None, step=1):
    if start is None and end is None:
        raise "Please provide at least one number for the range-limits."
    elif start is not None and end is None:
        _start = 0
        _end = start
    elif start is not None and end is not None:
        _start = start
        _end = end
    else:
        _start = 0
        _end = end
    _step = step
    return Myrange(_start, _end, _step)

可以像使用 range 函数一样使用它。

i = myrange(20)

n = [1, 2, 3]
result = [min(x + y for x in i) for y in n]

result 
## [1, 2, 3]

i 
## myrange(0, 20)  # representation of a Myrange object.

myrange(20)
## myrange(0, 20)

list(myrange(3, 10))
## [3, 4, 5, 6, 7, 8, 9]

list(myrange(0, 10))
## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

list(myrange(10))
## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

list(myrange(0, 10, 2))
## [0, 2, 4, 6, 8]

list(myrange(3, 10, 2))
## [3, 5, 7, 9]

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

生成器列表理解

来自分类Dev

生成器vs列表理解

来自分类Dev

Python生成器与列表理解冲突

来自分类Dev

Python列表理解与生成器

来自分类Dev

python中嵌套列表理解和嵌套生成器表达式的顺序

来自分类Dev

生成器理解和列表理解的迭代方式不同

来自分类Dev

具有递归和列表理解的素数生成器

来自分类Dev

在列表理解生成器中扩展元组

来自分类常见问题

列表理解和生成器表达式的收益

来自分类Dev

Python中的生成器与列表理解性能

来自分类Dev

连接字符串。生成器或列表理解?

来自分类Dev

具有递归和列表理解的素数生成器

来自分类Dev

列表理解中的生成器出现问题

来自分类Dev

如何嵌套生成器

来自分类Dev

为什么Python 2中的生成器表达式和dict / set理解使用与列表理解不同的嵌套函数?

来自分类Dev

为什么Python 2中的生成器表达式和dict / set理解使用与列表理解不同的嵌套函数?

来自分类Dev

从生成器创建列表

来自分类Dev

列表生成器混乱

来自分类Dev

带循环javascript的报价生成器

来自分类Dev

使用生成器理解与列表理解从文件中读取行

来自分类Dev

理解 Python 中的生成器函数

来自分类Dev

生成器中嵌套的异常行为

来自分类Dev

生成器中嵌套的异常行为

来自分类Dev

生成器中嵌套的异常行为

来自分类Dev

生成器中嵌套的异常行为

来自分类Dev

使用生成器而不是嵌套循环

来自分类Dev

转置嵌套生成器

来自分类Dev

嵌套生成器未正确触发

来自分类Dev

具有连接功能的列表vs生成器理解速度