【问题标题】:why 'exec' is behaving different inside the function?为什么'exec'在函数内部表现不同?
【发布时间】:2020-06-01 05:03:34
【问题描述】:

我的问题

我的解决方案:

import re
import math
a = input().replace("|","")
op = re.findall("[A-Z]+", a)[0]
a = list(map(float,re.split(r'P|S|M|D',a)))
expressions = {'P':'str(a[0]+a[1])','S':'str(a[0]-a[1])','M':'str(a[0]*a[1])','D':'str(a[0]/a[1])'}
exec('ex = eval(expressions[op])+"0"') 
ex = ex[:ex.find(".")+3][::-1]
l = [6]
l.extend([6+3*x for x in range(1,(len(ex)-6)//2+1)])
if ex[-1]=="-":
    l.pop()
for i in l:
    ex = ex[:i] + "|" + ex[i:] 
ex = ex[::-1] 
ex = "0"+ex.strip("|") if ex.find("|")==1 else ex.strip("|")
print(ex)

问题:

如果我将此代码包装在一个接受字符串输入并尝试返回我的ex 的函数中,代码会显示错误并且没有任何更改。我的问题是,谁能解释为什么这个单独工作完美并引发错误包裹在函数中时?

【问题讨论】:

  • 你为什么不只是(字符串)在空格上分割?
  • @KlausD。我知道其他方法,我能够解决它,但我的问题与 exec 的行为不同。
  • 尝试使用eval/exec 解决这个问题是个坏主意。使用实际代码而不是exec 更容易、更易于维护和更易于理解。这将避免您的范围问题,并将帮助您避免各种“令人惊讶”的行为。
  • @JanChristophTerasa 我尽量减少代码行。
  • 在我看来,您似乎在尝试模拟 lambdas,但由于它们在 Python 中可用,您只需将 lambdas 放入您的 expressions 字典中。

标签: python python-3.x list algorithm


【解决方案1】:

这是在execs 与locals 的互动中讨论的。在global 上下文中(不在函数中)没有问题-exec 修改全局变量,您会看到结果。在函数中,执行上下文是本地函数,但exec 不能更改本地上下文。通常的解决方法是传递一个本地上下文,您可以在其中看到更改:

local_context = {}
exec('ex = eval(expressions[op])+"0"', locals(), local_context)
ex = local_context['ex']

这里,第二个参数locals() 实际上是作为“全局变量”传递给 exec 的。这就是expressionsop 这样的东西可用。在此处传递globals() 通常没有用,除非您实际使用全局变量或其他函数。

第三个参数是 exec 可以使用的本地人,以及将填充的内容。如果你传递globals() 作为第二个参数,那么通常你也想传递你打算在这里使用的局部变量。在此处传递 locals() 不会修改您的实际本地人,因此通常会更令人困惑。

注意使用

exec('global ex; ex = eval(expressions[op])+"0"')
global ex # Need this to make sure the function knows about the new global variable in its local context

将工作并创建一个具有正确内容的全局ex 变量。这就是为什么exec 可以像您期望的那样在函数外工作的原因,在全局上下文中修改当前上下文没有问题。请注意,需要告知函数本身将全局 ex 添加到其本地上下文中,因此需要两个全局变量。

请注意,如果没有给出默认值,则局部变量为 locals(),全局变量为 globals(),如果仅给出全局变量,则局部变量也将等于该值。

【讨论】:

  • 我试过exec('global ex; ex = eval(expressions[op])+"0"'),但它显示“变量在定义之前分配”的错误
  • @classicdude7 啊,我确实没有发布完整的故事。 exec 在全局上下文中创建了 ex,但函数还不知道这一点,因为函数中并没有真正调用 global ex(同样,本地上下文没有改变)。一种解决方案是如果您愿意,可以将另一个全局放在 exec 之外,尽管我不太赞成这种解决方案。我会将其编辑为答案。
  • 你能提出一个更好更简洁的解决方案吗?
  • @classicdude7 当然可以,但最好不要打乱这个 QA。问一个关于你想要什么以及你目前在做什么的新问题 (exec)。在此处评论并附上指向该链接的链接,我会看一下,尽管知道此站点,您会在我到达之前得到答复。在一行中,可能使用 Python 内置运算符库 (import operator) 并有一个字典 (operator.add, operator.truediv 等...)。可能也不需要regex
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多