| from test.test_support import verify, TestFailed |
| |
| print "1. simple nesting" |
| |
| def make_adder(x): |
| def adder(y): |
| return x + y |
| return adder |
| |
| inc = make_adder(1) |
| plus10 = make_adder(10) |
| |
| verify(inc(1) == 2) |
| verify(plus10(-2) == 8) |
| |
| print "2. extra nesting" |
| |
| def make_adder2(x): |
| def extra(): # check freevars passing through non-use scopes |
| def adder(y): |
| return x + y |
| return adder |
| return extra() |
| |
| inc = make_adder2(1) |
| plus10 = make_adder2(10) |
| |
| verify(inc(1) == 2) |
| verify(plus10(-2) == 8) |
| |
| print "3. simple nesting + rebinding" |
| |
| def make_adder3(x): |
| def adder(y): |
| return x + y |
| x = x + 1 # check tracking of assignment to x in defining scope |
| return adder |
| |
| inc = make_adder3(0) |
| plus10 = make_adder3(9) |
| |
| verify(inc(1) == 2) |
| verify(plus10(-2) == 8) |
| |
| print "4. nesting with global but no free" |
| |
| def make_adder4(): # XXX add exta level of indirection |
| def nest(): |
| def nest(): |
| def adder(y): |
| return global_x + y # check that plain old globals work |
| return adder |
| return nest() |
| return nest() |
| |
| global_x = 1 |
| adder = make_adder4() |
| verify(adder(1) == 2) |
| |
| global_x = 10 |
| verify(adder(-2) == 8) |
| |
| print "5. nesting through class" |
| |
| def make_adder5(x): |
| class Adder: |
| def __call__(self, y): |
| return x + y |
| return Adder() |
| |
| inc = make_adder5(1) |
| plus10 = make_adder5(10) |
| |
| verify(inc(1) == 2) |
| verify(plus10(-2) == 8) |
| |
| print "6. nesting plus free ref to global" |
| |
| def make_adder6(x): |
| global global_nest_x |
| def adder(y): |
| return global_nest_x + y |
| global_nest_x = x |
| return adder |
| |
| inc = make_adder6(1) |
| plus10 = make_adder6(10) |
| |
| verify(inc(1) == 11) # there's only one global |
| verify(plus10(-2) == 8) |
| |
| print "7. nearest enclosing scope" |
| |
| def f(x): |
| def g(y): |
| x = 42 # check that this masks binding in f() |
| def h(z): |
| return x + z |
| return h |
| return g(2) |
| |
| test_func = f(10) |
| verify(test_func(5) == 47) |
| |
| print "8. mixed freevars and cellvars" |
| |
| def identity(x): |
| return x |
| |
| def f(x, y, z): |
| def g(a, b, c): |
| a = a + x # 3 |
| def h(): |
| # z * (4 + 9) |
| # 3 * 13 |
| return identity(z * (b + y)) |
| y = c + z # 9 |
| return h |
| return g |
| |
| g = f(1, 2, 3) |
| h = g(2, 4, 6) |
| verify(h() == 39) |
| |
| print "9. free variable in method" |
| |
| def test(): |
| method_and_var = "var" |
| class Test: |
| def method_and_var(self): |
| return "method" |
| def test(self): |
| return method_and_var |
| def actual_global(self): |
| return str("global") |
| def str(self): |
| return str(self) |
| return Test() |
| |
| t = test() |
| verify(t.test() == "var") |
| verify(t.method_and_var() == "method") |
| verify(t.actual_global() == "global") |
| |
| method_and_var = "var" |
| class Test: |
| # this class is not nested, so the rules are different |
| def method_and_var(self): |
| return "method" |
| def test(self): |
| return method_and_var |
| def actual_global(self): |
| return str("global") |
| def str(self): |
| return str(self) |
| |
| t = Test() |
| verify(t.test() == "var") |
| verify(t.method_and_var() == "method") |
| verify(t.actual_global() == "global") |
| |
| print "10. recursion" |
| |
| def f(x): |
| def fact(n): |
| if n == 0: |
| return 1 |
| else: |
| return n * fact(n - 1) |
| if x >= 0: |
| return fact(x) |
| else: |
| raise ValueError, "x must be >= 0" |
| |
| verify(f(6) == 720) |
| |
| |
| print "11. unoptimized namespaces" |
| |
| def check_syntax(s): |
| try: |
| compile(s, '?', 'exec') |
| except SyntaxError: |
| pass |
| else: |
| raise TestFailed |
| |
| # XXX for now, it is easiest to call this a syntax error: |
| # explicit is better than implicit... |
| test1 = \ |
| """def unoptimized_clash1(strip): |
| def f(s): |
| from string import * |
| return strip(s) # ambiguity: free or local |
| return f |
| """ |
| check_syntax(test1) |
| |
| # a little harder to reject this one, but possible... |
| test2 = \ |
| """def unoptimized_clash2(): |
| from string import * |
| def f(s): |
| return strip(s) # ambiguity: global or local |
| return f |
| """ |
| # check_syntax(test2) |
| |
| # XXX could allow this for exec with const argument, but what's the point |
| test3 = \ |
| """def error(y): |
| exec "a = 1" |
| def f(x): |
| return x + y |
| return f |
| """ |
| check_syntax(test3) |
| |
| test4 = \ |
| """def f(x): |
| def g(): |
| return x |
| del x |
| """ |
| check_syntax(test4) |
| |
| print "12. lambdas" |
| |
| f1 = lambda x: lambda y: x + y |
| inc = f1(1) |
| plus10 = f1(10) |
| verify(inc(1) == 2) |
| verify(plus10(5) == 15) |
| |
| f2 = lambda x: (lambda : lambda y: x + y)() |
| inc = f2(1) |
| plus10 = f2(10) |
| verify(inc(1) == 2) |
| verify(plus10(5) == 15) |
| |
| f3 = lambda x: lambda y: global_x + y |
| global_x = 1 |
| inc = f3(None) |
| verify(inc(2) == 3) |
| |
| f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y) |
| g = f8(1, 2, 3) |
| h = g(2, 4, 6) |
| verify(h() == 18) |
| |
| print "13. UnboundLocal" |
| |
| def errorInOuter(): |
| print y |
| def inner(): |
| return y |
| y = 1 |
| |
| def errorInInner(): |
| def inner(): |
| return y |
| inner() |
| y = 1 |
| |
| try: |
| errorInOuter() |
| except UnboundLocalError: |
| pass |
| else: |
| raise TestFailed |
| |
| try: |
| errorInInner() |
| except UnboundLocalError: |
| pass |
| else: |
| raise TestFailed |