尝试最终用python中的发电机阻止

发布于 2025-01-24 05:39:27 字数 667 浏览 1 评论 0原文

有人可以向我解释Generator的想法,然后在此代码中尝试以外的

from contextlib import contextmanager
 
@contextmanager
def file_open(path):
    try:
        f_obj = open(path, 'w')
        yield f_obj
    except OSError:
        print("We had an error!")
    finally:
        print('Closing file')
        f_obj.close()
 
 
if __name__ == '__main__':
    with file_open('test.txt') as fobj:
        fobj.write('Testing context managers')

众所周知,无论中的表达式是否正确,都始终执行。代码>。因此,我认为此代码应该这样起作用:如果我们没有例外,我们打开文件,转到发电机,然后我们最终阻止并从功能返回。但是我不了解Generator在此代码中的工作方式。我们只使用了一次,这就是为什么我们无法在文件中写所有文本的原因。但是我认为我的想法是不正确的。为什么?

Can someone explain me the idea of generator and try except in this code:

from contextlib import contextmanager
 
@contextmanager
def file_open(path):
    try:
        f_obj = open(path, 'w')
        yield f_obj
    except OSError:
        print("We had an error!")
    finally:
        print('Closing file')
        f_obj.close()
 
 
if __name__ == '__main__':
    with file_open('test.txt') as fobj:
        fobj.write('Testing context managers')

As I know, finally is always executed regardless of correctness of the expression in try. So in my opinion this code should work like this: if we haven't exceptions, we open file, go to generator and the we go to finally block and return from the function. But I can't understand how generator works in this code. We used it only once and that's why we can't write all the text in the file. But I think my thoughts are incorrect. WHy?

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

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

发布评论

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

评论(1

浊酒尽余欢 2025-01-31 05:39:27

因此,第一,您的实施不正确。即使未能打开,您也会尝试关闭打开的文件对象,这是一个问题。在这种情况下,您需要做的是:

@contextmanager
def file_open(path):
    try:
        f_obj = open(path, 'w')
        try:
            yield f_obj
        finally:
            print('Closing file')
            f_obj.close()         
    except OSError:
        print("We had an error!")

或更简单:

@contextmanager
def file_open(path):
    try:
        with open(path, 'w') as f_obj:
            yield f_obj
            print('Closing file')
    except OSError:
        print("We had an error!")

“一般工作中的发电机如何?”我将您推荐您现有问题关于该主题。 两种情况下天生停顿的事实:

  1. 这种特定情况很复杂,因为使用@contextlib.contextmanager decorator repulposes 生成器生成器在很大程度上无关的目的,使用它们在 请求第一个值)
  2. 在每个tource(请求每个后续值时)上

以实现上下文管理。

contextManager只是滥用此类课程(实际源代码涵盖边缘案例更为复杂):

class contextmanager:
    def __init__(self, gen):
        self.gen = gen  # Receives generator in initial state
    def __enter__(self):
        return next(self.gen)  # Advances to first yield, returning the value it yields
    def __exit__(self, *args):
        if args[0] is not None:
            self.gen.throw(*args)  # Plus some complicated handling to ensure it did the right thing
        else:
            try:
                next(self.gen)      # Check if it yielded more than once
            except StopIteration:
                pass                # Expected to only yield once
            else:
                raise RuntimeError(...)  # Oops, it yielded more than once, that's not supposed to happen

允许生成器的coroutine元素支持一种更简单的方式来编写简单的上下文管理器。

So, one, your implementation is incorrect. You'll try to close the open file object even if it failed to open, which is a problem. What you need to do in this case is:

@contextmanager
def file_open(path):
    try:
        f_obj = open(path, 'w')
        try:
            yield f_obj
        finally:
            print('Closing file')
            f_obj.close()         
    except OSError:
        print("We had an error!")

or more simply:

@contextmanager
def file_open(path):
    try:
        with open(path, 'w') as f_obj:
            yield f_obj
            print('Closing file')
    except OSError:
        print("We had an error!")

To "how do generators in general work?" I'll refer you to the existing question on that topic. This specific case is complicated because using the @contextlib.contextmanager decorator repurposes generators for a largely unrelated purpose, using the fact that they innately pause in two cases:

  1. On creation (until the first value is requested)
  2. On each yield (when each subsequent value is requested)

to implement context management.

contextmanager just abuses this to make a class like this (actual source code is rather more complicated to cover edge cases):

class contextmanager:
    def __init__(self, gen):
        self.gen = gen  # Receives generator in initial state
    def __enter__(self):
        return next(self.gen)  # Advances to first yield, returning the value it yields
    def __exit__(self, *args):
        if args[0] is not None:
            self.gen.throw(*args)  # Plus some complicated handling to ensure it did the right thing
        else:
            try:
                next(self.gen)      # Check if it yielded more than once
            except StopIteration:
                pass                # Expected to only yield once
            else:
                raise RuntimeError(...)  # Oops, it yielded more than once, that's not supposed to happen

allowing the coroutine elements of generators to back a simpler way to write simple context managers.

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