diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-01-25 20:11:23 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-01-25 20:11:23 (GMT) |
commit | 4588c78fafd569deb21b1a721a8507636a507837 (patch) | |
tree | 0da0ac42b584300348e12c9083ccba40e6912b36 | |
parent | 5e2d0764cd95b40de64fff54e14091e0e6bdf6f6 (diff) | |
download | cpython-4588c78fafd569deb21b1a721a8507636a507837.zip cpython-4588c78fafd569deb21b1a721a8507636a507837.tar.gz cpython-4588c78fafd569deb21b1a721a8507636a507837.tar.bz2 |
PEP 227 implementation
New tests cases for nested scopes.
-rw-r--r-- | Lib/test/output/test_scope | 13 | ||||
-rw-r--r-- | Lib/test/test_scope.py | 249 |
2 files changed, 262 insertions, 0 deletions
diff --git a/Lib/test/output/test_scope b/Lib/test/output/test_scope new file mode 100644 index 0000000..3ada943 --- /dev/null +++ b/Lib/test/output/test_scope @@ -0,0 +1,13 @@ +test_scope +1. simple nesting +2. extra nesting +3. simple nesting + rebinding +4. nesting with global but no free +5. nesting through class +6. nesting plus free ref to global +7. nearest enclosing scope +8. mixed freevars and cellvars +9. free variable in method +10. recursion +11. unoptimized namespaces +12. lambdas diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py new file mode 100644 index 0000000..c566301 --- /dev/null +++ b/Lib/test/test_scope.py @@ -0,0 +1,249 @@ +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) == 2) +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) |