test_generators.py
来自「mallet是自然语言处理、机器学习领域的一个开源项目。」· Python 代码 · 共 1,387 行 · 第 1/3 页
PY
1,387 行
from __future__ import generatorstutorial_tests = """Let's try a simple generator: >>> def f(): ... yield 1 ... yield 2 >>> for i in f(): ... print i 1 2 >>> g = f() >>> g.next() 1 >>> g.next() 2"Falling off the end" stops the generator: >>> g.next() Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in g StopIteration"return" also stops the generator: >>> def f(): ... yield 1 ... return ... yield 2 # never reached ... >>> g = f() >>> g.next() 1 >>> g.next() Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 3, in f StopIteration >>> g.next() # once stopped, can't be resumed Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration"raise StopIteration" stops the generator too: >>> def f(): ... yield 1 ... raise StopIteration ... yield 2 # never reached ... >>> g = f() >>> g.next() 1 >>> g.next() Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration >>> g.next() Traceback (most recent call last): File "<stdin>", line 1, in ? StopIterationHowever, they are not exactly equivalent: >>> def g1(): ... try: ... return ... except: ... yield 1 ... >>> list(g1()) [] >>> def g2(): ... try: ... raise StopIteration ... except: ... yield 42 >>> print list(g2()) [42]This may be surprising at first: >>> def g3(): ... try: ... return ... finally: ... yield 1 ... >>> list(g3()) [1]Let's create an alternate range() function implemented as a generator: >>> def yrange(n): ... for i in range(n): ... yield i ... >>> list(yrange(5)) [0, 1, 2, 3, 4]Generators always return to the most recent caller: >>> def creator(): ... r = yrange(5) ... print "creator", r.next() ... return r ... >>> def caller(): ... r = creator() ... for i in r: ... print "caller", i ... >>> caller() creator 0 caller 1 caller 2 caller 3 caller 4Generators can call other generators: >>> def zrange(n): ... for i in yrange(n): ... yield i ... >>> list(zrange(5)) [0, 1, 2, 3, 4]"""# The examples from PEP 255.pep_tests = """Specification: Yield Restriction: A generator cannot be resumed while it is actively running: >>> def g(): ... i = me.next() ... yield i >>> me = g() >>> me.next() Traceback (most recent call last): ... File "<string>", line 2, in g ValueError: generator already executingSpecification: Return Note that return isn't always equivalent to raising StopIteration: the difference lies in how enclosing try/except constructs are treated. For example, >>> def f1(): ... try: ... return ... except: ... yield 1 >>> print list(f1()) [] because, as in any function, return simply exits, but >>> def f2(): ... try: ... raise StopIteration ... except: ... yield 42 >>> print list(f2()) [42] because StopIteration is captured by a bare "except", as is any exception.Specification: Generators and Exception Propagation >>> def f(): ... return 1//0 >>> def g(): ... yield f() # the zero division exception propagates ... yield 42 # and we'll never get here >>> k = g() >>> k.next() Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in g File "<stdin>", line 2, in f ZeroDivisionError: integer division or modulo by zero >>> k.next() # and the generator cannot be resumed Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration >>>Specification: Try/Except/Finally >>> def f(): ... try: ... yield 1 ... try: ... yield 2 ... 1//0 ... yield 3 # never get here ... except ZeroDivisionError: ... yield 4 ... yield 5 ... raise ... except: ... yield 6 ... yield 7 # the "raise" above stops this ... except: ... yield 8 ... yield 9 ... try: ... x = 12 ... finally: ... yield 10 ... yield 11 >>> print list(f()) [1, 2, 4, 5, 8, 9, 10, 11] >>>Guido's binary tree example. >>> # A binary tree class. >>> class Tree: ... ... def __init__(self, label, left=None, right=None): ... self.label = label ... self.left = left ... self.right = right ... ... def __repr__(self, level=0, indent=" "): ... s = level*indent + `self.label` ... if self.left: ... s = s + "\\n" + self.left.__repr__(level+1, indent) ... if self.right: ... s = s + "\\n" + self.right.__repr__(level+1, indent) ... return s ... ... def __iter__(self): ... return inorder(self) >>> # Create a Tree from a list. >>> def tree(list): ... n = len(list) ... if n == 0: ... return [] ... i = n // 2 ... return Tree(list[i], tree(list[:i]), tree(list[i+1:])) >>> # Show it off: create a tree. >>> t = tree("ABCDEFGHIJKLMNOPQRSTUVWXYZ") >>> # A recursive generator that generates Tree leaves in in-order. >>> def inorder(t): ... if t: ... for x in inorder(t.left): ... yield x ... yield t.label ... for x in inorder(t.right): ... yield x >>> # Show it off: create a tree. ... t = tree("ABCDEFGHIJKLMNOPQRSTUVWXYZ") ... # Print the nodes of the tree in in-order. ... for x in t: ... print x, A B C D E F G H I J K L M N O P Q R S T U V W X Y Z >>> # A non-recursive generator. >>> def inorder(node): ... stack = [] ... while node: ... while node.left: ... stack.append(node) ... node = node.left ... yield node.label ... while not node.right: ... try: ... node = stack.pop() ... except IndexError: ... return ... yield node.label ... node = node.right >>> # Exercise the non-recursive generator. >>> for x in t: ... print x, A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"""# Examples from Iterator-List and Python-Dev and c.l.py.email_tests = """The difference between yielding None and returning it.>>> def g():... for i in range(3):... yield None... yield None... return>>> list(g())[None, None, None, None]Ensure that explicitly raising StopIteration acts like any other exceptionin try/except, not like a return.>>> def g():... yield 1... try:... raise StopIteration... except:... yield 2... yield 3>>> list(g())[1, 2, 3]Next one was posted to c.l.py.>>> def gcomb(x, k):... "Generate all combinations of k elements from list x."...... if k > len(x):... return... if k == 0:... yield []... else:... first, rest = x[0], x[1:]... # A combination does or doesn't contain first.... # If it does, the remainder is a k-1 comb of rest.... for c in gcomb(rest, k-1):... c.insert(0, first)... yield c... # If it doesn't contain first, it's a k comb of rest.... for c in gcomb(rest, k):... yield c>>> seq = range(1, 5)>>> for k in range(len(seq) + 2):... print "%d-combs of %s:" % (k, seq)... for c in gcomb(seq, k):... print " ", c0-combs of [1, 2, 3, 4]: []1-combs of [1, 2, 3, 4]: [1] [2] [3] [4]2-combs of [1, 2, 3, 4]: [1, 2] [1, 3] [1, 4] [2, 3] [2, 4] [3, 4]3-combs of [1, 2, 3, 4]: [1, 2, 3] [1, 2, 4] [1, 3, 4] [2, 3, 4]4-combs of [1, 2, 3, 4]: [1, 2, 3, 4]5-combs of [1, 2, 3, 4]:From the Iterators list, about the types of these things.>>> def g():... yield 1...>>> type(g)<type 'function'>>>> i = g()>>> type(i)<type 'generator'>>>> [s for s in dir(i) if not s.startswith('_')]['gi_frame', 'gi_running', 'next']>>> print i.next.__doc__x.next() -> the next value, or raise StopIteration>>> iter(i) is i1>>> import types>>> isinstance(i, types.GeneratorType)1And more, added later.>>> i.gi_running0>>> type(i.gi_frame)<type 'frame'>>>> i.gi_running = 42Traceback (most recent call last): ...TypeError: readonly attribute>>> def g():... yield me.gi_running>>> me = g()>>> me.gi_running0>>> me.next()1>>> me.gi_running0A clever union-find implementation from c.l.py, due to David Eppstein.Sent: Friday, June 29, 2001 12:16 PMTo: python-list@python.orgSubject: Re: PEP 255: Simple Generators>>> class disjointSet:... def __init__(self, name):... self.name = name... self.parent = None... self.generator = self.generate()...... def generate(self):... while not self.parent:... yield self... for x in self.parent.generator:... yield x...... def find(self):... return self.generator.next()...... def union(self, parent):... if self.parent:... raise ValueError("Sorry, I'm not a root!")... self.parent = parent...... def __str__(self):... return self.name>>> names = "ABCDEFGHIJKLM">>> sets = [disjointSet(name) for name in names]>>> roots = sets[:]>>> import random>>> random.seed(42)>>> while 1:... for s in sets:... print "%s->%s" % (s, s.find()),... print... if len(roots) > 1:... s1 = random.choice(roots)... roots.remove(s1)... s2 = random.choice(roots)... s1.union(s2)... print "merged", s1, "into", s2... else:... breakA->A B->B C->C D->D E->E F->F G->G H->H I->I J->J K->K L->L M->Mmerged D into G
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?