Python 什么是;“收益率”;你要做什么?

Python 什么是;“收益率”;你要做什么?,python,iterator,generator,yield,coroutine,Python,Iterator,Generator,Yield,Coroutine,在Python中,yield关键字有什么用途?它有什么作用 例如,我试图理解以下代码1: >>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ... print(i) 0 1 4 def\u获取子对象(自我、距离、最小距离、最大距离): 如果self.\u leftchild和距离-最大距离=self.\u中间值: 屈服于自己 这是来电者: result, candi

在Python中,
yield
关键字有什么用途?它有什么作用

例如,我试图理解以下代码1

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4
def\u获取子对象(自我、距离、最小距离、最大距离):
如果self.\u leftchild和距离-最大距离=self.\u中间值:
屈服于自己
这是来电者:

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
result,候选者=[],[self]
而候选人:
node=candidates.pop()
距离=节点。获取距离(obj)
如果距离=最小距离:
结果.扩展(节点。\u值)
扩展(节点获取子候选对象(距离、最小距离、最大距离))
返回结果
调用方法
\u get\u child\u candidates
时会发生什么? 是否返回列表?单一元素?又叫了吗?后续通话何时停止



1.这段代码是由Jochen Schulz(jrschulz)编写的,他为度量空间创建了一个很棒的Python库。这是指向完整源代码:[Module mspace][1]的链接。
yield
就像
return
-它返回您告诉它的任何内容(作为生成器)。不同之处在于,下次调用生成器时,执行从上次调用
yield
语句开始。与return不同,当发生屈服时,堆栈帧不会被清除,但是控制权会被转移回调用方,因此下次调用函数时,其状态将恢复。

对于您的代码,函数
get_child_candidates
的作用类似于迭代器,因此当您扩展列表时,它会一次向新列表添加一个元素


list.extend
调用迭代器,直到迭代器耗尽。对于您发布的代码示例,只返回一个元组并将其附加到列表中会更清楚。

yield
就像
return
——它返回您告诉它的任何内容(作为生成器)。不同之处在于,下次调用生成器时,执行从上次调用
yield
语句开始。与return不同,当发生屈服时,堆栈帧不会被清除,但是控制权会被转移回调用方,因此下次调用函数时,其状态将恢复。

对于您的代码,函数
get_child_candidates
的作用类似于迭代器,因此当您扩展列表时,它会一次向新列表添加一个元素


list.extend
调用迭代器,直到迭代器耗尽。对于您发布的代码示例,只返回一个元组并将其附加到列表中会更清楚。

它返回一个生成器。我对Python不是特别熟悉,但我相信这与您熟悉Python是一样的


关键思想是编译器/解释器/任何东西都会做一些诡计,以便对调用方而言,它们可以继续调用next(),并且它将继续返回值,就像生成器方法被暂停一样。现在很明显,你不能真正“暂停”一个方法,所以编译器会为你建立一个状态机,让你记住你现在在哪里,以及局部变量是什么样子。这比自己编写迭代器容易得多。

它返回一个生成器。我对Python不是特别熟悉,但我相信这与您熟悉Python是一样的

关键思想是编译器/解释器/任何东西都会做一些诡计,以便对调用方而言,它们可以继续调用next(),并且它将继续返回值,就像生成器方法被暂停一样。现在很明显,你不能真正“暂停”一个方法,所以编译器会为你建立一个状态机,让你记住你现在在哪里,以及局部变量是什么样子。这比自己编写迭代器要容易得多。

这样想:

迭代器只是具有
next()
方法的对象的一个听起来很奇特的术语。所以一个屈服函数最终是这样的:

def fib():
    last, cur = 0, 1
    while True: 
        yield cur
        last, cur = cur, last + cur
for f in fib():
    if some_condition: break
    coolfuncs(f);
>>> isinstance(gen, types.GeneratorType)
True
>>> isinstance(gen, collections.Iterator)
True
原文:

def some_function():
    for i in xrange(4):
        yield i

for i in some_function():
    print i
这基本上就是Python解释器对上述代码所做的:

