yield 关键字在 Python 中的用途是什么?

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

要了解其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... 的数据结构都是可迭代的;listsstrings,文件...

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


生成器: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 是个对象!
<generator object createGenerator at 0xb7555c34>
>>> 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]

但是在上面的代码中,得到了一个生成器,这更好,因为:

  1. 不需要两次读取值。
  2. 可能有很多子元素,并且不希望所有子元素都存储在内存中。

这样做之所以有效,是因为 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())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # 新的 ATM 也一样
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # 危机过后 ATM 里也没钱
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> 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)
<itertools.permutations object at 0xb754f1dc>
>>> 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__()方法)的过程。可迭代对象是可以从中获取迭代器的任何对象。迭代器是使您可以迭代可迭代对象的对象。

相关文章
|
9天前
|
算法 Java Docker
(Python基础)新时代语言!一起学习Python吧!(三):IF条件判断和match匹配;Python中的循环:for...in、while循环;循环操作关键字;Python函数使用方法
IF 条件判断 使用if语句,对条件进行判断 true则执行代码块缩进语句 false则不执行代码块缩进语句,如果有else 或 elif 则进入相应的规则中执行
80 1
|
28天前
|
缓存 供应链 监控
1688item_search_factory - 按关键字搜索工厂数据接口深度分析及 Python 实现
item_search_factory接口专为B2B电商供应链优化设计,支持通过关键词精准检索工厂信息,涵盖资质、产能、地理位置等核心数据,助力企业高效开发货源、分析产业集群与评估供应商。
|
1月前
|
JSON 监控 数据格式
1688 item_search_app 关键字搜索商品接口深度分析及 Python 实现
1688开放平台item_search_app接口专为移动端优化,支持关键词搜索、多维度筛选与排序,可获取商品详情及供应商信息,适用于货源采集、价格监控与竞品分析,助力采购决策。
|
21天前
|
缓存 监控 算法
唯品会item_search - 按关键字搜索 VIP 商品接口深度分析及 Python 实现
唯品会item_search接口支持通过关键词、分类、价格等条件检索商品,广泛应用于电商数据分析、竞品监控与市场调研。结合Python可实现搜索、分析、可视化及数据导出,助力精准决策。
|
21天前
|
缓存 监控 算法
苏宁item_search - 按关键字搜索商品接口深度分析及 Python 实现
苏宁item_search接口支持通过关键词、分类、价格等条件检索商品,广泛应用于电商分析、竞品监控等场景。具备多维度筛选、分页获取、数据丰富等特性,结合Python可实现搜索、分析与可视化,助力市场研究与决策。
|
20天前
|
JSON 缓存 供应链
电子元件 item_search - 按关键字搜索商品接口深度分析及 Python 实现
本文深入解析电子元件item_search接口的设计逻辑与Python实现,涵盖参数化筛选、技术指标匹配、供应链属性过滤及替代型号推荐等核心功能,助力高效精准的电子元器件搜索与采购决策。
|
26天前
|
缓存 自然语言处理 算法
item_search - Lazada 按关键字搜索商品接口深度分析及 Python 实现
Lazada的item_search接口是关键词搜索商品的核心工具,支持多语言、多站点,可获取商品价格、销量、评分等数据,适用于市场调研与竞品分析。
|
3月前
|
人工智能 JavaScript 前端开发
Python中常见的关键字
Python中常见的关键字是语言内置的特殊单词,具有特定功能,如控制逻辑、定义函数等。关键字不可作为变量名使用,否则会导致语法或类型错误。本文详细介绍了关键字的含义、分类及常见示例,并列举了常见报错原因与解决方法。
145 0
|
3月前
|
存储 人工智能 大数据
Python中的yield关键字
在Python中,`yield`关键字用于创建生成器函数,实现懒惰计算和状态保存。它能逐个生成值,节省内存,适用于处理大数据集或无限序列。通过生成器函数和表达式,可以高效地进行数据过滤与递增序列生成,提高代码效率与可维护性。
308 0
|
10月前
|
C语言 Python
[oeasy]python054_python有哪些关键字_keyword_list_列表_reserved_words
本文介绍了Python的关键字列表及其使用规则。通过回顾`hello world`示例,解释了Python中的标识符命名规则,并探讨了关键字如`if`、`for`、`in`等不能作为变量名的原因。最后,通过`import keyword`和`print(keyword.kwlist)`展示了Python的所有关键字,并总结了关键字不能用作标识符的规则。
182 9

推荐镜像

更多