yield在python中是什么意思_yield 关键字在 Python 中的用途是什么?

要了解其yield作用,必须了解什么是 生成器。而且,了解生成器之前,必须了解 _iterables_。

可迭代: iterable

创建一个列表,自然是需要能一一阅读其中每个元素。逐一读取其项的过程被称为迭代:>>> mylist = [1, 2, 3]

>>> for i in mylist:

... print(i)

1

2

3

mylist 是一个_可迭代的_。当您使用列表推导式时,即是创建了一个列表,因此也是可迭代的:>>> mylist = [x*x for x in range(3)]

>>> for i in mylist:

... print(i)

0

1

4

所有可以使用 for... in... 的数据结构都是可迭代的;lists,strings,文件...

这些可迭代的方法很方便,因为您可以随意读取它们,但是您将所有值都存储在内存中,当拥有很多值时,这并不总是想要的。

生成器:generator

生成器也是一种迭代器,一种特殊的迭代,特殊在只能迭代一次。生成器不会将所有值存储在内存中,而是即时生成值:generator: 发电机, 发生器,发电机发电但不储能 ;)>>> mygenerator = (x*x for x in range(3))

>>> for i in mygenerator:

... print(i)

0

1

4

只要使用()代替[], 便是列表推导式变成了生成器推导式。但是,由于生成器只能使用一次,因此您无法执行for i in mygenerator第二次:生成器计算0,然后将其丢弃,然后计算1,最后一次计算4。典型的黑瞎子掰苞米。

让出:yield

yield关键字与return的使用方式一样,不同之处在于该函数将返回生成器。>>> def createGenerator():

... mylist = range(3)

... for i in mylist:

... yield i*i

...

>>> mygenerator = createGenerator() # 创建一个 generator

>>> print(mygenerator) # mygenerator 是个对象!

>>> for i in mygenerator:

... print(i)

0

1

4

这个例子本身没什么用,但是当需要函数返回大量的值且只需要读取一次时,使用 yield 就变得方便。

掌握yield,需要清楚的一点是:在调用函数时,在函数主体中编写的代码不会运行,该函数仅返回生成器对象,初学容易对这一点产生困惑。

其次要明白,代码将在每次for使用生成器时从中断处继续。

现在最困难的部分是:

第一次for调用从您的函数创建的生成器对象时,它将从头开始运行函数中的代码,直到命中为止yield,然后它将返回循环的第一个值。然后,每个后续调用将运行您在函数中编写的循环的下一次迭代,并返回下一个值。这将一直持续到生成器被认为是空的为止,这在函数运行时没有命中时就会发生yield。那可能是因为循环已经结束,或者是因为您不再满足"if/else"。yield: 出产, 缴出, 让出, 屈服, 让路

用代码来说明

生成器 generator:# 创建返回生成器的方法

def _get_child_candidates(self, distance, min_dist, max_dist):

# 使用生成器对象一次,下面代码就会被调用一次:

# 如果还有左子对象节点,且距离合适, 返回下一个子对象

if self._leftchild and distance - max_dist < self._median:

yield self._leftchild

# 如果还有右子对象节点,且距离合适, 返回下一个子对象

if self._rightchild and distance + max_dist >= self._median:

yield self._rightchild

# 函数执行到这,被认为生成器空了

# 这里不超过两个值了: 左和右子对象

调用方 caller:# 创建空的 list, 和一个包含当前对象引用的列表

result, candidates = list(), [self]

# 循环 candidates (开始只有一个元素)

while candidates:

# 取最后的 candidate 并从列表中移除

node = candidates.pop()

# 获取 obj 与 candidate 间的距离

distance = node._get_dist(obj)

# 距离合适则填入结果

if distance <= max_dist and distance >= min_dist:

result.extend(node._values)

# 并把 candidate 的子元素加入列表

# 循环直至锁定candidate 全部子元素的子元素

candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))

return result

此代码包含几个智能部分:对一个列表循环迭代,但是循环在迭代时列表会扩展:-)这是浏览所有这些嵌套数据的一种简洁方法,即使这样做有点危险,因为可能会遇到无限循环。在这种情况下,请candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))耗尽所有生成器的值,但是while继续创建新的生成器对象,因为它们未应用于同一节点,因此将产生与先前值不同的值。

该extend()方法是期望可迭代并将其值添加到列表的列表对象方法。

通常我们将一个列表传递给它:>>> a = [1, 2]

>>> b = [3, 4]

>>> a.extend(b)

>>> print(a)

[1, 2, 3, 4]

但是在上面的代码中,得到了一个生成器,这更好,因为:不需要两次读取值。

可能有很多子元素,并且不希望所有子元素都存储在内存中。

这样做之所以有效,是因为 Python 不在乎方法的参数是否为列表。Python 期望的是可迭代对象,因此它可以与字符串,列表,元组和生成器一起使用!这就是所谓的鸭子输入,这是Python如此酷的原因之一。但这是另一个故事了……

控制生产器耗尽>>> class Bank(): # 搞个银行,弄点ATM提款机

... crisis = False

... def create_atm(self):

... while not self.crisis:

... yield "$100"

>>> hsbc = Bank() # 顺利的话你要多少 ATM 给你多少

>>> 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 # 危机来了,不行了,没钱了!

>>> print(corner_street_atm.next())

>>> wall_street_atm = hsbc.create_atm() # 新的 ATM 也一样

>>> print(wall_street_atm.next())

>>> hsbc.crisis = False # 危机过后 ATM 里也没钱

>>> print(corner_street_atm.next())

>>> brand_new_atm = hsbc.create_atm() # 搞个新的做新生

>>> for cash in brand_new_atm:

... print cash

$100

$100

$100

$100

$100

$100

$100

$100

$100

...

注意:对于Python 3,请使用print(corner_street_atm.__next__())或print(next(corner_street_atm))

对于诸如控制对资源的访问之类的各种事情,这可能很有用。

Itertools,您最好的朋友

itertools模块包含用于操纵可迭代对象的特殊功能。是否曾想复制发电机?连锁两个发电机?用一个班轮将值嵌套在嵌套列表中?Map / Zip没有创建另一个列表?

然后就import itertools。

一个例子?让我们看一下四马比赛的可能到达顺序:>>> horses = [1, 2, 3, 4]

>>> races = itertools.permutations(horses)

>>> print(races)

>>> print(list(itertools.permutations(horses)))

[(1, 2, 3, 4),

(1, 2, 4, 3),

(1, 3, 2, 4),

(1, 3, 4, 2),

(1, 4, 2, 3),

(1, 4, 3, 2),

(2, 1, 3, 4),

(2, 1, 4, 3),

(2, 3, 1, 4),

(2, 3, 4, 1),

(2, 4, 1, 3),

(2, 4, 3, 1),

(3, 1, 2, 4),

(3, 1, 4, 2),

(3, 2, 1, 4),

(3, 2, 4, 1),

(3, 4, 1, 2),

(3, 4, 2, 1),

(4, 1, 2, 3),

(4, 1, 3, 2),

(4, 2, 1, 3),

(4, 2, 3, 1),

(4, 3, 1, 2),

(4, 3, 2, 1)]

了解迭代的内部机制

迭代是一个隐含可迭代对象(实现__iter__()方法)和迭代器(实现__next__()方法)的过程。可迭代对象是可以从中获取迭代器的任何对象。迭代器是使您可以迭代可迭代对象的对象。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值