【问题标题】:Where best to put the generator.close()?最好将 generator.close() 放在哪里?
【发布时间】:2016-01-07 16:06:37
【问题描述】:

我今天早上构建了这个类,它工作得很好而且很紧凑,但是因为每次我担心我会在内存中留下一堆东西时,它都会调用一个新的生成器来工作。我很想在最后的 yield 语句之后立即执行此操作。看起来会干净一些。

class Enter:
    def __init__(self,Entries, container=[], keyName = "Key", valueName = "Value"):
        self.Dict = {}
        self.Entries = Entries
        self.container = container
        self.keyName = keyName
        self.valueName = valueName

    def gen(self,dis):
            print(dis)
            yield input("Entry: ")

    def enter(self):
        for ea in range(self.Entries):
            print("\nPlease input a", self.keyName, "then a", self.valueName)
            x = next(self.gen("\nEnter a " + self.keyName + ":"))
            y = next(self.gen("\nEnter a " + self.valueName + ":"))
            self.Dict.update({x:y})
        retrun self.Dict

    def enterList(self):
        lst = []
        for ea in range(self.Entries):
            print("\nSome Message")
            x = next(self.gen("\nEnter: "))
            lst.append(x)
        if self.container == ():
            lst = tuple(lst)         
        return lst

Dictionary = Enter(Entries = 2, keyName = "First Name", valueName="LastName").enter()

print(Dictionary)

output = Enter(Entries = 3, container= () ).enterList()

print(output)

【问题讨论】:

  • 使用生成器有点奇怪。为什么没有常规的函数调用和返回语句?
  • 像每个对象一样,一旦没有指向它的引用,生成器就会被垃圾回收器释放。由于您只在每个生成器上调用next(),因此您没有引用,因此它们不会无限期地留在内存中。他们最终会被释放。不过,您正在为这些生成器节省大量样板内存。如果您只有一个值,请不要使用生成器。
  • 多少样板?我又做了一些工作,将它重命名为 Entry,现在它只返回一个列表、元组或字典,只需要一个小方法。我只向 def init 添加了一个参数。我是新手,所以我还没有看到其他任何东西可以用这么少的代码做到这一点。我还是想取出indiv。手动生成生成器,但如果涉及的样板规模太大和/或有明显更好的东西,我想澄清一下。

标签: python python-3.x generator


【解决方案1】:

每个生成器对象都有很多开销,仅用于管理状态和所有内容。除非出于正确的原因需要生成器,否则应避免使用它们。在您的情况下,您只生产一个项目,您的生成器无法生产更多,并且该值可以立即免费获得。所以在这里使用生成器是完全错误的。

相反,您可以像这样高效地编写 enter 函数,而无需任何开销:

def enter(self):
    for ea in range(self.Entries):
        print("\nPlease input a", self.keyName, "then a", self.valueName)
        x = input("\nEnter a " + self.keyName + ":")
        y = input("\nEnter a " + self.valueName + ":")
        self.Dict[x] = y
    return self.Dict

【讨论】:

  • 更一般地说,“除非您出于正当理由需要语言功能,否则您应该避免使用它”
  • 该代码有助于我理解,谢谢。我仍然不清楚规模的差异。我确实了解生成器通常确实涉及更多开销。多少以及是否重要仍然是我想明确的问题。
  • @戳。我发现您的评论不恰当,希望您不要对我的帖子发表评论,这样我就不必花时间这样做了。
  • @user3163030 非常抱歉花费我的时间回答您的问题。
【解决方案2】:

从您的代码风格来看,我会说您是一名 Java 程序员,正在学习 Python。

欢迎使用 python,你选择了正确的版本 :)

关于 python 的一个非常酷的事情是您很少需要担心内存泄漏。 python 使用引用计数来确保不可访问的对象被垃圾回收。

x = next(self.gen("\nEnter a " + self.keyName + ":")) 发生了 3 件重要的事情:

  • gen(self,dis) 被调用,返回一个生成器对象
  • next(gen) 将生成器移动到下一个 yield 语句 yield input("Entry: ") 并返回产生的值。 请注意,它不会导致生成器退出,因为它尚未到达返回或函数结束。再次调用 next(gen) 会这样做(并提高 StopIteration
  • 返回值绑定到x,而生成器对象变得不可访问(它没有绑定到它的变量)。生成器对象因此被 python 垃圾收集器删除。

这就是说,我同意其他人的说法,即生成器不适合此应用程序。不是因为开销 - 我非常怀疑生成器实例化会在大多数应用程序中导致任何明显的开销 - 而是因为应用程序非常简单。

此外,如果简化为代码将更易于阅读

def gen(self,dis):
        print(dis)
        return input("Entry: ")

def enter(self):
    for ea in range(self.Entries):
        print("\nPlease input a", self.keyName, "then a", self.valueName)
        x = self.gen("\nEnter a " + self.keyName + ":")
        y = self.gen("\nEnter a " + self.valueName + ":")
        self.Dict.update({x:y})
    retrun self.Dict

一般python最好写idiomatically

【讨论】:

  • 太好了,谢谢!我一般是编程新手。今天早上我碰巧把输入功能放在了生成器上,发现它很整洁。我没有意识到我可以退货。我确实读了很多书,但也花了很多时间,“用棍子戳它”,看看会发生什么。我仍然听说过关于生成器的开销,但我不知道它的相对规模。我确实阅读了文档,它提到需要关闭,所以这个问题。感谢视频链接。最重要的是,代码中的答案很容易上手。
猜你喜欢
  • 2015-09-19
  • 1970-01-01
  • 2011-11-21
  • 2011-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
  • 2023-03-25
相关资源
最近更新 更多