Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Dev

effect of "exec" on local scope

 

 

Python dev RSS feed   Index | Next | Previous | View Threaded


metawilm at gmail

Oct 8, 2008, 10:53 AM

Post #1 of 6 (278 views)
Permalink
effect of "exec" on local scope

The issue came up while trying to get some Sympy code running on CLPython.

class C:
exec "a = 3"
print locals()

1. Is it guaranteed that class C gets an attribute "a", i.e. that the
locals printed include {'a': 3}?
2. It it (also) guaranteed if it were in a function scope?

The complete syntax of exec is:
exec CODE in Y, Z
where Y, Z are optional.

The documentation of "exec" says "if the optional parts are
omitted,the code is executed in the current scope." There are at least
two different interpretations:

a. The code is executed in the current class scope, so the assignment
must have an effect on the class scope.

b. The scope defaults to the local scope, by which is meant the
mapping returned by locals(), and of locals() the documentation says
that changes made to it may not influence the interpreter. (The
documentation of exec suggests using globals() and locals() as
arguments to exec, which seems hint at this interpretation.)

The relevant documentation:
exec: http://docs.python.org/reference/simple_stmts.html#grammar-token-exec_stmt
locals: http://docs.python.org/library/functions.html#locals

- Willem
_______________________________________________
Python-Dev mailing list
Python-Dev[at]python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


tjreedy at udel

Oct 8, 2008, 12:17 PM

Post #2 of 6 (271 views)
Permalink
Re: effect of "exec" on local scope [In reply to]

Willem Broekema wrote:
> The issue came up while trying to get some Sympy code running on CLPython.
>
> class C:
> exec "a = 3"
> print locals()
>
> 1. Is it guaranteed that class C gets an attribute "a", i.e. that the
> locals printed include {'a': 3}?
> 2. It it (also) guaranteed if it were in a function scope?
>
> The complete syntax of exec is:
> exec CODE in Y, Z
> where Y, Z are optional.
>
> The documentation of "exec" says "if the optional parts are
> omitted,the code is executed in the current scope." There are at least
> two different interpretations:
>
> a. The code is executed in the current class scope, so the assignment
> must have an effect on the class scope.
>
> b. The scope defaults to the local scope, by which is meant the
> mapping returned by locals(), and of locals() the documentation says
> that changes made to it may not influence the interpreter. (The
> documentation of exec suggests using globals() and locals() as
> arguments to exec, which seems hint at this interpretation.)
>
> The relevant documentation:
> exec: http://docs.python.org/reference/simple_stmts.html#grammar-token-exec_stmt
> locals: http://docs.python.org/library/functions.html#locals

The 3.0 doc for exec() has this warning:
"Warning
The default locals act as described for function locals() below:
modifications to the default locals dictionary should not be attempted.
Pass an explicit locals dictionary if you need to see effects of the
code on locals after function exec() returns."

This implies interpretation b.

However, is spite of the warning, class locals is a dict and locals() is
that dict, so a is available for further use in class code.

So the answer to question 1 for current CPython is yes.

Whether that is guaranteed for all implementations and versions is
another story.

Functions are much trickier. The local namespace is not a dict, and
modifying the locals() dict does not modify the namespace. The answer
to 2. is No, not even now.

>>> def f():
exec('a=3')
print(locals())
return a

>>> f()
{'a': 3}
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
f()
File "<pyshell#36>", line 4, in f
return a
NameError: global name 'a' is not defined

But why then is 'a' printed in the second call to locals (the implied
one in exec being the first)? It appears that a function or code object
can have only only one repeatedly used shadow dict. The 3.0 (and 2.5)
doc says "locals()
Update and return a dictionary representing the current local symbol
table." Note "update"; I had missed that before. To see this...

>>> def g():
a = locals()
b = locals()
return id(a), id(b), a,b

>>> g()
(20622048, 20622048, {'a': {...}}, {'a': {...}})

Inserting "print(a['a'])" between the locals calls raises KeyError.

Terry Jan Reedy


_______________________________________________
Python-Dev mailing list
Python-Dev[at]python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


ondrej at certik

Oct 8, 2008, 4:40 PM

Post #3 of 6 (265 views)
Permalink
Re: effect of "exec" on local scope [In reply to]

Hi Terry,

