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, candida

在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库。这是指向完整源代码的链接:。

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

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


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

它返回一个生成器。我对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
这更有意义还是让你更困惑


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

要理解
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执行第二次
,因为生成器只能使用一次:它们计算0,然后忘记它并计算1,然后逐个结束计算4

产量
yield
是一个与
return
类似的关键字,函数将返回生成器

>>> def create_generator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = create_generator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object create_generator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4
来电者:

但在您的代码中,它有一个生成器,这很好,因为:

  • 您不需要读取两次值
  • 你可能有很多孩子,你不想把他们都存储在内存中
  • 这是因为Python不关心方法的参数是否是列表。Python需要iterables,因此它可以处理字符串、列表、元组和生成器!这就是所谓的duck类型,也是Python如此酷的原因之一。但这是另一个故事,另一个问题

    您可以停在这里,或稍微阅读一下,了解发电机的高级用途:

    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)
    
    控制发电机耗尽 理解迭代的内在机制 迭代是一个包含可重用(实现
    \uu iter\uuuuuuuuuuuuuuuuu()
    方法)和迭代器(实现
    \uuuuuuuuuuuuuuuuuuuuu()
    方法)的过程。 Iterables是可以从中获取迭代器的任何对象。迭代器是允许您在iterables上进行迭代的对象


    这篇文章中有更多关于它的内容。

    这里是一个简单语言的示例。我将提供高级人员概念与低级Python概念之间的对应关系

    我想对数字序列进行运算,但我不想为序列的创建而烦恼,我只想专注于我想做的运算。因此,我做了以下工作:

    • 我打电话给你,告诉你我想要一个以特定方式产生的数字序列,然后我告诉你算法是什么
      此步骤对应于发电机功能,即功能c
      >>> 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)]
      
      for item in sequence:
      
      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);
      
      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]