当前位置: 首页 > 面试题库 >

在python 3中的函数中创建动态命名的变量/在python 3中了解exec / eval / locals

龙珂
2023-03-14
问题内容

首先,我要说的是,我阅读了许多与创建动态命名变量类似的主题,但是它们大多与Python 2有关,或者假定您正在使用类。是的,我阅读了Python
2和Python 3中exec函数的行为

我也知道在99%的时间里创建动态命名的变量是一个坏主意,而字典是获得的方法,但是我只想知道是否仍然可行,以及exec和locals在python
3中的工作原理。

我想显示一些示例代码来说明我的问题(斐波纳契计算斐波纳契数,ListOfLetters提供[“ A”,“ B”,…]):

def functionname():
    for index, buchstabe in enumerate(ListOfLetters.create_list("A", "K"), 1): 
        exec("{} = {}".format(buchstabe, fibonacci(index)) ) #A = 1, B = 1, C = 2, D = 3, E = 5,...
        print(index, buchstabe, eval(buchstabe)) #works nicely, e.g. prints "4 D 3"
    print(locals()) #pritns all locals: {'B': 1, 'A': 1, 'index': 11, 'C': 2, 'H': 21, 'K': 89, ...
    print(locals()['K']) #prints 89 as it should
    print(eval("K")) #prints 89 as it should
    print(K) #NameError: name 'K' is not defined

因此,至少就我目前的理解而言,的行为存在一些不一致之处locals(),因为它包含所添加的变量名,exec()但该变量在函数中不可用。

如果有人可以解释一下并告诉您这是设计使然还是语言中确实存在不一致之处,我将不胜感激。是的,我知道locals不应该修改它,但是我没有修改它,我在打电话给exec()


问题答案:

当您不确定某个东西为什么能在Python中正常工作时,它通常可以帮助将您困惑的行为放入函数中,然后使用该dis模块将其从Python字节码中分解出来。

让我们从一个简单的代码版本开始:

def foo():
    exec("K = 89")
    print(K)

如果运行foo(),您将得到与更复杂的函数相同的异常:

>>> foo()
Traceback (most recent call last):
  File "<pyshell#167>", line 1, in <module>
    foo()
  File "<pyshell#166>", line 3, in foo
    print(K)
NameError: name 'K' is not defined

让我们分解一下,看看为什么:

>>> import dis
>>> dis.dis(foo)
  2           0 LOAD_GLOBAL              0 (exec)
              3 LOAD_CONST               1 ('K = 89')
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 POP_TOP

  3          10 LOAD_GLOBAL              1 (print)
             13 LOAD_GLOBAL              2 (K)
             16 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             19 POP_TOP
             20 LOAD_CONST               0 (None)
             23 RETURN_VALUE

您需要注意的操作是标为“
13”的操作。这是编译器K在函数的最后一行(print(K))中查找的地方。它使用的LOAD_GLOBAL操作码失败,因为“
K”不是全局变量名称,而是它在我们的locals()字典中的值(由exec调用添加)。

如果我们说服编译器将其K视为局部变量(在运行之前为其提供值exec),那么它将知道不寻找不存在的全局变量怎么办?

def bar():
    K = None
    exec("K = 89")
    print(K)

如果运行该函数,将不会出现错误,但不会输出期望值:

>>> bar()
None

让我们分解一下原因:

>>> dis.dis(bar)
  2           0 LOAD_CONST               0 (None)
              3 STORE_FAST               0 (K)

  3           6 LOAD_GLOBAL              0 (exec)
              9 LOAD_CONST               1 ('K = 89')
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             15 POP_TOP

  4          16 LOAD_GLOBAL              1 (print)
             19 LOAD_FAST                0 (K)
             22 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             25 POP_TOP
             26 LOAD_CONST               0 (None)
             29 RETURN_VALUE

注意在“ 3”和“
19”处使用的操作码。Python编译器使用STORE_FASTLOAD_FAST将局部变量的值K放入插槽0,然后将其取回。使用编号的插槽比从像这样的字典中插入和获取值的速度要快得多locals(),这就是Python编译器为函数中的所有局部变量访问而这样做的原因。您不能通过修改返回的字典来覆盖插槽中的局部变量locals()exec如果您不将其传递给它的命名空间的字典,也一样)。

确实,让我们尝试函数的第三个版本,locals当我们将K其定义为常规局部变量时,可以再次浏览:

def baz():
    K = None
    exec("K = 89")
    print(locals())

89这次您也不会在输出中看到!

>>> baz()
{"K": None}

函数文档中解释了您看到旧K值的原因:locals()

更新并返回代表当前本地符号表的字典。

该语句K未更改存储本地变量值的插槽,该exec语句仅修改locals()字典。locals()再次调用时,Python使用插槽中的值“更新”字典,用替换存储在其中的值exec

这就是为什么文档继续说:

注意: 此字典的内容不得修改;更改可能不会影响解释器使用的局部变量和自由变量的值。

您的exec呼叫正在修改locals()字典,并且您发现以后的代码并不总是看到其更改。



 类似资料:
  • Python3 内置函数 描述 exec 执行储存在字符串或文件中的 Python 语句,相比于 eval,exec可以执行更复杂的 Python 代码。 语法 以下是 exec 的语法: exec(object[, globals[, locals]]) 参数 object:必选参数,表示需要被指定的Python代码。它必须是字符串或code对象。如果object是一个字符串,该字符串会先被

  • 我正在用android创建一款纸牌游戏(21点)。前两张卡是easy card1和card2,但是我想按一下“点击我”按钮,发一张新卡,并将其分配给card3、card4等。有没有任何方法可以做到这一点,而无需创建所需的最大变量数,并使用if-then语句检查它们是否被分配了值?

  • 我正在将java脚本移动到dart,在java脚本中我创建了动态变量,例如 我怎么能用飞镖呢?

  • 问题内容: 我制作了一个便签程序,可以帮助您学习JavaFX。它通过XML保存该类,并在启动时查找XML文件,并将其添加到名为AllCards的NoteCardSet类型的ArrayList,即NoteCards的ArrayList。有了这个,我制作了许多动态按钮,使它们宽了4列。这是该代码: 显然,这可以在JavaFX中创建,但是可以在FXML中创建吗? 问题答案: 不,您不能在FXML中执行此

  • 本文向大家介绍JS使用eval()动态创建变量的方法,包括了JS使用eval()动态创建变量的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了JS使用eval()动态创建变量的方法。分享给大家供大家参考,具体如下: 一、什么是eval()函数? eval_r()函数可计算某个字符串,并执行其中的的 JavaScript 代码。 二、如何动态定义变量? 既然eval()能够计算字符串,何

  • 本文向大家介绍在SAP ABAP中创建具有动态变量类型的变量,包括了在SAP ABAP中创建具有动态变量类型的变量的使用技巧和注意事项,需要的朋友参考一下 您可以使用与RTTS相关的API来创建一个标准表(例如RANGE),该表具有类似“ LOW”,“ HIGH”,“ EQ”和“ OPTION”的组件 场符号