类中的python生成器

类中的python生成器,python,class,generator,Python,Class,Generator,我从中学习发电机。这确实是发电机的一个很好的例子。但我对其中一个示例代码感到困惑 >>> class Bank(): # let's create a bank, building ATMs ... crisis = False ... def create_atm(self): ... while not self.crisis: ... yield "$100" >>> hsbc = Bank() # whe

我从中学习发电机。这确实是发电机的一个很好的例子。但我对其中一个示例代码感到困惑

>>> class Bank(): # let's create a bank, building ATMs
...    crisis = False
...    def create_atm(self):
...        while not self.crisis:
...            yield "$100"
>>> hsbc = Bank() # when everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())  
$100  
>>> print(corner_street_atm.next())  
$100  
>>> print([corner_street_atm.next() for cash in range(5)])  
['$100', '$100', '$100', '$100', '$100']  
>>> hsbc.crisis = True # crisis is coming, no more money!  
>>> print(corner_street_atm.next())  
<type 'exceptions.StopIteration'>   
>>> wall_street_atm = hsbc.create_atm() # it's even true for new ATMs  
>>> print(wall_street_atm.next())  
<type 'exceptions.StopIteration'>  

>>> hsbc.crisis = False # trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>

>>> brand_new_atm = hsbc.create_atm() # build a new one to get back in business
>>> for cash in brand_new_atm:
...    print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...
>>class Bank():#让我们创建一个银行,创建自动取款机
...    危机=错误
...    def创建_atm(自身):
...        虽然不是自我危机:
...            收益率“$100”
>>>当一切正常时,自动取款机会给你想要的钱
>>>拐角处街道自动取款机=汇丰银行。创建自动取款机()
>>>打印(街角\街道\ atm.next())
$100  
>>>打印(街角\街道\ atm.next())
$100  
>>>打印([corner_street_atm.next()用于范围内的现金(5)])
['$100', '$100', '$100', '$100', '$100']  
>>>hsbc.crisis=True#危机即将来临,没有更多的钱了!
>>>打印(街角\街道\ atm.next())
>>>华尔街自动取款机=汇丰。创建自动取款机()#对于新的自动取款机也是如此
>>>打印(华尔街atm.next())
>>>hsbc.crisis=False#问题是,即使在危机后,自动取款机仍然是空的
>>>打印(街角\街道\ atm.next())
>>>brand_new_atm=hsbc.create_atm()#创建一个新的以重新投入业务
>>>对于全新自动取款机中的现金:
...    印钞
$100
$100
$100
$100
$100
$100
$100
$100
$100
...
hsbc.crisis重置为False时,拐角处的atm只能产生停止迭代。
为什么会发生这种情况。我认为危机过后,街角的自动取款机不是空的。

问题在于,当你说

corner_street_atm = hsbc.create_atm()
您只调用了一次函数,而且每次都会调用它。因此,让我们来看看发生了什么

  def create_atm(self):
        # Called right away, when you say the above line and only then
        print("Called function") 

        # Loops while crisis = False
        while not self.crisis: 
            yield "$100"
现在,我们可以问这样一个问题:当危机是真的时,我们的方法在哪里寻找,我们发现这是一个点,如下所示:

  def create_atm(self):
        # Called right away, when you say the above line and only then
        print("Called function") 

        # Loops while crisis = False
        while not self.crisis: 
            yield "$100"
            #<------ Where you function points after you set crisis to false and get the next
小心这一点,作为你最后的决定

for cash in brand_new_atm:
    print(cash)

