在大部分情况下range和xrange的用法是一样的。用来生成一个list 供我们使用。区别是range返回的是一个list 而xrange返回的是一个 generator.
>>> range(5)
[0, 1, 2, 3, 4]
>>> xrange(5)
xrange(5)
Generator
为了解释Generator必须先解释一个概念: 可迭代(Iterate)
当你建立了一个list 你就可以调用里面的每一个元素,这个list就称为可迭代对象。
所有可以使用 for .. in .. 语法的脚注一个迭代器: list string 等等
Generator 是可以迭代的,但是只能读取一次因为他并不是把所有的值都存在内存中而是实时的生成数据。由于generator 并不是把值存在一个很长的list或者其他迭代器里面,这样使用generator可以减少内存的消耗。
>>> for i in mygenerator:
... print i
...
0
1
4
>>> for i in mygenerator:
... print i
...
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print i
...
0
1
4
>>> for i in mygenerator:
... print i
... \
...
Yield 为python中的一个比较高级的用法最近在一次某传统IT公司的面试中就被问到了此问题,可惜当时对这一无所知。
yield 的作用类似return 但是yield返回的是个generator.需要注意的是在如果一个function的返回使用yield,在调用此function时 在function里面的code并没有被执行,而是返回一个generator。
当我们是用for 对generator进行迭代时 从函数开始到yield之前的code都会被run到并返回第一个值,下面的循环以此类推,直到没有可返回的值迭代退出。
在使用yield返回的generator 对象时也可以使用generator 的next()方法,函数执行结束时,generator 自动抛出 StopIteration 异常,表示迭代完成。在 for 循环里,无需处理 StopIteration 异常,循环会正常结束。
Yield 在openstack 的heat代码中使用比较广泛.
下面是得到一个stack中所有resource 的code,通过yield返回一个generator(heat/engine/stack.py)
def iter_resources(self, nested_depth=0):
'''
Iterates over all the resources in a stack, including nested stacks up
to `nested_depth` levels below.
'''
for res in six.itervalues(self):
yield res
get_nested = getattr(res, 'nested', None)
if not callable(get_nested) or nested_depth == 0:
continue
nested_stack = get_nested()
if nested_stack is None:
continue
for nested_res in nested_stack.iter_resources(nested_depth - 1):
yield nested_res
对其的迭代过程(heat/engine/service)通过for 对其迭代:
def list_stack_resources(self, cnxt, stack_identity, nested_depth=0):
s = self._get_stack(cnxt, stack_identity, show_deleted=True)
stack = parser.Stack.load(cnxt, stack=s)
depth = min(nested_depth, cfg.CONF.max_nested_stack_depth)
return [api.format_stack_resource(resource, detail=False)
for resource in stack.iter_resources(depth)]