`exec`-based routine crashes app upon migration from 3.4.3 to python 3.5.2.

eryk sun eryksun at gmail.com
Thu Jul 28 17:18:45 EDT 2016


On Thu, Jul 28, 2016 at 6:40 PM, Chris Angelico <rosuav at gmail.com> wrote:
> On Fri, Jul 29, 2016 at 1:47 AM, Enjoys Math <enjoysmath at gmail.com> wrote:
>> I've manually set breakpoints and traced this app crash back to this
>> function:
>>
>>     def loadLSobjsOfType(self, objType, listJ):
>>         if listJ != None:
>>             for objJ in listJ:
>>                 _locals = locals()
>>                 exec('obj = ' + objType + '(self)', None, _locals)
>>                 obj = _locals['obj']
>>                 obj.loadJson(objJ)
>>                 self.addLSobjOfType(objType, obj)
>>
>> when breakpoints are set on `obj=_locals['obj']` my wingware debugger kicks
>> in and throws a KeyError exeption.
>>
>> So what's the proper way to get the return value of an exec call when there
>> is one?
>
> (Side point: Be aware that it's perfectly legal for a Python
> interpreter to make mutations to locals() actually significant. You're
> safe here, but just make sure that can't ever bite you.)
>
> By the look of things, you're executing code using a locals but no
> globals, and it's executing code at the global scope. Can you simply
> remove the 'None' parameter, and thus make _locals be the exec'd
> code's locals AND globals both?

Passing `None` for the globals parameter executes the code using the
current globals(). This is pointless since the OP could just use
exec() without passing either globals or locals to use the current
globals and locals dicts.

exec() compiles code like a module, so assignment uses the STORE_NAME
instruction unless the name is declared `global`. STORE_NAME sets the
value in the frame's f_locals dict. That much is fine with the OP's
code, so on the surface I don't see the problem here. For example:

    class C:
        def method(self):
            exec('obj = int(self)')
            return locals()['obj']
        def __int__(self):
            return 42

    >>> C().method()
    42



More information about the Python-list mailing list