将字典加载到本地范围的方法之间的差异[重复]

Posted

技术标签:

【中文标题】将字典加载到本地范围的方法之间的差异[重复]【英文标题】:Differences between methods for loading a dictionary into the local scope [duplicate] 【发布时间】:2019-12-08 01:20:20 【问题描述】:

在我们的代码中有一个地方,我们必须将字典的内容加载到本地范围的变量中。我知道这通常不是一个好主意,但是.. 原因。

在对类似问题 (Python: load variables in a dict into namespace) 的各种回答中,似乎有几种方法可以做到这一点,我想知道以下两种方法之间是否存在显着差异。

(注意,我只关注将键值对直接加载到本地范围的答案,而不是将它们加载到命名空间或类似对象的方法)

 

the_dict = 'x': 1', 'y': 'foo'

 

方法一:

for k, v in the_dict.items():
    exec('k = v'.format(k=k))

 

方法二:

locals().update(the_dict)

 

最后一种方法似乎最简单,但我不确定是否有任何我没有看到的问题或陷阱。字典的值可以是任意类型,包括异常等对象。

如果相关,这是针对 Python 2.7

【问题讨论】:

方法 2 更安全,而且几乎可以肯定更快(因为 update() 或多或少是一个原子操作,因此减少了完整 for 循环的开销以及执行时间exec 函数)。 与您链接到的问题中的pointed out 一样,方法2 does not work at all。方法 1 是更新函数局部变量的唯一方法(尽管它丑陋且缓慢)。但即使这样也只能在 Python 2 中使用,因为 exec 在 Python 3 中不再是一个语句。所以,由于这个问题没有问任何以前没有回答过的问题,它看起来应该作为一个副本关闭。 【参考方案1】:

正如您所说,这不仅是一个坏主意 - 它在 Python 中根本行不通。 至少对于“本地”意味着函数范围的“本地范围”来说不是。

TL;DR:如果您的“本地范围”是**模块范围,只需更新 locals() 就足够了。如果您的“本地范围”是一个功能块,更新locals() 通常对于动态创建局部变量是没有用的。然而,在 Python 2 中,在函数体中使用 exec 将禁用快速局部优化,并且使用的字节码操作将是 LOAD NAME,这将匹配在 exec 体中定义的 vairbales。因此,在函数内部,您必须使用 exec 选项(尽管,如果函数包含单个 exec 语句,更新 locals 应该可以工作,因为优化会被禁用)

它可以用于模块范围(无论如何在 Python 中称为global),并且 使用类体作为命名范围。

这是因为在函数内部,出于速度原因,从固定槽中使用局部变量,这会影响名称->局部变量(locals().返回的字典)的映射。因此,如果您可以在 locals() dict 中创建新的“局部变量”,如果在下面一行的代码中尝试访问该变量,那么在同一函数体中,该代码将被编译以尝试获取来自globals 的变量 - 即:

a = "global"
def b():
   locals()["a"] = "local"
   print(a)

结果:

>>> b()
global

另一方面,eval 几乎不需要 - 当您获得一个可以工作的范围时,更新正确的字典已经可以工作了。如上所述,可以为此使用类体,其优点是它可以直接作为命名空间工作:

>>> the_dict = 'x': '1', 'y': 'foo'
>>> class A:
...    locals().update(the_dict)
... 
>>> A.x
'1'
>>> A.y
'foo'

这当然是“推荐”的。请注意,在极端情况下创建类可能会产生一些副作用(例如,如果 dict 中的一个对象具有__get__ 方法,它将被用作描述符)。

【讨论】:

(顺便提一下:你现在真的不应该使用 Python2) 感谢您在答案第一部分提供的信息。我不知道 locals() 字典只是本地命名空间的副本(这在文档中已明确说明。但是,我不赞成答案,因为它忽略了我陈述 的问题部分“...将值直接加载到本地范围,而不是将它们加载到命名空间或类似的方法”。我无法修改访问这些变量的代码以包括对类的使用。此外,关于不使用 Python 2 的评论既没有回答问题,也没有提供有用的信息。 所以,我更新了答案。如果您愿意,如果答案中没有错误,写这些答案确实需要时间才能让他们投反对票。您可以在不投票的情况下发表评论,要求额外澄清。关于 Python 2 的评论是有原因的,而且你知道它是什么——它正在停产,计划于 2020 年 1 月 1 日硬关闭。 @jsbueno 可以动态地创建新的函数局部变量。可以使用exec 语句来完成(在 Python 2 中,但不是 3 中),如问题所示(即方法 1)。 是的,对不起,我忘记了。我认为它现在已修复。

以上是关于将字典加载到本地范围的方法之间的差异[重复]的主要内容,如果未能解决你的问题,请参考以下文章

javascript函数声明和范围差异[重复]

PHP和MySQL之间的时间差异[重复]

将本地 HTML 文件加载、导入或包含到 HTML 文件中 [重复]

两个日期之间的天数差异[重复]

将一个范围内的数字转换为另一个范围内的数字[重复]

基于pyspark中仅一列的两个DataFrame之间的差异[重复]