将永远循环,因为您目前看不到atm机中有多少现金(因此,只要没有危机,它就会吐出美元钞票。

问题在于,当您说

corner_street_atm = hsbc.create_atm()
您只调用了一次函数,而且每次都会调用它。因此,让我们来看看发生了什么

  def create_atm(self):
        # Called right away, when you say the above line and only then
        print("Called function") 

        # Loops while crisis = False
        while not self.crisis: 
            yield "$100"
现在,我们可以问这样一个问题:当危机是真的时,我们的方法在哪里寻找,我们发现这是一个点,如下所示:

  def create_atm(self):
        # Called right away, when you say the above line and only then
        print("Called function") 

        # Loops while crisis = False
        while not self.crisis: 
            yield "$100"
            #<------ Where you function points after you set crisis to false and get the next
小心这一点,作为你最后的决定

for cash in brand_new_atm:
    print(cash)

将永远循环,因为您当前看不到atm机中有多少现金(因此只要没有危机,它只会吐出美元钞票。

一般来说,这是因为您在设置
hsbc.crisis=True
后调用了
拐角处的atm.next()
。如果您这样做,您将不会有任何问题:

hsbc.crisis=False

corner_street_atm = hsbc.create_atm()

hsbc.crisis=True

hsbc.crisis=False

corner_street_atm.next()
Out[54]: '$100'
原因是,
corner\u street\u atm
是一个生成器(迭代器)对象,在本例中创建的生成器将调用o,每次调用其next()方法都不带参数;如果返回的值等于sentinel,则将引发
StopIteration
,否则将返回该值


问题是,一旦你调用
拐角街\u atm.next()
hsbc.crisis=True
之后,就会引发异常。一旦引发异常,就没有办法再循环这个对象了,除非你创建一个新对象!

通常是因为你调用了
拐角街\u atm.next()
设置
hsbc.crisis=True
后。如果您这样做,您将不会有任何问题:

hsbc.crisis=False

corner_street_atm = hsbc.create_atm()

hsbc.crisis=True

hsbc.crisis=False

corner_street_atm.next()
Out[54]: '$100'
原因是,
corner\u street\u atm
是一个生成器(迭代器)对象,在本例中创建的生成器将调用o,每次调用其next()方法都不带参数;如果返回的值等于sentinel,则将引发
StopIteration
,否则将返回该值


问题是,一旦你调用
拐角处的atm.next()
hsbc.crisis=True
之后,就会引发异常。一旦引发异常,就没有办法再循环这个对象了,除非你创建一个新对象!

这里的问题是你的生成器(它是一种迭代器)已耗尽。一旦耗尽,迭代器就不应在生成值和提高
StopIteration
之间来回切换(换句话说,即使您的示例不是希望它执行的操作,但它的行为仍应如此)。以下是有关迭代器协议的更多信息:

在这种特殊情况下,生成器停止生成值的原因是,一旦退出
while
循环(当
'crisis'
为True时调用
next
时,就会发生这种情况),就无法重新进入循环

您最可能想做的是在一个单独的
ATM
对象上使用
\uuu iter\uuuu
魔术方法。有关详细信息,请参见:

它可能看起来像这样:

class ATM():
    def __init__(self, owner):
        self.owner = owner
    def __iter__(self):
        yield "$100"
    def __call__(self):
        if self.owner.crisis is True:
            return 'crisis!'

class Bank(): # let's create a bank, building ATMs
    crisis = False
    def create_atm(self):
        return ATM(self)
您将希望通过以下方式获得atm迭代器:

>>> hsbc = Bank() 
>>> corner_street_atm = hsbc.create_atm() # this way
>>> corner_street_atm = ATM(hsbc) # or this way
>>> corner_street_atm_iterator = iter(corner_street_atm, 'crisis!')
最后一行使用了一个可选的
iter
函数形式,因为提供了第二个参数。第二个形式返回的迭代器在
corner\u street\u atm.\uuuu call\uu()
返回提供给iter的sentinel值。在这种情况下,sentinel是
“危机!”

然后像这样迭代:

class Bank():
    crisis = False

    def create_atm(self):
        print("Called function")
        while True:
            if not self.crisis:
                yield "$100"
            else:
                yield "$0"
>>> print(corner_street_atm_iterator.next())  
$100  
注意:
ATM
对象如果不使用
iter
'crisis!'
哨兵参数,就永远不会用完钱

infinite_atm_iterator = iter(ATM(some_bank))

这里的问题是您的生成器(它是一种迭代器)已经耗尽。一旦耗尽,迭代器就不应该在生成值和提高
StopIteration
之间来回切换(换句话说,您的示例的行为应该是这样的,即使它不是您希望它做的)。下面是有关迭代器协议的更多信息:

在这种特殊情况下,生成器停止生成值的原因是,一旦退出
while
循环(whi