何为使用yieldPython 中的关键字?

比如说,我在试着理解这个代码1:

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  

这就是打电话的人:

result, candidates = [], [self]
while candidates:
    node = candidates.pop()
    distance = node._get_dist(obj)
    if distance <= max_dist and distance >= min_dist:
        result.extend(node._values)
    candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result

当方法_get_child_candidates是否调用 ? 列表是否返回 ? 单元素 ? 是否又调用 ? 以后的呼叫何时停止 ?


1. 本代码由Jochen Schulz(jrschulz)编写,他为公制空间制作了一个伟大的Python图书馆。模块 m 空间.

当前回答

缩略yieldkeywit 用于查点/ 字符中, 函数预期将返回一个输出。 我想引用此非常简单 。例例A:

# example A
def getNumber():
    for r in range(1,10):
        return r

上述函数只返回1即使它被多次调用。 如果我们替换returnyield以内例B:

# example B
def getNumber():
    for r in range(1,10):
        yield r

它会回来的1第一次调用时2当日,3,4直至10岁为止的增量。

尽管《公约》例B在概念上是真实的,但称它为Python 3( 3)我们必须采取以下行动:


g = getNumber() #instance
print(next(g)) #will print 1
print(next(g)) #will print 2
print(next(g)) #will print 3

# so to assign it to a variables
v = getNumber()
v1 = next(v) #v1 will have 1
v2 = next(v) #v2 will have 2
v3 = next(v) #v3 will have 3

其他回答

一个容易理解它是什么的简单例子:yield

def f123():
    for _ in range(4):
        yield 1
        yield 2


for i in f123():
    print (i)

产出是:

1 2 1 2 1 2 1 2

缩略yield关键字缩写为两个简单的事实:

  1. 如果汇编者检测到yield关键字任何地方函数内部的函数,该函数不再通过return语句。取代, 它, 它立即立即返回返回 a“等待列表”对象调用发电机
  2. 发电机是易用的,什么是易 易 易 性它的任何东西 像一个listsetrange或 dict-view, 带有按一定顺序视察每个要素的内建程序规程.

概括地说:最常见的情况是,a 发电机是一个懒惰、递增的待用清单。, 和yield语句允许您使用函数符号来编程列表值发电机应该逐渐吐出来此外,先进用途使你能够使用发电机作为共同路线(见下文)。

generator = myYieldingFunction(...)  # basically a list (but lazy)
x = list(generator)  # evaluate every element into a list

   generator
       v
[x[0], ..., ???]

         generator
             v
[x[0], x[1], ..., ???]

               generator
                   v
[x[0], x[1], x[2], ..., ???]

                       StopIteration exception
[x[0], x[1], x[2]]     done

基本上,当yield语句被遇到,函数暂停并保存状态,然后根据 python 传动协议发布“ 列表中下一个返回值” 。next()并捕获aStopIteration您可能遇到过发电机,例如:发电机表达式; 发电机功能更强大,因为您可以将参数反馈到暂停的发电机功能中,用它们来实施共同路线。稍后更多。


基本示例(“清单”)

让我们定义一个函数makeRange和皮松的一模一样range调用makeRange(n)将一个天才:

def makeRange(n):
    # return 0,1,2,...,n-1
    i = 0
    while i < n:
        yield i
        i += 1

>>> makeRange(5)
<generator object makeRange at 0x19e4aa0>

要迫使发电机立即返回其待处理值, 您可以将它传送到list()(就像你可以 任何可重复的):

>>> list(makeRange(5))
[0, 1, 2, 3, 4]

比较“仅返回列表”的示例

上述例子可视为仅仅是创建一份清单,并附在后面并返回:

# return a list                  #  # return a generator
def makeRange(n):                #  def makeRange(n):
    """return [0,1,2,...,n-1]""" #      """return 0,1,2,...,n-1"""
    TO_RETURN = []               # 
    i = 0                        #      i = 0
    while i < n:                 #      while i < n:
        TO_RETURN += [i]         #          yield i
        i += 1                   #          i += 1
    return TO_RETURN             # 

>>> makeRange(5)
[0, 1, 2, 3, 4]

不过,有一个重大差别;见最后一节。


您如何使用发电机

所有发电机都是易变的, 所以它们经常被这样使用:

#                  < ITERABLE >
>>> [x+10 for x in makeRange(5)]
[10, 11, 12, 13, 14]

