类中的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