class it:
    def __init__(self):
        # Start at -1 so that we get 0 when we add 1 below.
        self.count = -1

    # The __iter__ method will be called once by the 'for' loop.
    # The rest of the magic happens on the object returned by this method.
    # In this case it is the object itself.
    def __iter__(self):
        return self

    # The next method will be called repeatedly by the 'for' loop
    # until it raises StopIteration.
    def next(self):
        self.count += 1
        if self.count < 4:
            return self.count
        else:
            # A StopIteration exception is raised
            # to signal that the iterator is done.
            # This is caught implicitly by the 'for' loop.
            raise StopIteration

def some_func():
    return it()

for i in some_func():
    print i
这更有意义还是让你更困惑

我应该注意到,出于说明的目的,这是一种过于简单的说法。:)

这样想:

迭代器只是具有
next()
方法的对象的一个听起来很奇特的术语。所以一个屈服函数最终是这样的:

def fib():
    last, cur = 0, 1
    while True: 
        yield cur
        last, cur = cur, last + cur
for f in fib():
    if some_condition: break
    coolfuncs(f);
>>> isinstance(gen, types.GeneratorType)
True
>>> isinstance(gen, collections.Iterator)
True
原文:

def some_function():
    for i in xrange(4):
        yield i

for i in some_function():
    print i
这基本上就是Python解释器对上述代码所做的:

class it:
    def __init__(self):
        # Start at -1 so that we get 0 when we add 1 below.
        self.count = -1

    # The __iter__ method will be called once by the 'for' loop.
    # The rest of the magic happens on the object returned by this method.
    # In this case it is the object itself.
    def __iter__(self):
        return self

    # The next method will be called repeatedly by the 'for' loop
    # until it raises StopIteration.
    def next(self):
        self.count += 1
        if self.count < 4:
            return self.count
        else:
            # A StopIteration exception is raised
            # to signal that the iterator is done.
            # This is caught implicitly by the 'for' loop.
            raise StopIteration

def some_func():
    return it()

for i in some_func():
    print i
这更有意义还是让你更困惑


我应该注意到,出于说明的目的,这是一种过于简单的说法。:)

要理解
yield
的功能,您必须了解生成器是什么。在你能理解发电机之前,你必须先理解易逝性

易怒 创建列表时,可以逐个读取其项。逐项读取其项目称为迭代:

>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3
mylist
是一个iterable。当您使用列表理解时,您会创建一个列表,从而创建一个iterable:

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4
>>> list(makeRange(5))
[0, 1, 2, 3, 4]
您可以在上使用“
for…in…
”的所有内容都是可编辑的<代码>列表,
字符串
,文件

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

发电机 生成器是迭代器,一种iterable,您只能迭代一次。生成器不会将所有值存储在内存中,而是动态生成值:

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4
除了您使用了
()
而不是
[]
之外,它是一样的。但是,您不能在mygenerator中为i执行
for f in fib():
    if some_condition: break
    coolfuncs(f);
for x in mylist:
    ...loop body...
def f123():
    yield 1
    yield 2
    yield 3

for item in f123():
    print item
generator = myYieldingFunction(...)
x = list(generator)

   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

list==[x[0], x[1], x[2]]
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(makeRange(5))
[0, 1, 2, 3, 4]
# list-version                   #  # generator-version
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  ## indented
    return TO_RETURN             #>

>>> makeRange(5)
[0, 1, 2, 3, 4]
#                   _ITERABLE_
>>> [x+10 for x in makeRange(5)]
[10, 11, 12, 13, 14]
>>> x=iter(range(5))
>>> next(x)
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
> x = myRange(5)
> list(x)
[0, 1, 2, 3, 4]
> list(x)
[]
from itertools import islice

def fib_gen():
    a, b = 1, 1
    while True:
        yield a
        a, b = b, a + b

assert [1, 1, 2, 3, 5] == list(islice(fib_gen(), 5))
def ftake(fnext, last):
    return [fnext() for _ in xrange(last)]

def fib_gen2():
    #funky scope due to python2.x workaround
    #for python 3.x use nonlocal
    def _():
        _.a, _.b = _.b, _.a + _.b
        return _.a
    _.a, _.b = 0, 1
    return _

assert [1,1,2,3,5] == ftake(fib_gen2(), 5)
class fib_gen3:
    def __init__(self):
        self.a, self.b = 1, 1

    def __call__(self):
        r = self.a
        self.a, self.b = self.b, self.a + self.b
        return r

