何为使用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 空间.

当前回答

yield:

  • 可以通过停止函数从函数返回一个值多次。
  • 可使用from和它一样yield from.
  • 用于返回大数据时,将其分为小部分数据,以防止大量使用内存。

例如,test()可在以下返回'One', 'Two'['Three', 'Four']以一一一一一一一一一一一一一停止test()so so, so, so, so, so, so, so, so, so,test()停止返回共3倍test()总共3次:

def test():
    yield 'One'                  # Stop, return 'One' and resume 
    yield 'Two'                  # Stop, return 'Two' and resume
    yield from ['Three', 'Four'] # Stop and return ['Three', 'Four'] 

下面这三套代码可以调用test()打印和打印'One', 'Two', 'Three''Four':

for x in test():
    print(x)
x = test()
print(next(x))
print(next(x))
print(next(x))
print(next(x))
x = test()
print(x.__next__())
print(x.__next__())
print(x.__next__())
print(x.__next__())

其结果是:

$ python yield_test.py
One
Two
Three
Four

此外,在使用returnyield,没有办法从return:

def test():
    yield 'One' 
    yield 'Two'
    yield from ['Three', 'Four']
    return 'Five' # 'Five' cannot be got

x = test()
print(next(x))
print(next(x))
print(next(x))
print(next(x))
print(next(x)) # Here

因此,在试图获取'Five':

$ python yield_test.py 
One
Two
Three
Four
Traceback (most recent call last):
  File "C:\Users\kai\yield_test.py", line 12, in <module>
    print(next(x))
          ^^^^^^^
StopIteration: Five

其他回答

python 的输出与返回语句类似,但有些差异除外。如果要从函数返回多个值,返回语句将把所有值都作为列表返回,并将其存储在调用符块的内存中。但如果我们不想使用额外的内存,会怎样?相反,我们需要在需要时从函数中获取该值。这是产出的来源。考虑以下函数:

def fun():
   yield 1
   yield 2
   yield 3

打电话的人是:

def caller():
   print ('First value printing')
   print (fun())
   print ('Second value printing')
   print (fun())
   print ('Third value printing')
   print (fun())

上述代码段(调用函数),如果调用,产出:-

First value printing
1
Second value printing
2
Third value printing
3

从上文可以看出, 产出返回其调用器的值, 但当函数再次调用时, 它不会从第一个语句开始, 而是从产出后右侧的语句开始。 在上述示例中, “ 第一值打印” 打印, 函数被调用。 1 被回传并打印。 然后, 打印“ 第二值打印” , 并再次调用有趣 () 。 它不打印 1 (第一个语句) , 而是返回 2 , 也就是说, 仅从产出 1 之后的语句 。 同样的程序会进一步重复 。

yield简直就像return区别在于,下次你打电话给发电机时,从最后一次呼叫开始执行。yield与返回不同的语句,当生成时, 堆叠框架不会被清理, 但是控件会被转回调用方, 所以下次调用函数时, 它的状态将会恢复 。

对于您的代码,函数get_child_candidates动作就像一个循环器,这样当您扩展列表时,它会一次向新列表添加一个元素。

list.extend在你公布的代码样本中, 只需将图普还给列表, 并附加到列表中, 就会更加清晰 。

简单使用实例 :

>>> def foo():
    yield 100
    yield 20
    yield 3

    
>>> for i in foo(): print(i)

100
20
3
>>> 

如何运行 : 调用时, 函数会立即返回对象。 对象可以传递到下一个( ) 函数 。 当调用下一个( ) 函数时, 您的函数会一直运行到下一个产值, 并为下一个( ) 函数提供返回值 。

在引擎盖下, 循环确认对象是一个生成对象, 并使用下一个( ) 来获取下一个值 。