为了对发电机有更好的感觉,你可以和发电机一起玩itertools模块 (必须使用)chain.from_iterable而不是chain例如,你甚至可能使用发电机来实施无穷无尽的懒惰清单,例如:itertools.count()您可以执行您自己的def enumerate(iterable): zip(count(), iterable),或者与yield时段循环中的关键字 。

请注意:发电机实际上可以用于更多的其他物品,例如:实施共同方案或非确定性编程或其他优雅的东西。 然而, 我在此展示的“ 懒惰列表” 观点是您最常用的 。


幕后幕后

这就是“ Python 迭代协议” 是如何工作的。 也就是说, 当您在list(makeRange(5))。这就是我刚才所说的“懒惰、递增清单”。

>>> x=iter(range(5))
>>> next(x)  # calls x.__next__(); x.next() is deprecated
0
>>> next(x)
1
>>> next(x)
2
>>> next(x)
3
>>> next(x)
4
>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

内置函数next()只需调用物体.__next__()函数,该函数是“终止协议”的一部分,并在所有迭代器中查找。您可以手动使用next()函数( 以及迭代协议的其他部分) 来实施花哨, 通常以降低可读性为代价, 所以尽量避免这样做...


锥体

锥体例如:

def interactiveProcedure():
    userResponse = yield makeQuestionWebpage()
    print('user response:', userResponse)
    yield 'success'

coroutine = interactiveProcedure()
webFormData = next(coroutine)  # same as .send(None)
userResponse = serveWebForm(webFormData)

# ...at some point later on web form submit...

successStatus = coroutine.send(userResponse)