assert [1,1,2,3,5] == ftake(fib_gen3(), 5)
def get_odd_numbers(i):
    return range(1, i, 2)
def yield_odd_numbers(i):
    for x in range(1, i, 2):
       yield x
foo = get_odd_numbers(10)
bar = yield_odd_numbers(10)
foo
[1, 3, 5, 7, 9]
bar
<generator object yield_odd_numbers at 0x1029c6f50>
bar.next()
1
bar.next()
3
bar.next()
5
>>> def f():
...   yield 1
...   yield 2
...   yield 3
... 
>>> g = f()
>>> for i in g:
...   print(i)
... 
1
2
3
>>> for i in g:
...   print(i)
... 
>>> # Note that this time nothing was printed
def save_file(filename):
  def write_file_continuation():
    write_stuff_to_file(filename)

  check_if_file_exists_and_user_wants_to_overwrite(write_file_continuation)
def f():
  while True:
    yield 4
class Generator():
  def __init__(self,iterable,generatorfun):
    self.next_continuation = lambda:generatorfun(iterable)

  def next(self):
    value, next_continuation = self.next_continuation()
    self.next_continuation = next_continuation
    return value
def generatorfun(iterable):
  if len(iterable) == 0:
    raise StopIteration
  else:
    return (iterable[0], lambda:generatorfun(iterable[1:]))
def normalFunction():
    return
    if False:
        pass

def yielderFunction():
    return
    if False:
        yield 12
>>> yielderFunction()
<generator object yielderFunction at 0x07742D28>
>>> gen = yielderFunction()
>>> dir(gen)
['__class__',
 ...
 '__iter__',    #Returns gen itself, to make it work uniformly with containers
 ...            #when given to a for loop. (Containers return an iterator instead.)
 'close',
 'gi_code',
 'gi_frame',
 'gi_running',
 'next',        #The method that runs the function's body.
 'send',
 'throw']
Welcome to Racket v6.5.0.3.