On Wed, Oct 8, 2008 at 9:17 PM, Terry Reedy <tjreedy[at]udel.edu> wrote:
> Willem Broekema wrote:
>>
>> The issue came up while trying to get some Sympy code running on CLPython.
>>
>> class C:
>> exec "a = 3"
>> print locals()
>>
>> 1. Is it guaranteed that class C gets an attribute "a", i.e. that the
>> locals printed include {'a': 3}?
>> 2. It it (also) guaranteed if it were in a function scope?
>>
>> The complete syntax of exec is:
>> exec CODE in Y, Z
>> where Y, Z are optional.
>>
>> The documentation of "exec" says "if the optional parts are
>> omitted,the code is executed in the current scope." There are at least
>> two different interpretations:
>>
>> a. The code is executed in the current class scope, so the assignment
>> must have an effect on the class scope.
>>
>> b. The scope defaults to the local scope, by which is meant the
>> mapping returned by locals(), and of locals() the documentation says
>> that changes made to it may not influence the interpreter. (The
>> documentation of exec suggests using globals() and locals() as
>> arguments to exec, which seems hint at this interpretation.)
>>
>> The relevant documentation:
>> exec:
>> http://docs.python.org/reference/simple_stmts.html#grammar-token-exec_stmt
>> locals: http://docs.python.org/library/functions.html#locals
>
> The 3.0 doc for exec() has this warning:
> "Warning
> The default locals act as described for function locals() below:
> modifications to the default locals dictionary should not be attempted. Pass
> an explicit locals dictionary if you need to see effects of the code on
> locals after function exec() returns."
>
> This implies interpretation b.
>
> However, is spite of the warning, class locals is a dict and locals() is
> that dict, so a is available for further use in class code.
>
> So the answer to question 1 for current CPython is yes.
>
> Whether that is guaranteed for all implementations and versions is another
> story.
>
> Functions are much trickier. The local namespace is not a dict, and
> modifying the locals() dict does not modify the namespace. The answer to 2.
> is No, not even now.
>
>>>> def f():
> exec('a=3')
> print(locals())
> return a
>
>>>> f()
> {'a': 3}
> Traceback (most recent call last):
> File "<pyshell#37>", line 1, in <module>
> f()
> File "<pyshell#36>", line 4, in f
> return a
> NameError: global name 'a' is not defined
>
> But why then is 'a' printed in the second call to locals (the implied one in
> exec being the first)? It appears that a function or code object can have
> only only one repeatedly used shadow dict. The 3.0 (and 2.5) doc says
> "locals()
> Update and return a dictionary representing the current local symbol table."
> Note "update"; I had missed that before. To see this...
>
>>>> def g():
> a = locals()
> b = locals()
> return id(a), id(b), a,b
>
>>>> g()
> (20622048, 20622048, {'a': {...}}, {'a': {...}})
>
> Inserting "print(a['a'])" between the locals calls raises KeyError.


Thanks very much for the thorough answer. The reason for Willem's
question is this code that we currently have in sympy (see [1] for the
whole thread):

class Basic(AssumeMeths):
...
for k in AssumeMeths._assume_defined:
exec "is_%s = property(make__get_assumption('Basic', '%s'))" % (k,k)


Which works in CPython but fails in CLPython. From your answer it
seems to me that this code is not nice and we should not use it and
should rather use something like:

class Basic(AssumeMeths):
...

for k in AssumeMeths._assume_defined:
setattr(Basic, 'is_%s' % k, property(make__get_assumption('Basic', '%s' % k)))


which should work on all platforms. What do you think?

Ondrej

[1] http://code.google.com/p/sympy/issues/detail?id=1134
_______________________________________________
Python-Dev mailing list
Python-Dev[at]python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


guido at python

Oct 8, 2008, 6:02 PM

Post #4 of 6 (265 views)
Permalink
Re: effect of "exec" on local scope [In reply to]

Well, I don't recall what CLPython is, but I believe it is broken and
that code should work -- there are (or used to be) examples of using
exec to populate classes in the standard library so while it may look
dodgy it really is exected to work...

