当我们创建了一个列表后,你就可以一个接一个地读取元素。这样一个接一个地读取元素就叫做iteration:
>>> mylist = [1, 2, 3] >>> for i in mylist: ... print(i) 1 2 3mylist是一个iterable.但你使用一个列表,你创建了一个列表,也就是一个iterable:
>>> mylist = [x*x for x in range(3)] >>> for i in mylist: ... print(i) 0 1 4任何你可以使用“for....in....”都是一个iterable:列表,字符串,文件等等都是
这些iterable是非常方便的,因为你可以读取你想读取的任意多的数据,但是你把它们的值都存储在了内存中,但有很多只的时候这可能就不是你想要的结果了。
>>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ... print(i) 0 1 4这和上面的例子是一样,除了这次你用了(),上面用的是[]。但是,你不可以第二次去执行for i in mygenerator,因为generators只能使用一次:它计算了0,然后丢掉它去计算1,直到计算了4,一个接一个地。
>>> def createGenerator(): ... mylist = range(3) ... for i in mylist: ... yield i*i ... >>> mygenerator = createGenerator() # create a generator >>> print(mygenerator) # mygenerator is an object! <generator object createGenerator at 0xb7555c34> >>> for i in mygenerator: ... print(i) 0 1 4这里是一个没什么用的例子,但是当你知道你的函数会返回巨大的一堆数据,而你只需要读取它们一次时,它是很方便的。
为了掌握yield,你必须知道当你调用一个函数,你写在函数体里的代码并没有执行。这个函数仅仅是返回了一个generator对象,这是有一点小技巧的。
然后,你的代码将会在每一次用for使用generator的时候被执行。
现在是比较难的部分:
当for第一次调用从你函数中创建的generator对象时,它会从开始执行函数中的代码直到它遇到yield,然后它会返回这个循环的第一个值。然后,每一次其它的调用将会再一次执行你写在函数中的循环,并且返回下一个值,直到没有值可以返回为止。
generator会被认为是空的一旦你的函数运行的时候没有再遇到yield。这可能是因为循环已经到了终点,或者是你并没有再满足“if/else”.
# 这里你创建了一个node对象的方法,这个方法将返回一个generator def node._get_child_candidates(self, distance, min_dist, max_dist): # 这里是每一次你使用generator对象时会调用的代码: # If there is still a child of the node object on its left # AND if distance is ok, return the next child if self._leftchild and distance - max_dist < self._median: yield self._leftchild # If there is still a child of the node object on its right # AND if distance is ok, return the next child if self._rightchild and distance + max_dist >= self._median: yield self._rightchild # If the function arrives here, the generator will be considered empty # there is no more than two values: the left and the right children
# Create an empty list and a list with the current object reference result, candidates = list(), [self] # Loop on candidates (they contain only one element at the beginning) while candidates: # Get the last candidate and remove it from the list node = candidates.pop() # Get the distance between obj and the candidate distance = node._get_dist(obj) # If distance is ok, then you can fill the result if distance <= max_dist and distance >= min_dist: result.extend(node._values) # Add the children of the candidate in the candidates list # so the loop will keep running until it will have looked # at all the children of the children of the children, etc. of the candidate candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) return result
>>> a = [1, 2] >>> b = [3, 4] >>> a.extend(b) >>> print(a) [1, 2, 3, 4]但是你的代码中它取得了一个generator,这是好的,因为:
>>> class Bank(): # let's create a bank, building ATMs ... crisis = False ... def create_atm(self): ... while not self.crisis: ... yield "$100" >>> hsbc = Bank() # when everything's ok the ATM gives you as much as you want >>> 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 # crisis is coming, no more money! >>> print(corner_street_atm.next()) <type 'exceptions.StopIteration'> >>> wall_street_atm = hsbc.create_atm() # it's even true for new ATMs >>> print(wall_street_atm.next()) <type 'exceptions.StopIteration'> >>> hsbc.crisis = False # trouble is, even post-crisis the ATM remains empty >>> print(corner_street_atm.next()) <type 'exceptions.StopIteration'> >>> brand_new_atm = hsbc.create_atm() # build a new one to get back in business >>> for cash in brand_new_atm: ... print cash $100 $100 $100 $100 $100 $100 $100 $100 $100 ...这对于各种事情比如控制访问资源是很有用的。
一个例子?让我们看一个四匹马可能的到达顺序:
>>> 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)]