我知道其他一些语言,如PHP,支持“变量变量名”的概念——也就是说,字符串的内容可以用作变量名的一部分。

我听说这通常是一个坏主意,但我认为它可以解决我的Python代码中的一些问题。

在Python中可以做这样的事情吗?会出什么问题?


如果您只是试图通过名称查找现有变量,请参见如何通过(字符串)名称选择变量。但是,首先考虑是否可以按照这个问题中的建议重新组织代码以避免这种需要。


当前回答

当你想使用变量变量时,最好使用字典。所以与其写

$foo = "bar"
$$foo = "baz"

你写

mydict = {}
foo = "bar"
mydict[foo] = "baz"

这样就不会意外地覆盖先前存在的变量(这是安全方面的问题),并且可以使用不同的“名称空间”。

其他回答

当你想使用变量变量时,最好使用字典。所以与其写

$foo = "bar"
$$foo = "baz"

你写

mydict = {}
foo = "bar"
mydict[foo] = "baz"

这样就不会意外地覆盖先前存在的变量(这是安全方面的问题),并且可以使用不同的“名称空间”。

这应该是非常危险的…… 但是你可以使用exec():

a = 'b=5'
exec(a)
c = b*2
print (c)

结果: 10

新程序员有时会写这样的代码:

my_calculator.button_0 = tkinter.Button(root, text=0)
my_calculator.button_1 = tkinter.Button(root, text=1)
my_calculator.button_2 = tkinter.Button(root, text=2)
...

然后,编码器得到一堆命名变量,编码工作量为O(m * n),其中m是命名变量的数量,n是需要访问这组变量的次数(包括创建)。更精明的初学者会注意到,每一行之间的唯一区别是根据规则变化的数字,并决定使用循环。然而,他们被如何动态创建这些变量名所困扰,可能会尝试这样的方法:

for i in range(10):
    my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)

他们很快发现这行不通。

如果程序需要任意变量“名称”,字典是最好的选择,正如在其他回答中解释的那样。然而,如果您只是想创建许多变量,并且不介意用一组整数来引用它们,那么您可能正在寻找一个列表。如果您的数据是同质的,例如每日温度读数、每周测验分数或图形小部件网格,则尤其如此。

可以按如下方式组装:

my_calculator.buttons = []
for i in range(10):
    my_calculator.buttons.append(tkinter.Button(root, text=i))

这个列表也可以用理解式在一行中创建:

my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]

这两种情况的结果都是一个填充列表,第一个元素是用my_calculator访问的。按钮[0],下一个与my_calculator。按钮[1],等等。“基本”变量名成为列表的名称,变量标识符用于访问它。

最后,不要忘记其他数据结构,比如set——它类似于字典,只是每个“名称”都没有附加值。如果你只是需要一个“包”的对象,这可能是一个很好的选择。而不是像这样:

keyword_1 = 'apple'
keyword_2 = 'banana'

if query == keyword_1 or query == keyword_2:
    print('Match.')

你会得到这个:

keywords = {'apple', 'banana'}
if query in keywords:
    print('Match.')

对于相似对象的序列使用list,对于任意顺序的对象包使用set,或者对于具有关联值的名称包使用dict。

大家的共识是使用字典来进行查询-请参阅其他答案。在大多数情况下,这是一个好主意,然而,这产生了许多方面:

您将自己负责这个字典,包括垃圾收集(indict变量)等。 变量变量没有局部性或全局性,这取决于字典的全局性 如果要重命名变量名,则必须手动执行 然而,你要灵活得多,例如: 您可以决定覆盖现有变量或… ... 选择实现const变量 针对不同类型的重写引发异常 等。

也就是说,我已经实现了一个变量变量管理器类,它提供了上面的一些想法。它适用于python 2和3。

你可以这样使用这个类:

from variableVariablesManager import VariableVariablesManager

myVars = VariableVariablesManager()
myVars['test'] = 25
print(myVars['test'])

# define a const variable
myVars.defineConstVariable('myconst', 13)
try:
    myVars['myconst'] = 14 # <- this raises an error, since 'myconst' must not be changed
    print("not allowed")
except AttributeError as e:
    pass

# rename a variable
myVars.renameVariable('myconst', 'myconstOther')

# preserve locality
def testLocalVar():
    myVars = VariableVariablesManager()
    myVars['test'] = 13
    print("inside function myVars['test']:", myVars['test'])
testLocalVar()
print("outside function myVars['test']:", myVars['test'])

# define a global variable
myVars.defineGlobalVariable('globalVar', 12)
def testGlobalVar():
    myVars = VariableVariablesManager()
    print("inside function myVars['globalVar']:", myVars['globalVar'])
    myVars['globalVar'] = 13
    print("inside function myVars['globalVar'] (having been changed):", myVars['globalVar'])
testGlobalVar()
print("outside function myVars['globalVar']:", myVars['globalVar'])

如果你希望只允许覆盖相同类型的变量:

myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)

任何一组变量也可以包装在一个类中。 “变量”变量可以在运行时通过__dict__属性直接访问内置字典添加到类实例中。

下面的代码定义了Variables类,它在构造过程中将变量(在本例中是属性)添加到其实例中。变量名取自指定的列表(例如,可以由程序代码生成):

# some list of variable names
L = ['a', 'b', 'c']

class Variables:
    def __init__(self, L):
        for item in L:
            self.__dict__[item] = 100

v = Variables(L)
print(v.a, v.b, v.c)
#will produce 100 100 100