如果我们在Python中使用耗尽的发电机进行循环会发生什么?

发布于 2025-02-09 00:44:11 字数 880 浏览 1 评论 0原文

我正在Python 3中创建一个发电机,该发电机可能会产生一个或更多的值。

我想要的条件是,我想从第二个值开始使用此迭代器循环,依此类推,以该值运行API请求函数。如果发电机仅产生一个值,则不需要执行for循环和相应的代码。如果发电机产生多个值,则从发电机的第二个值等开始执行前循环内部的函数。

我要以第二个值开始的原因是因为已经为API请求访问了第一个值,并且其结果已存储。

我的问题与产生单个值的发电机有关。

我在下面给出代码示例:(我简化了使用print()函数的API请求):

def iterexample(): # creating a simple iterator that return a single value
    yield 0

print(0)
iter = iterexample()
next(iter) #generator is consumed once here
for i in iter: #1 generator is exhausted
    print(i, ' inside loop')   #2 this is skipped because the generator is exhausted
#3 rest of the code outside the loop will be executed

它返回我的期望:只有0是打印的,而不是“ 0 inside loop”

0

我的问题是:

  1. 它是最安全,最柔软的方法那会吗?它会筹集吗? 有错误吗?
  2. 它会产生无限循环吗?我很害怕是否会导致 API请求的无限循环。
  3. 请查看我的#1〜#3评论,在上面的代码中,是我的 正确理解吗?

感谢您的回复和帮助。干杯!

I am creating a generator in python 3 which may yield a single value or more.

The condition that I wanted is, I want to loop with this iterator starting at the second value and so on, running an API request function with that value. If the generator yield only a single value, the for loop and corresponding code is not needed to be executed. If the generator yield more than one value, the function inside the for-loop will be executed starting from the second value of generator and so on.

The reason why I want to start at the second value is because the first value is already accessed for the API request and its result has been stored.

My question is related to a generator that produce a single value.

I give the code example below: (I simplified API Request with print() function):

def iterexample(): # creating a simple iterator that return a single value
    yield 0

print(0)
iter = iterexample()
next(iter) #generator is consumed once here
for i in iter: #1 generator is exhausted
    print(i, ' inside loop')   #2 this is skipped because the generator is exhausted
#3 rest of the code outside the loop will be executed

It returns what I expected: only 0 is printed, not "0 inside loop"

0

My question is:

  1. Is it the safest and the most pythonic way to do that? will it raise
    any error?
  2. Will it produce infinite loop? I am very afraid if it will result as
    infinite loop of API request.
  3. Please review my #1 ~ #3 comment in above codes, are my
    understanding correct?

Thanks for the response and the help. Cheers!

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

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

发布评论

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

评论(2

柳若烟 2025-02-16 00:44:11

1是最安全,最愚蠢的方法吗?它会引起任何错误吗?

一旦发电机耗尽,当询问新值时,它将不断提高stopiteration例外。对于循环,可以在升起此例外时终止循环来处理这种情况,这使得将耗尽的发电机传递到用于循环构造器的情况下是安全的。

但是,您的代码调用next直接,因此仅当它还处理stopiteration异常时才安全。在这种情况下,您需要记录提供的生成器必须产生1个或更多值或容忍空案例。如果发电机没有返回值,那么您将获得错误。例如,

def iterexample():
    while False:
        yield 0

print(next(iterexample()))
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print(next(iterexample()))
StopIteration

为防止空发电机,您可以将第二个可选默认参数用于Next

print(next(iterexample(), "default"))
default

2它会产生无限循环吗?我很害怕是否会作为API请求的无限循环产生。

同样,这取决于发电机。发电机不需要具有最终值。您可以轻松地定义这样的非终止生成器:

def iterexample():
    i = 0
    while True:
        yield i
        i += 1

for i in iterexample(): #This never ends.
    print(i)

如果这是您的关注点,防止永无止境输出的一种方法是使用islice,该在消耗了许多值后会切断发电机:

from itertools import islice

for i in islice(iterexample(), 5):
    print(i)
0
1
2
3
4

1 Is it the safest and the most pythonic way to do that? will it raise any error?

Once a generator is exhausted, it will continually raise StopIteration exceptions when asked for new values. For loops can handle this case by terminating the loop when this exception is raised, which makes it safe to pass an exhausted generator to a for loop constructor.

However, your code calls next directly, and is therefore only safe only if it also handle StopIteration exceptions. In this case you would need to document that the generator provided must produce 1 or more values or be tolerant of the empty case. If the generator returned no values, then you would get an error. e.g.

def iterexample():
    while False:
        yield 0

print(next(iterexample()))
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print(next(iterexample()))
StopIteration

To prevent against empty generators you can use the second optional default argument to next.

print(next(iterexample(), "default"))
default

2 Will it produce infinite loop? I am very afraid if it will result as infinite loop of API request.

Again this depends on the generator. Generators do not need to have an end value. You can easily define non-ending generators like this:

def iterexample():
    i = 0
    while True:
        yield i
        i += 1

for i in iterexample(): #This never ends.
    print(i)

If this is a concern for you, one way to prevent never ending outputs would be to use an islice that cuts off your generator after so many values are consumed:

from itertools import islice

for i in islice(iterexample(), 5):
    print(i)
0
1
2
3
4
浮华 2025-02-16 00:44:11

如果我正确理解您的问题:您有一个案件所需的第一个值,其余的则是其他情况。
我建议建立一个适合您需求的结构,例如:

class MyStructrue:
    def __init__(self, initial_data):
        if not initial_data:
            # Make sure your data structure is valid before using it
            raise ValueErro("initial_data is empty")

        self.initial_data = initial_data

    @property
    def cached_value(self):
        return self.initial_data[0]

    @property
    def all_but_first(self):
        return self.initial_data[1:]

在这种情况下,您确保数据有效,并且可以给您的登录名称,以反映您的价值所代表的内容。在此示例中,我给了他们虚拟名称,但是您应该尝试制作与您的业务相关的东西。

可以使用这样的类(更改名称只是为了说明方法命名如何记录您的代码):

tasks = TaskQueue(get_input_in_some_way())
advance_task_status(tasks.current_task)

for pending_task in tasks.pending_tasks:
    log_remaining_time(pending_tasks)

您应该首先尝试了解数据架构代表的内容并构建有用的API,以隐藏实现实现以更好地反映您的业务。

If I understand correctly your issue: you have a first value that you need for a case, and the rest for another case.
I would recommend building a structure that fits your needs, something like this:

class MyStructrue:
    def __init__(self, initial_data):
        if not initial_data:
            # Make sure your data structure is valid before using it
            raise ValueErro("initial_data is empty")

        self.initial_data = initial_data

    @property
    def cached_value(self):
        return self.initial_data[0]

    @property
    def all_but_first(self):
        return self.initial_data[1:]

In this case, you make sure your data is valid, and you can give your accessors names that reflects what you those value are representing. In this example, I gave them dummy names, but you should try to make something that is relevant to your business.

Such a class could be used this way (changed names just to illustrate how method naming can document your code):

tasks = TaskQueue(get_input_in_some_way())
advance_task_status(tasks.current_task)

for pending_task in tasks.pending_tasks:
    log_remaining_time(pending_tasks)

You should first try to understand what your datastructure represents and build a useful api that hide the implementation to better reflect your business.

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