yield关键字的使用
先来段最简单的代码:
def iter():
for i in range(10):
yield i
调用这个方法:
>>>check_iter = iter()
>>>dir(check_iter)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__
reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
可以看到有一个next属性,调用之
>>> check_iter.next()
0
>>> check_iter.next()
1
>>> check_iter.next()
2
>>> check_iter.next()
会发现check_iter通过next()会逐渐的返回原来iter函数的值,而不是像return 那样直接返回一个list给调用处,那么这里有人就定义yield这里的作用是生成器了!
深度研究,以python中自带的UserDict模块下的DictMixin作为研究对象,研究yield关键字的用法
class DictMixin:
# Mixin defining all dictionary methods for classes that already have
# a minimum dictionary interface including getitem, setitem, delitem,
# and keys. Without knowledge of the subclass constructor, the mixin
# does not define __init__() or copy(). In addition to the four base
# methods, progressively more efficiency comes with defining
# __contains__(), __iter__(), and iteritems().
# second level definitions support higher levels
def __iter__(self):
for k in self.keys():
yield k
def has_key(self, key):
try:
value = self[key]
except KeyError:
return False
return True
def __contains__(self, key):
return self.has_key(key)
# third level takes advantage of second level definitions
def iteritems(self):
for k in self:
yield (k, self[k])
def iterkeys(self):
return self.__iter__()
# fourth level uses definitions from lower levels
def itervalues(self):
for _, v in self.iteritems():
yield v
def values(self):
return [v for _, v in self.iteritems()]
def items(self):
return list(self.iteritems())
def clear(self):
for key in self.keys():
del self[key]
def setdefault(self, key, default=None):
try:
return self[key]
except KeyError:
self[key] = default
return default
def pop(self, key, *args):
if len(args) > 1:
raise TypeError, "pop expected at most 2 arguments, got "\
+ repr(1 + len(args))
try:
value = self[key]
except KeyError:
if args:
return args[0]
raise
del self[key]
return value
def popitem(self):
try:
k, v = self.iteritems().next()
except StopIteration:
raise KeyError, 'container is empty'
del self[k]
return (k, v)
def update(self, other=None, **kwargs):
# Make progressively weaker assumptions about "other"
if other is None:
pass
elif hasattr(other, 'iteritems'): # iteritems saves memory and lookups
for k, v in other.iteritems():
self[k] = v
elif hasattr(other, 'keys'):
for k in other.keys():
self[k] = other[k]
else:
for k, v in other:
self[k] = v
if kwargs:
self.update(kwargs)
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
def __repr__(self):
return repr(dict(self.iteritems()))
def __cmp__(self, other):
if other is None:
return 1
if isinstance(other, DictMixin):
other = dict(other.iteritems())
return cmp(dict(self.iteritems()), other)
def __len__(self):
return len(self.keys())
关于此类,大家可以从注释中看到“Mixin类定义了所有的字典方法,前提是要有一个字典接口,包括getitem,setitem,delitem,和key”,揣测下要有key值,即必须是{"key" : "value"}这种类型,必须有一个元素,如果不对,欢迎拍砖。因为学习的过程就是体会错误的过程。我们看到有一个__iter__内置方法有yield关键字.也就是说这里是一个生产器,在其他地方,也就是调用处调用这个方法的时候,会使用到与之相关的next()方法
>>> a = {'hello' : 'world'}
>>> a = {'hello' : 'world', '你好' : '世界'}
>>> id(a.iterkeys())
11284272
>>> id(a.iterkeys())
11284224
>>> id(a.iterkeys())
11284272
>>> id(a.iterkeys())
11284224
你可以看到这里是通过调用iterkeys()方法,然后掉用内置方法__iter__,获得的key值的内存地址,如果你仍然纠结并没有显式看到next方法,那么,别急,在看这个源码的其他地方:
在iteritems方法中有一个yield关键字:
def iteritems(self):
for k in self:
yield (k, self[k])
偶调用他的地方是:
def popitem(self):
try:
k, v = self.iteritems().next()
except StopIteration:
raise KeyError, 'container is empty'
del self[k]
return (k, v)
iteritems方法返回一个tuple类型的值,请你清楚,tuple是以","作为标志的,而不是"()",所以 python会有return a,b这种return语句出现的,而实际上在很多计算机语言是不允许返回多个值的。其实python也一样!那么这里通过 yield返回了一个tuple,即key和value对应的tuple,而现在想得到下一个,next()就在这里出现了。