[Python-ideas] Unpack of sequences

M.-A. Lemburg mal at egenix.com
Thu Aug 30 09:51:21 CEST 2012


Guido van Rossum wrote:
> On Wed, Aug 29, 2012 at 12:30 PM, M.-A. Lemburg <mal at egenix.com> wrote:
>> Guido van Rossum wrote:
>>> Also it won't work in Python 3.
>>
>> The star import is only used to trigger a call to PyFrame_LocalsToFast().
>>
>> In Python 3, the only way to trigger such a call is by using
>> a call level trace function... or by exposing the C function
>> in Python.
> 
> I don't believe that's the whole story. In Python 2, the import *
> changes the semantics of locals. (So does 'exec' BTW.) Example:
> 
>>>> def f():
> ...  if 0: from test import *
> ...  locals()['x'] = 1
> ...  print(x)
> ...
> <stdin>:1: SyntaxWarning: import * only allowed at module level
>>>> def g():
> ...  locals()['x'] = 1
> ...  print(x)
> ...
>>>> f()
> 1
>>>> g()
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 3, in g
> NameError: global name 'x' is not defined
>>>>
> 
> Note the difference in generated bytecode:
> 
>>>> dis.dis(f)
>   3           0 LOAD_CONST               1 (1)
>               3 LOAD_NAME                0 (locals)
>               6 CALL_FUNCTION            0
>               9 LOAD_CONST               2 ('x')
>              12 STORE_SUBSCR
> 
>   4          13 LOAD_NAME                1 (x)
>              16 PRINT_ITEM
>              17 PRINT_NEWLINE
>              18 LOAD_CONST               0 (None)
>              21 RETURN_VALUE
>>>> dis.dis(g)
>   2           0 LOAD_CONST               1 (1)
>               3 LOAD_GLOBAL              0 (locals)
>               6 CALL_FUNCTION            0
>               9 LOAD_CONST               2 ('x')
>              12 STORE_SUBSCR
> 
>   3          13 LOAD_GLOBAL              1 (x)
>              16 PRINT_ITEM
>              17 PRINT_NEWLINE
>              18 LOAD_CONST               0 (None)
>              21 RETURN_VALUE
>>>>
> 
> Compare line 13 in both: LOAD_NAME vs. LOAD_GLOBAL. Effectively, in
> f(), the locals are dynamic (this is how they were implemented in
> Python 0.0). In g() they are not, so the compiler decides that x can't
> be a local, and generates a LOAD_GLOBAL.

You're right. The effect is not the calling of the PyFrame
function, but that of the compiler generating different bytecode
with the star import.

In fact, the way the star import calls the PyFrame API overrides the
locals update. It first copies the fast locals to the locals dictionary
(overriding the updates applied before the import),
then adds the symbols from the import and then copies the locals
from the dictionary back to the fast slots.

Here's a version that uses fast locals a,b,c:

def h(d):
    a = 0
    b = 0
    c = 0
    locals().update(d)
    from test import *
    print a,b,c

It prints 0 0 0. The dis output:

 20           0 LOAD_CONST               1 (0)
              3 STORE_FAST               1 (a)

 21           6 LOAD_CONST               1 (0)
              9 STORE_FAST               2 (b)

 22          12 LOAD_CONST               1 (0)
             15 STORE_FAST               3 (c)

 23          18 LOAD_NAME                0 (locals)
             21 CALL_FUNCTION            0
             24 LOAD_ATTR                1 (update)
             27 LOAD_FAST                0 (d)
             30 CALL_FUNCTION            1
             33 POP_TOP

 24          34 LOAD_CONST               2 (-1)
             37 LOAD_CONST               3 (('*',))
             40 IMPORT_NAME              2 (test)
             43 IMPORT_STAR

 25          44 LOAD_FAST                1 (a)
             47 PRINT_ITEM
             48 LOAD_FAST                2 (b)
             51 PRINT_ITEM
             52 LOAD_FAST                3 (c)
             55 PRINT_ITEM
             56 PRINT_NEWLINE
             57 LOAD_CONST               0 (None)
             60 RETURN_VALUE

> In Python 3, all functions behave like g(): import * is no longer
> allowed, and exec() is no longer treated special (it's no longer a
> reserved keyword).

That's good. I don't think that any of this is really needed in Python.

-- 
Marc-Andre Lemburg
eGenix.com

Professional Python Services directly from the Source  (#1, Aug 30 2012)
>>> Python/Zope Consulting and Support ...        http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ...             http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/
________________________________________________________________________
2012-10-23: Python Meeting Duesseldorf ...                 54 days to go
2012-08-28: Released mxODBC 3.2.0 ...             http://egenix.com/go31
2012-08-20: Released mxODBC.Connect 2.0.0 ...     http://egenix.com/go30

::: Try our new mxODBC.Connect Python Database Interface for free ! ::::


   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
    D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
           Registered at Amtsgericht Duesseldorf: HRB 46611
               http://www.egenix.com/company/contact/



More information about the Python-ideas mailing list