在一些语言中,比如ES6和更高语言中,它的实施略有不同, 所以下一个是生成对象的成员函数, 每次它得到下一个值时, 你就可以从调用器中传递数值。 所以如果结果是生成器, 那么你可以做类似y=结果。 ext( 555) , 而程序生成值可以说像 z = 产值 999 。 y 的值将是 999 , 下一个产值是 999, 而 z 的值将是 555 , 下一个产值是 555。 Python 获取并发送方法也有类似的效果 。

简单解答

函数至少包含一个时yield语句,函数自动成为发电机功能。当您调用发电机功能时, python 在发电机功能中执行代码,直到yield发生声明。yield当您再次调用发电机功能时, python 继续从冻结位置执行发电机功能中的代码,直到yield发电机函数执行代码直到发电机功能用完时没有yield语句。

基准基准基准基准基准基准基准

创建列表并返回它 :

def my_range(n):
    my_list = []
    i = 0
    while i < n:
        my_list.append(i)
        i += 1
    return my_list

@profile
def function():
    my_sum = 0
    my_values = my_range(1000000)
    for my_value in my_values:
        my_sum += my_value

function()

结果有:

Total time: 1.07901 s
Timer unit: 1e-06 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     9                                           @profile
    10                                           def function():
    11         1          1.1      1.1      0.0      my_sum = 0
    12         1     494875.0 494875.0     45.9      my_values = my_range(1000000)
    13   1000001     262842.1      0.3     24.4      for my_value in my_values:
    14   1000000     321289.8      0.3     29.8          my_sum += my_value



Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
     9   40.168 MiB   40.168 MiB           1   @profile
    10                                         def function():
    11   40.168 MiB    0.000 MiB           1       my_sum = 0
    12   78.914 MiB   38.746 MiB           1       my_values = my_range(1000000)
    13   78.941 MiB    0.012 MiB     1000001       for my_value in my_values:
    14   78.941 MiB    0.016 MiB     1000000           my_sum += my_value

在飞行上生成值 :

def my_range(n):
    i = 0
    while i < n:
        yield i
        i += 1

@profile
def function():
    my_sum = 0
    
    for my_value in my_range(1000000):
        my_sum += my_value

function()

结果有:

Total time: 1.24841 s
Timer unit: 1e-06 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     7                                           @profile
     8                                           def function():
     9         1          1.1      1.1      0.0      my_sum = 0
    10
    11   1000001     895617.3      0.9     71.7      for my_value in my_range(1000000):
    12   1000000     352793.7      0.4     28.3          my_sum += my_value



Line #    Mem usage    Increment  Occurences   Line Contents
============================================================
     7   40.168 MiB   40.168 MiB           1   @profile
     8                                         def function():
     9   40.168 MiB    0.000 MiB           1       my_sum = 0
    10
    11   40.203 MiB    0.016 MiB     1000001       for my_value in my_range(1000000):
    12   40.203 MiB    0.020 MiB     1000000           my_sum += my_value

摘要摘要摘要

生成器函数需要稍多一点时间来执行, 而不是返回列表但少用内存的函数 。

也可以将数据发送回生成器!

事实上,正如这里许多答案所解释的,使用yield创建 a 创建generator.

您可以使用yield关键字到将数据发送回“ 实时” 生成器.

示例:

假设我们有一种方法可以从英语翻译成其他语言。 在开始的时候, 它会做一些很重的事情, 应该做一次。 我们希望这个方法可以永远运行( 不知道为什么..... . :) , 并且收到要翻译的单词 。

def translator():
    # load all the words in English language and the translation to 'other lang'
    my_words_dict = {'hello': 'hello in other language', 'dog': 'dog in other language'}

    while True:
        word = (yield)
        yield my_words_dict.get(word, 'Unknown word...')

运行中 :

my_words_translator = translator()

next(my_words_translator)
print(my_words_translator.send('dog'))

next(my_words_translator)
print(my_words_translator.send('cat'))

将打印 :

dog in other language
Unknown word...

概括如下:

使用send生成器内的方法将数据发送回生成器。如果允许, a(yield)使用。