> > >>> def x(nonlocal_var): ... def y():
... z = lambda *, keyword_only=nonlocal_var: None ... return y ... >>> x(None)() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in y SystemError: no locals when loading 'nonlocal_var' >>> dis.dis(x) 2 0 LOAD_CONST 1 (<code object y at > 0x7f1fa5d57030, file "<stdin>", line 2>) 3 MAKE_FUNCTION 0 6 STORE_FAST 1 (y) > 4 9 LOAD_FAST 1 (y) 12 RETURN_VALUE >>> dis.dis(x(None)) 3 0 LOAD_CONST 1 ('keyword_only') 3 LOAD_NAME 0 (nonlocal_var) 6 LOAD_CONST 2 (<code object <lambda> at > 0x7f1fa626aa48, file "<stdin>", line 3>) 9 MAKE_FUNCTION 256 12 STORE_FAST 0 (z) 15 LOAD_CONST 0 (None) 18 RETURN_VALUE Conclusion: When setting defaults to keyword-only arguments in lambdas which are inside non-global scopes, cPython is unable to access *either the free variables or global scope* and raises SystemError. This is cool, though: > >>> def y(): > ... global_var > ... z = lambda *, keyword_only=global_var: None > ... > >>> y() > >>> >>> dis.dis(y) > 2 0 LOAD_GLOBAL 0 (global_var) > 3 POP_TOP > 3 4 LOAD_CONST 1 ('keyword_only') > 7 LOAD_GLOBAL 0 (global_var) > 10 LOAD_CONST 2 (<code object <lambda> at > 0x7f1fa5d4fd78, file "<stdin>", line 3>) > 13 MAKE_FUNCTION 256 > 16 STORE_FAST 0 (z) > 19 LOAD_CONST 0 (None) > 22 RETURN_VALUE >>> def x(nonlocal_var): > ... def y(): > ... nonlocal_var > ... z = lambda *, keyword_only=nonlocal_var: None > ... return y > ... > >>> x(None)() > >>> What is happening is that LOAD_NAME is trying to access the value 'nonlocal_var' from y.__code__.co_freevars, but compilation doesn't push it there from the lambda, so adding a call to it causes it to work. The change of opcode implies that locality is decided before the opcodes are made, and so not being pushed to co_freevars changes the opcode. AKA: *When setting defaults to keyword-only arguments in lambdas which are inside non-global scopes, cPython doesn't push the name to co_freevars.* Now - where shall I report this?
-- http://mail.python.org/mailman/listinfo/python-list