1

please read the two code ,and i find the only different is printing the locals() or not. But one of them is wrong. Please help me , thanks

import numpy as np

class Solution:
    def solve(self, f, a, b, n):
        x = np.linspace(a,b,n)
        # print(locals())
        loc = locals()
        fstr = '''
def fun(x):
    return %s
        ''' % f
        exec(fstr)
        # print(locals())
        fun  = loc['fun']
        y = fun(x)
        print(x,y,sep = '\n')

a = Solution()
a.solve('x+1',-5,5,5)

In this code ,I didn't print the locals()

if I only print it and write '#' in front of "fun = loc['fun']" and "y = fun(x)" ,there is a key named 'fun' in the output of locals()

import numpy as np

class Solution:
    def solve(self, f, a, b, n):
        x = np.linspace(a,b,n)
        # print(locals())
        loc = locals()
        fstr = '''
def fun(x):
    return %s
        ''' % f
        exec(fstr)
        print(locals())
        fun  = loc['fun']
        y = fun(x)
        print(x,y,sep = '\n')

a = Solution()
a.solve('x+1',-5,5,5)

But in this code ,i can't find the key named 'fun' in the output of locals()

Traceback (most recent call last):
  File "tmp.py", line 20, in <module>
    a.solve('x+1',-5,5,5)
  File "tmp.py", line 15, in solve
    fun  = loc['fun']
KeyError: 'fun'

All of this seem that "fun = loc['fun']" and "y = fun(x)" determine the output of locals()

but i think it is impossible for python that latter code can change the front code

YJSchaf
  • 13
  • 2
  • This Question is a possible duplicate of this [link](https://stackoverflow.com/questions/7969949/whats-the-difference-between-globals-locals-and-vars). please check that! – McLovin Dec 10 '19 at 09:23

1 Answers1

5

Yeah, that happens with locals(). locals() is confusing and not well documented.

Calling locals() repeatedly in the same stack frame returns the same dict every time, and every call to locals() updates that dict with the current values of local (or closure) variables. The dict is attached to the stack frame as its f_locals attribute, and accessing that attribute will also update the dict.

To use locals() safely without the values changing unpredictably, you should copy the returned dict:

current_locals = locals().copy()

Otherwise, even running your code in a debugger could change its behavior, since debuggers typically access f_locals to inspect local variables.


Also, trying to exec code that assigns any variables in a local scope is officially unsupported and behaves weirdly, and def counts as an assignment. You shouldn't use exec for this anyway.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Thanks your answer! Would you mean that use locals() may change the value of itself ? But if i change the code "fun = loc['fun']" and "y = fun(x)" to "funn = loc['fun']" and "y = funn(x)" ,which mean i change the name of the function , it can run.Could tell me why? – YJSchaf Dec 10 '19 at 10:21
  • @YJSchaf: Python no longer has an empty "real" `fun` variable to copy the non-value over the `'fun'` entry in `locals()` once you change that. – user2357112 Dec 10 '19 at 11:16
  • As you say , when I want to change the value of fun , 'fun' in locals() was changed earlier. But if i write 'k = copy.deepcopy(locals()['fun']) ' and 'fun = k' , it still is error. I am confused that I have copied the locals()['fun'] to a new address, and the change of 'fun' will not change the value of k, but it still error. I print(id(k)) and print(id(locals()['fun'])) then find that they are same ! Does copy.deepcopy not work? – YJSchaf Dec 10 '19 at 13:43
  • I know that using exce() and locals() is not supported. But I really want to try to use exec to write a subfunction in a function such that this subfunction can be called in the function instead of everywhere. I don't know how to write it. Could you tell me a batter mothed without using locals() to approach that? PS : please forgive my poor English , which sometimes I may misunderstand your mean :P – YJSchaf Dec 10 '19 at 13:44