传递给发电机的复制列表反映了对原始的更改

发布于 2025-02-08 18:36:26 字数 928 浏览 2 评论 0原文

在回答

from typing import List, Iterable


class Name:
    def __init__(self, name: str):
        self.name = name


def generator(lst: List[Name]) -> Iterable[str]:
    lst_copy = lst.copy()
    for obj in lst_copy:
        yield obj.name

时进行的,对原始列表的更改仍然反映:

lst = [Name("Tom"), Name("Tommy")]
gen = generator(lst)
lst[0] = Name("Andrea")
for name in gen:
    print(name)

输出:

Andrea
Tommy

简单地返回发电机表达式按预期工作:

def generator(lst: List[Name]) -> Iterable[str]:
    return (obj.name for obj in lst.copy())

输出:

Tom
Tommy

为什么第一个生成器函数在第一个生成器函数中lst.copy()为什么不按预期工作?

In answering this question, I stumbled across some unexpected behavior:

from typing import List, Iterable


class Name:
    def __init__(self, name: str):
        self.name = name


def generator(lst: List[Name]) -> Iterable[str]:
    lst_copy = lst.copy()
    for obj in lst_copy:
        yield obj.name

When modifying the list that is passed to the generator, even though a copy is made, changes to the original list are still reflected:

lst = [Name("Tom"), Name("Tommy")]
gen = generator(lst)
lst[0] = Name("Andrea")
for name in gen:
    print(name)

Output:

Andrea
Tommy

Simply returning a generator expression works as expected:

def generator(lst: List[Name]) -> Iterable[str]:
    return (obj.name for obj in lst.copy())

Output:

Tom
Tommy

Why doesn't the lst.copy() in the first generator function work as expected?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

╰◇生如夏花灿烂 2025-02-15 18:36:26

我认为,最好通过增加一些额外的打印语句来理解这种行为:

def generator(lst: List[Name]) -> Iterable[str]:
    print("Creating list copy...")
    lst_copy = lst.copy()
    print("Created list copy!")
    for obj in lst_copy:
        yield obj.name
        
lst = [Name("Tom"), Name("Tommy")]
print("Starting assignment...")
gen = generator(lst)
print("Assignment complete!")

print("Modifying list...")
lst[0] = Name("Andrea")
print("Modification complete!")

for name in gen:
    print(name)

请注意,副本不会在分配时间发生 - 在之后,列表被修改了!

Starting assignment...
Assignment complete!
Modifying list...
Modification complete!
Creating list copy...
Created list copy!
Andrea
Tommy

在发电机的身体中执行,直到循环尝试提取元素之前。由于这种提取尝试是在列表突变之后发生的,因此突变反映在发电机的结果中。

I think the behavior is best understood with the addition of some extra print statements:

def generator(lst: List[Name]) -> Iterable[str]:
    print("Creating list copy...")
    lst_copy = lst.copy()
    print("Created list copy!")
    for obj in lst_copy:
        yield obj.name
        
lst = [Name("Tom"), Name("Tommy")]
print("Starting assignment...")
gen = generator(lst)
print("Assignment complete!")

print("Modifying list...")
lst[0] = Name("Andrea")
print("Modification complete!")

for name in gen:
    print(name)

Notice that the copy does not happen at assignment time -- it happens after the list is modified!

Starting assignment...
Assignment complete!
Modifying list...
Modification complete!
Creating list copy...
Created list copy!
Andrea
Tommy

Nothing in the generator's body is executed until the for loop attempts to extract an element. Since this extraction attempt occurs after the list is mutated, the mutation is reflected in the results from the generator.

青萝楚歌 2025-02-15 18:36:26

在请求第一项之前,发电机的主体不会开始执行。因此,在此代码中:

def generator(lst: List[Name]) -> Iterable[str]:
    lst_copy = lst.copy()
    for obj in lst_copy:
        yield obj.name

lst = [Name("Tom"), Name("Tommy")]
gen = generator(lst)
lst[0] = Name("Andrea")
for name in gen:
    print(name)

...首先,执行lst [0] =名称(“ Andrea”)。然后,您有一个循环的,它开始执行发电机。那是执行lst_copy = lst.copy(),这为时已晚,无法在lst [0] sistigment之前进入。

发电机表达式起作用,因为在创建迭代器之前,必须评估发电机(lst.copy(),最后一部分)的迭代部分。

The body of a generator does not start executing until the first item is requested. So in this code:

def generator(lst: List[Name]) -> Iterable[str]:
    lst_copy = lst.copy()
    for obj in lst_copy:
        yield obj.name

lst = [Name("Tom"), Name("Tommy")]
gen = generator(lst)
lst[0] = Name("Andrea")
for name in gen:
    print(name)

... First, the lst[0] = Name("Andrea") is executed. Then, you have a for loop, which starts executing the generator. That's when lst_copy = lst.copy() is executed, which is too late to get in before the lst[0] assignment.

The generator expression works, because the iterable portion of the generator (lst.copy(), the last part) must be evaluated before creating the iterator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文