-> (define gen
     (lambda (l)
       (define yield
         (lambda ()
           (if (null? l)
               'END
               (let ((v (car l)))
                 (set! l (cdr l))
                 v))))
       (lambda(m)
         (case m
           ('yield (yield))
           ('init  (lambda (data)
                     (set! l data)
                     'OK))))))
-> (define stream (gen '(1 2 3)))
-> (stream 'yield)
1
-> (stream 'yield)
2
-> (stream 'yield)
3
-> (stream 'yield)
'END
-> ((stream 'init) '(a b))
'OK
-> (stream 'yield)
'a
-> (stream 'yield)
'b
-> (stream 'yield)
'END
-> (stream 'yield)
'END
->
def isPrimeNumber(n):
    print "isPrimeNumber({}) call".format(n)
    if n==1:
        return False
    for x in range(2,n):
        if n % x == 0:
            return False
    return True

def primes (n=1):
    while(True):
        print "loop step ---------------- {}".format(n)
        if isPrimeNumber(n): yield n
        n += 1

for n in primes():
    if n> 10:break
    print "wiriting result {}".format(n)
loop step ---------------- 1
isPrimeNumber(1) call
loop step ---------------- 2
isPrimeNumber(2) call
loop step ---------------- 3
isPrimeNumber(3) call
wiriting result 3
loop step ---------------- 4
isPrimeNumber(4) call
loop step ---------------- 5
isPrimeNumber(5) call
wiriting result 5
loop step ---------------- 6
isPrimeNumber(6) call
loop step ---------------- 7
isPrimeNumber(7) call
wiriting result 7
loop step ---------------- 8
isPrimeNumber(8) call
loop step ---------------- 9
isPrimeNumber(9) call
loop step ---------------- 10
isPrimeNumber(10) call
loop step ---------------- 11
isPrimeNumber(11) call
>>> def coroutine():
...     i = -1
...     while True:
...         i += 1
...         val = (yield i)
...         print("Received %s" % val)
...
>>> sequence = coroutine()
>>> sequence.next()
0
>>> sequence.next()
Received None
1
>>> sequence.send('hello')
Received hello
2
>>> sequence.close()
yield from <expr>
async def new_coroutine(data):
   ...
   await blocking_action()
>>> def func():
...     yield 'I am'
...     yield 'a generator!'
... 
>>> type(func)                 # A function with yield is still a function
<type 'function'>
>>> gen = func()
>>> type(gen)                  # but it returns a generator
<type 'generator'>
>>> hasattr(gen, '__iter__')   # that's an iterable
True
>>> hasattr(gen, 'next')       # and with .next (.__next__ in Python 3)
True                           # implements the iterator protocol.
>>> import collections, types
>>> issubclass(types.GeneratorType, collections.Iterator)
True
>>> isinstance(gen, types.GeneratorType)
True
>>> isinstance(gen, collections.Iterator)
True
>>> list(gen)
['I am', 'a generator!']
>>> list(gen)
[]
>>> list(func())
['I am', 'a generator!']
def func(an_iterable):
    for item in an_iterable:
        yield item
def func(an_iterable):
    yield from an_iterable
def bank_account(deposited, interest_rate):
    while True:
        calculated_interest = interest_rate * deposited 
        received = yield calculated_interest
        if received:
            deposited += received


>>> my_account = bank_account(1000, .05)
>>> first_year_interest = next(my_account)
>>> first_year_interest
50.0
>>> next_year_interest = my_account.send(first_year_interest + 1000)
>>> next_year_interest
102.5
expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
                     ('=' (yield_expr|testlist_star_expr))*)
...
yield_expr: 'yield' [yield_arg]
yield_arg: 'from' test | testlist
def getNextLines():
   while con.isOpen():
       yield con.read()
for line in getNextLines():
    doSomeThing(line)
def simpleYield():
    yield "first time"
    yield "second time"
    yield "third time"
    yield "Now some useful value {}".format(12)

for i in simpleYield():
    print i
"first time"
"second time"
"third time"
"Now some useful value 12"
def square_list(n):
    the_list = []                         # Replace
    for x in range(n):
        y = x * x
        the_list.append(y)                # these
    return the_list                       # lines
def square_yield(n):
    for x in range(n):
        y = x * x
        yield y                           # with this one.
>>> for square in square_list(4):
...     print(square)
...
0
1
4
9
>>> for square in square_yield(4):
...     print(square)
...
0
1
4
9
>>> def squares_all_of_them():
...     x = 0
...     while True:
...         yield x * x
...         x += 1
...
>>> squares = squares_all_of_them()
>>> for _ in range(4):
...     print(next(squares))
...
0
1
4
9
>>> list(square_yield(4))
[0, 1, 4, 9]
import random

def return_dates():
    dates = [] # With 'return' you need to create a list then return it
    for i in range(5):
        date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"])
        dates.append(date)
    return dates
def yield_dates():
    for i in range(5):
        date = random.choice(["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th"])
        yield date # 'yield' makes a generator automatically which works
                   # in a similar way. This is much more efficient.
dates_list = return_dates()
print(dates_list)
for i in dates_list:
    print(i)

dates_generator = yield_dates()
print(dates_generator)
for i in dates_generator:
    print(i)
def simple_generator():
    yield 'one'
    yield 'two'
    yield 'three'

for i in simple_generator():
    print i
one
two
three
def myRangeNaive(i):
    n = 0
    range = []
    while n < i:
        range.append(n)
        n = n + 1
    return range
for i in myRangeNaive(10):
    print i
def myRangeSmart(i):
    n = 0
    while n < i:
       yield n
       n = n + 1
    return

for i in myRangeSmart(10):
    print i
def f123():
    for _ in range(4):
        yield 1
        yield 2


for i in f123():
    print (i)
1 2 1 2 1 2 1 2
def num_list(n):
    for i in range(n):
        return i
In [5]: num_list(3)
Out[5]: 0
In [10]: def num_list(n):
    ...:     for i in range(n):
    ...:         yield i
    ...:

In [11]: num_list(3)
Out[11]: <generator object num_list at 0x10327c990>

In [12]: list(num_list(3))
Out[12]: [0, 1, 2]
In [15]: def num_list(n):
    ...:     result = []
    ...:     for i in range(n):
    ...:         result.append(i)
    ...:     return result

In [16]: num_list(3)
Out[16]: [0, 1, 2]