Python:使用vars()将字符串赋值给变量。

25

我觉得在运行时创建新变量并创建结果的字典以便稍后处理,例如写入文件,非常有用:

myDict = {}
for i in range (1,10):
    temp = "variable"+str(i) 
    vars()[temp] = myFunctionThatReturnsData() # variable1= data1, variable2 = data2,etc.
    myDict[temp] = vars(temp)

通过 myDict[result1] = data1 创建了字典项 [result1:data1],我可以通过 myDict[result1] 调用它。之前一直在使用 vars(),但并不真正理解我在做什么。我想,vars() 返回一个带有局部变量的字典(?), 而

vars()[x] = y

创建了一个新的字典项[x:y]?

我有一个脚本,我传入一个已准备好的字典 {input1:data1,input2:data2} ,然后使用这种方法遍历所有值、存储所有结果并将其输出到文件中。这段代码在类中的一个函数内部,目前正常工作。

我的困惑源于我已经阅读过各种帖子,说明 locals() 不应该被弄乱,而 vars() 相当于 locals() 或 globals() ..

所以我至少有两个问题:

1. vars() 到底是什么,或者特别是,vars()[x] = y 做了什么,

2. 这个字典的范围是什么(我在编写更大型程序时需要记住什么),

3. 是否是良好的编程实践。

提前感谢!

7个回答

35

创建一系列变量的 Pythonic 方法

如果您想要一个变量序列,请创建一个序列。而不是尝试创建独立的变量,例如:

variable0
variable1
variable2
variable3

你应该考虑创建一个list。这与S.Lott所建议的类似(S.Lott通常有很好的建议),但更适用于你的for循环:

sequence = []
for _ in xrange(10):
    sequence.append(function_that_returns_data())

(注意我们丢弃了循环变量 (_)。我们只是想进行10次遍历。)

然后你的数据将会以以下形式可用:

sequence[0]
sequence[1]
sequence[2]
sequence[3]
[...]
sequence[9]

作为额外的奖励,你可以执行:

for datum in sequence:
    process_data(datum)

一开始,你可能会对序列从0开始感到不适应。可以进行各种扭曲操作以使实际数据从1开始,但这样做更加麻烦,不值得费力。我建议只需习惯从零开始的列表即可。因为所有内容都是围绕它们构建的,很快就会感觉自然。

vars()和locals()

现在回答你问题的另一个部分。vars()(或locals())提供了访问Python创建的变量的底层接口。因此,以下两行代码是等价的。

locals()['x'] = 4
x = 4
vars()['x']的作用域与x的作用域完全相同。使用locals()(或vars())的一个问题在于,它会让你把一些无法通过正常手段从命名空间中移除的东西放入命名空间中。因此,你可以这样做:locals()[4] = 'An integer',但是你不能通过正常手段把它取出来,只能再次使用locals(),因为本地命名空间(和所有Python命名空间一样)只用于保存字符串。

>>> x = 5
>>> dir()
['__builtins__', '__doc__', '__name__', 'x']
>>> locals()[4] = 'An integer'
>>> dir()
[4, '__builtins__', '__doc__', '__name__', 'x']
>>> x
5
>>> 4
4
>>> locals()[4]
'An integer'

请注意,4和locals()[4]返回的内容是不同的。这可能导致一些意想不到、难以调试的问题。这就是避免使用locals()的原因之一。另一个原因是它通常会增加很多复杂性,而Python提供了更简单、更少出错的方法来完成类似的任务(例如创建变量序列)。


2
我认为 vars()['x'] = 4x = 4 在某些情况下实际上是等效的。如果您在函数中这样做,并且没有在其他地方设置 x,并且编译器对该函数进行了优化,则稍后在函数中正常查找 x(即 y = x + 2)将无法正常工作。我认为编译器会缓存它可以看到的变量(可能在编译时定义),并且不考虑这种花招。如果您向函数添加 exec 语句,则编译器将不会尝试优化该函数。 - Matt Anderson
1
感谢您的周到回答, 对于序列中的数据: function(datum) 看起来非常有用。今天我学到了很多,谢谢! - PPTim
要查找有关该构造的更多信息,请查阅“python 迭代器”。 - jcdyer
设置 locals()[...] 具有未定义的行为。https://dev59.com/0msz5IYBdhLWcg3wQFUq - ninjagecko
1
为什么不使用 for _ in xrange(10):,而不是 (请注意,在 for 循环中我们甚至不需要 i。我们只是想要进行 10 次循环。) - boardrider

9
这样做更好。它更简单易懂。
myDict = {}
for i in range (1,10):
    temp = "variable"+str(i) 
    myDict[temp] = myFunctionThatReturnsData() # variable1= data1, variable2 = data2,etc.

这就是你需要做的全部。

结果将会是myDict['variable1']myDict['variable9']

你很少需要使用vars()或者locals()。只需停止使用它们,使用普通变量和普通字典即可。尽量避免你不理解的东西,坚持使用简单、明显的东西。


现在我想起来为什么我使用vars(),可能是因为当我逐行测试代码时,能够直接从IDLE调用变量感觉很好。谢谢你的回答! - PPTim

6

从vars的帮助文档中,

vars(...) vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
您正在使用无变量的方式,因此让我们查看locals()帮助文档。

locals(...) locals() -> dictionary

Update and return a dictionary containing the current scope's local

variables.

这就回答了你的前两个问题。vars() 函数返回一个字典,其中变量名作为字符串索引本地变量。其范围是局部的。

我不确定第三个问题,但这似乎有点像一种不好的 hack。如果你只在正确的范围内小心使用它,可能可以解决问题。


我被困惑所困扰,以至于忘记寻求帮助。谢谢。 - PPTim

5
很好地解释了这些概念,而则清楚地说明了vars()locals()的作用。但是一个小例子总是可以加速理解。
class Bull(object):

    def __init__(self):
        self.x = 1
        self.y = "this"

    def __repr__(self):
        return "Bull()"

    def test1(self):
        z = 5
        return vars()

    def test2(self):
        y = "that"
        return vars(self)

    def test3(self):
        return locals()

    def test4(self):
        y = 1
        return locals()

if __name__ == "__main__":
    b = Bull()
    print b.test1()
    print b.test2()
    print b.test3()
    print b.test4()
    print vars(b).get("y")

这将导致:
{'self': Bull(), 'z': 5}
{'y': 'this', 'x': 1}
{'self': Bull()}
{'y': 1, 'self': Bull()}
this

3

我可以回答第三个问题:这不是好的编程实践。我不确定你试图实现什么,但我相信有一种更优雅的方法来完成它,而不使用locals()(根据交互式Python shell中的help(vars),它与vars()相同)。


2

在这种方式中使用vars/locals或globals是(a)不良做法,(b)并非在所有情况下都可行。详情请参见Python中动态设置局部变量。归根结底:只需使用字典--这就是它们的用途。


0

我也在很多地方搜索了这个答案。到目前为止,我看到的最好的答案是:

var_list = ["Var_Name{}".format(i) for i in range(1,100)]

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接