mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			277 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 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
 | 
