SystemError when defining

Joshua Landau joshua.landau.ws at gmail.com
Fri Nov 4 15:10:00 EDT 2011


>
> >>> 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?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20111104/520e349d/attachment-0001.html>


More information about the Python-list mailing list