On Wed, Oct 8, 2008 at 4:40 PM, Ondrej Certik <ondrej[at]certik.cz> wrote:
> Hi Terry,
>
> On Wed, Oct 8, 2008 at 9:17 PM, Terry Reedy <tjreedy[at]udel.edu> wrote:
>> Willem Broekema wrote:
>>>
>>> The issue came up while trying to get some Sympy code running on CLPython.
>>>
>>> class C:
>>> exec "a = 3"
>>> print locals()
>>>
>>> 1. Is it guaranteed that class C gets an attribute "a", i.e. that the
>>> locals printed include {'a': 3}?
>>> 2. It it (also) guaranteed if it were in a function scope?
>>>
>>> The complete syntax of exec is:
>>> exec CODE in Y, Z
>>> where Y, Z are optional.
>>>
>>> The documentation of "exec" says "if the optional parts are
>>> omitted,the code is executed in the current scope." There are at least
>>> two different interpretations:
>>>
>>> a. The code is executed in the current class scope, so the assignment
>>> must have an effect on the class scope.
>>>
>>> b. The scope defaults to the local scope, by which is meant the
>>> mapping returned by locals(), and of locals() the documentation says
>>> that changes made to it may not influence the interpreter. (The
>>> documentation of exec suggests using globals() and locals() as
>>> arguments to exec, which seems hint at this interpretation.)
>>>
>>> The relevant documentation:
>>> exec:
>>> http://docs.python.org/reference/simple_stmts.html#grammar-token-exec_stmt
>>> locals: http://docs.python.org/library/functions.html#locals
>>
>> The 3.0 doc for exec() has this warning:
>> "Warning
>> The default locals act as described for function locals() below:
>> modifications to the default locals dictionary should not be attempted. Pass
>> an explicit locals dictionary if you need to see effects of the code on
>> locals after function exec() returns."
>>
>> This implies interpretation b.
>>
>> However, is spite of the warning, class locals is a dict and locals() is
>> that dict, so a is available for further use in class code.
>>
>> So the answer to question 1 for current CPython is yes.
>>
>> Whether that is guaranteed for all implementations and versions is another
>> story.
>>
>> Functions are much trickier. The local namespace is not a dict, and
>> modifying the locals() dict does not modify the namespace. The answer to 2.
>> is No, not even now.
>>
>>>>> def f():
>> exec('a=3')
>> print(locals())
>> return a
>>
>>>>> f()
>> {'a': 3}
>> Traceback (most recent call last):
>> File "<pyshell#37>", line 1, in <module>
>> f()
>> File "<pyshell#36>", line 4, in f
>> return a
>> NameError: global name 'a' is not defined
>>
>> But why then is 'a' printed in the second call to locals (the implied one in
>> exec being the first)? It appears that a function or code object can have
>> only only one repeatedly used shadow dict. The 3.0 (and 2.5) doc says
>> "locals()
>> Update and return a dictionary representing the current local symbol table."
>> Note "update"; I had missed that before. To see this...
>>
>>>>> def g():
>> a = locals()
>> b = locals()
>> return id(a), id(b), a,b
>>
>>>>> g()
>> (20622048, 20622048, {'a': {...}}, {'a': {...}})
>>
>> Inserting "print(a['a'])" between the locals calls raises KeyError.
>
>
> Thanks very much for the thorough answer. The reason for Willem's
> question is this code that we currently have in sympy (see [1] for the
> whole thread):
>
> class Basic(AssumeMeths):
> ...
> for k in AssumeMeths._assume_defined:
> exec "is_%s = property(make__get_assumption('Basic', '%s'))" % (k,k)
>
>
> Which works in CPython but fails in CLPython. From your answer it
> seems to me that this code is not nice and we should not use it and
> should rather use something like:
>
> class Basic(AssumeMeths):
> ...
>
> for k in AssumeMeths._assume_defined:
> setattr(Basic, 'is_%s' % k, property(make__get_assumption('Basic', '%s' % k)))
>
>
> which should work on all platforms. What do you think?
>
> Ondrej
>
> [1] http://code.google.com/p/sympy/issues/detail?id=1134
> _______________________________________________
> Python-Dev mailing list
> Python-Dev[at]python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
>



--
--Guido van Rossum (home page: http://www.python.org/~guido/)
_______________________________________________
Python-Dev mailing list
Python-Dev[at]python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


tjreedy at udel

Oct 8, 2008, 8:18 PM

Post #5 of 6 (260 views)
Permalink
Re: effect of "exec" on local scope [In reply to]

Ondrej Certik wrote:

> Which works in CPython but fails in CLPython. From your answer it
> seems to me that this code is not nice and we should not use it and
> should rather use something like:
>
> class Basic(AssumeMeths):
> ...
>
> for k in AssumeMeths._assume_defined:
> setattr(Basic, 'is_%s' % k, property(make__get_assumption('Basic', '%s' % k)))
>
> which should work on all platforms. What do you think?

That is what setattr is for. Many consider exec a last resort. I think
any further discussion should move to the general python list or c.l.p
since this is not a develop-core-python issue.

_______________________________________________
Python-Dev mailing list
Python-Dev[at]python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


ncoghlan at gmail

Oct 9, 2008, 4:27 AM

Post #6 of 6 (247 views)
Permalink
Re: effect of "exec" on local scope [In reply to]

Guido van Rossum wrote:
> Well, I don't recall what CLPython is, but I believe it is broken and
> that code should work -- there are (or used to be) examples of using
> exec to populate classes in the standard library so while it may look
> dodgy it really is exected to work...

I think this behaviour (modifying locals() at class scope) was actually
implicitly blessed in PEP 3115, even though that PEP doesn't explicitly
state locals() in a class body is required to grant access to the
namespace returned by __prepare__().

Perhaps the time is right for the locals() documentation to be more
explicit regarding when modifying its contents will affect the current
namespace?
- yes at module scope (effectively the same as globals())
- yes at class scope
- maybe (but typically not) at function scope

Cheers,
Nick.

--
Nick Coghlan | ncoghlan[at]gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://www.boredomandlaziness.org
_______________________________________________
Python-Dev mailing list
Python-Dev[at]python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com

Python dev RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact lists@gossamer-threads.com
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.