共同常规(通常通过下列途径接受输入的发电机)yielde.g.nextInput = yield nextOutput,作为双向通信的一种形式)基本上是一种计算方法,它允许暂停自己并请求输入(例如,它下一步应该做什么)。当共程本身暂停时(当运行中的共程最终击中yield键,计算被暂停,控制被倒回“调用”功能(要求next暂停的生成器/ coutine 仍然暂停, 直到另一个引用函数( 可能是一个不同的函数/ 变量) 要求下一个值来取消它( 通常通过输入数据将暂停的逻辑内含引导到 coroutine 代码 ) 。

您可以将皮延共程视为懒惰的递增待决列表, 下一个元素不仅取决于先前的计算, 而且还取决于输入, 您可以选择在生成过程中注射 。


贫提亚e

通常,大多数人不会关心以下的区别,可能想在这里停止阅读。

在Python-speak语中,易 易 易 性中“理解“循环”概念的任意对象,如列表[1,2,3],和一个振动器是请求循环( 类似) 的具体实例[1,2,3].__iter__()A. A. A.发电机发电机与任何迭代器完全相同,但文字写法除外(用函数语法)。

当您从列表中请求一个迭代器时, 它会创建一个新的迭代器。 但是, 当您从一个迭代器中请求一个迭代器( 您很少会这样做 ) 时, 它只会给您一个副本 。

因此,在不可能的情况下,你没有 做这样的事情...

> x = myRange(5)
> list(x)
[0, 1, 2, 3, 4]
> list(x)
[]

...然后记住发电机是振动器;即,这是一次性使用。如果您想要重新使用它,您应该拨打myRange(...)如果您需要两次使用结果,将结果转换为列表并将其存储在变量中x = list(myRange(5))。那些绝对需要克隆生成器的人(例如,正在做可怕的黑化元方案化的人)可以使用itertools.tee (Python 3仍然在工作(如果绝对必要,自Python PEP 标准提案推迟审议。

简单简单简单yield计算 fibonacci 序列的基础方法,解释如下:

def fib(limit=50):
    a, b = 0, 1
    for i in range(limit):
       yield b
       a, b = b, a+b

当你把这个输入你的REPL,然后尝试把它称为, 你会得到一个神秘的结果:

>>> fib()
<generator object fib at 0x7fa38394e3b8>

这是因为:yield发送到 Python 的信号, 您想要创建发电机发电机,即,一个根据需求产生价值的物体。

那么,您如何生成这些值? 可以通过使用内置函数直接实现next,或间接地,通过将其喂养到消耗价值的建筑上。

使用内置next()函数,直接引用.next/__next__迫使发电机产生一个价值:

>>> g = fib()
>>> next(g)
1
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
>>> next(g)
5

间接提供fib至 afor环环, alist初始初始化器, atuple初始化器, 或其他任何期望生成/ 产生值的对象, 您会“ 组装” 生成器, 直到它无法生成更多值( 并返回 ) :

results = []
for i in fib(30):       # consumes fib
    results.append(i) 
# can also be accomplished with
results = list(fib(30)) # consumes fib

同样,tuple初始化器 :

>>> tuple(fib(5))       # consumes fib
(1, 1, 2, 3, 5)

生成器与功能不同, 因为它很懒。 它通过保持本地状态, 并允许您在需要的时候恢复运行来达到这个目的 。

当你们第一次祈祷的时候,fib称其为:

f = fib()

Python 编译函数,遇到yieldkeyword and simply return a generate objects back at you. 似乎没有什么帮助。

当您要求它生成第一个值时,它直接或间接地执行它发现的所有语句,直到它遇到一个yield,然后,它产生回 价值,你提供yield并暂停。 举例来证明这一点, 让我们使用一些print电话(取代电话)print "text"如果Python 2 上写着:

def yielder(value):
    """ This is an infinite generator. Only use next on it """ 
    while 1:
        print("I'm going to generate the value for you")
        print("Then I'll pause for a while")
        yield value
        print("Let's go through it again.")

现在,输入REPL:

>>> gen = yielder("Hello, yield!")

您现在有一个生成对象, 正在等待命令来生成值。 使用next并查看打印的内容 :

>>> next(gen) # runs until it finds a yield
I'm going to generate the value for you
Then I'll pause for a while
'Hello, yield!'

未引用的结果是打印的内容。引用的结果是返回的内容yield调来next现在再次:

>>> next(gen) # continues from yield and runs again
Let's go through it again.
I'm going to generate the value for you
Then I'll pause for a while
'Hello, yield!'

发电机记得它被停停在yield value从那里打印下一条消息并搜索yield暂停该语句时(由于while(循环))

缩略yieldkeywit 用于查点/ 字符中, 函数预期将返回一个输出。 我想引用此非常简单 。例例A:

# example A
def getNumber():
    for r in range(1,10):
        return r

上述函数只返回1即使它被多次调用。 如果我们替换returnyield以内例B:

# example B
def getNumber():
    for r in range(1,10):
        yield r

它会回来的1第一次调用时2当日,3,4直至10岁为止的增量。

尽管《公约》例B在概念上是真实的,但称它为Python 3( 3)我们必须采取以下行动:


g = getNumber() #instance
print(next(g)) #will print 1
print(next(g)) #will print 2
print(next(g)) #will print 3

# so to assign it to a variables
v = getNumber()
v1 = next(v) #v1 will have 1
v2 = next(v) #v2 will have 2
v3 = next(v) #v3 will have 3

(我下面的回答只从使用Python发电机的角度,而不是从使用Python发电机的角度,而不是从使用Python发电机的角度来回答发电机机制基本实施,这涉及一些玩弄堆叠和堆积操纵的把戏。 ))

何时yield使用代替return在 python 函数中,该函数被转换为特殊的东西,称为generator function该函数返回generator类型。缩略yield关键字是通知 Python 编译者专门处理此函数的标志。正常函数一旦从中返回某些值, 正常函数就会终止。 但是, 在编译器的帮助下, 生成器函数将会终止 。能够被想象到即,执行环境将恢复,执行将持续到最后一年。直到你明确要求返回,这会引起StopIteration选项(这也是迭代协议的一部分),或达到函数的结尾。我发现很多关于generator但这个1个调自自functional programming perspective是最可消化的。

(现在我想谈一下为什么generatoriterator我希望这能帮助你掌握基本动机和基本动机这一概念以其他语言出现,如C#。 )

据我所知,当我们想要处理一堆数据时, 我们通常先把数据存放在某处,然后一个一个地处理。但是这个是。幼天如果数据量很大, 事先将数据全部储存起来是昂贵的 。而不是储存data为什么不直接储存某种metadata间接,即:the logic how the data is computed.

有两种方法可以包扎这类元数据。

  1. OO 方法,我们包封元数据as a class这就是所谓的iterator执行滚动协议(即__next__(), 和__iter__()这也是人们所普遍看到的方法。电动电机设计图案.
  2. 功能方法,我们包封元数据as a function这就是所谓的generator function但是在兜帽帽下, 返回的人generator object仍为IS-A因为它还执行传动协议 。

无论哪种方式, 都会创建一个迭代器, 即某个可以提供您想要的数据的对象。 OO 处理方式可能有点复杂。 总之, 由您决定使用哪一种 。