summaryrefslogtreecommitdiffstatshomepage
path: root/tests
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2022-05-03 10:38:15 +1000
committerDamien George <damien@micropython.org>2022-05-03 16:38:43 +1000
commit590de399f01cd08aa4825b26b91785e07abcf68c (patch)
treee5c2a629ec2f3d032f5d85803625ffdaf109d21e /tests
parenta21fd7cc21270c8b286129a6fe79025c57b33102 (diff)
downloadmicropython-590de399f01cd08aa4825b26b91785e07abcf68c.tar.gz
micropython-590de399f01cd08aa4825b26b91785e07abcf68c.zip
py/emitcommon: Don't implicitly close class vars that are assigned to.
When in a class body or at the module level don't implicitly close over variables that have been assigned to. Fixes issue #8603. Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/basics/scope_class.py77
1 files changed, 77 insertions, 0 deletions
diff --git a/tests/basics/scope_class.py b/tests/basics/scope_class.py
new file mode 100644
index 0000000000..9c519695dc
--- /dev/null
+++ b/tests/basics/scope_class.py
@@ -0,0 +1,77 @@
+# test scoping rules that involve a class
+
+# the inner A.method should be independent to the local function called method
+def test1():
+ def method():
+ pass
+
+ class A:
+ def method():
+ pass
+
+ print(hasattr(A, "method"))
+ print(hasattr(A(), "method"))
+
+
+test1()
+
+
+# the inner A.method is a closure and overrides the local function called method
+def test2():
+ def method():
+ return "outer"
+
+ class A:
+ nonlocal method
+
+ def method():
+ return "inner"
+
+ print(hasattr(A, "method"))
+ print(hasattr(A(), "method"))
+ return method() # this is actually A.method
+
+
+print(test2())
+
+
+# a class body will capture external variables by value (not by reference)
+def test3(x):
+ class A:
+ local = x
+
+ x += 1
+ return x, A.local
+
+
+print(test3(42))
+
+
+# assigning to a variable in a class will implicitly prevent it from closing over a variable
+def test4(global_):
+ class A:
+ local = global_ # fetches outer global_
+ global_ = "global2" # creates class attribute
+
+ global_ += 1 # updates local variable
+ return global_, A.local, A.global_
+
+
+global_ = "global"
+print(test4(42), global_)
+
+
+# methods within a class can close over variables outside the class
+def test5(x):
+ def closure():
+ return x
+
+ class A:
+ def method():
+ return x, closure()
+
+ closure = lambda: x + 1 # change it after A has been created
+ return A
+
+
+print(test5(42).method())