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

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

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


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


当前回答

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

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。

其他回答

Python中的变量

"""
<?php
$a = 'hello';
$e = 'wow'
?>
<?php
$$a = 'world';
?>
<?php
echo "$a ${$a}\n";
echo "$a ${$a[1]}\n";
?>
<?php
echo "$a $hello";
?>
"""

a = 'hello'  #<?php $a = 'hello'; ?>
e = 'wow'   #<?php $e = 'wow'; ?>
vars()[a] = 'world' #<?php $$a = 'world'; ?>
print(a, vars()[a]) #<?php echo "$a ${$a}\n"; ?>
print(a, vars()[vars()['a'][1]]) #<?php echo "$a ${$a[1]}\n"; ?>
print(a, hello) #<?php echo "$a $hello"; ?>

输出:

hello world
hello wow
hello world

使用globals()、locals()或vars()将产生相同的结果

#<?php $a = 'hello'; ?>
#<?php $e = 'wow'; ?>
#<?php $$a = 'world'; ?>
#<?php echo "$a ${$a}\n"; ?>
#<?php echo "$a ${$a[1]}\n"; ?>
#<?php echo "$a $hello"; ?>

print('locals():\n')
a = 'hello'
e = 'wow'
locals()[a] = 'world'
print(a, locals()[a])
print(a, locals()[locals()['a'][1]])
print(a, hello)

print('\n\nglobals():\n')
a = 'hello'
e = 'wow'
globals()[a] = 'world'
print(a, globals()[a])
print(a, globals()[globals()['a'][1]])
print(a, hello)

输出:

locals():

hello world
hello wow
hello world


globals():

hello world
hello wow
hello world

奖励(从字符串创建变量)

# Python 2.7.16 (default, Jul 13 2019, 16:01:51)
# [GCC 8.3.0] on linux2

创建变量并解包元组:

g = globals()
listB = []
for i in range(10):
    g["num%s" % i] = i ** 10
    listB.append("num{0}".format(i))

def printNum():
    print "Printing num0 to num9:"
    for i in range(10):
        print "num%s = " % i, 
        print g["num%s" % i]

printNum()

listA = []
for i in range(10):
    listA.append(i)

listA = tuple(listA)
print listA, '"Tuple to unpack"'

listB = str(str(listB).strip("[]").replace("'", "") + " = listA")

print listB

exec listB

printNum()

输出:

Printing num0 to num9:
num0 =  0
num1 =  1
num2 =  1024
num3 =  59049
num4 =  1048576
num5 =  9765625
num6 =  60466176
num7 =  282475249
num8 =  1073741824
num9 =  3486784401
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) "Tuple to unpack"
num0, num1, num2, num3, num4, num5, num6, num7, num8, num9 = listA
Printing num0 to num9:
num0 =  0
num1 =  1
num2 =  2
num3 =  3
num4 =  4
num5 =  5
num6 =  6
num7 =  7
num8 =  8
num9 =  9

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

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

你写

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

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

您可以使用字典来实现这一点。字典是键和值的存储。

>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'y': 2, 'x': 1, 'z': 3}
>>> dct["y"]
2

可以使用可变键名实现可变变量的效果,而不存在安全风险。

>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'

如果你想做些什么

var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...

清单可能比字典更合适。list表示对象的有序序列,索引为整数:

lst = ['foo', 'bar', 'baz']
print(lst[1])           # prints bar, because indices start at 0
lst.append('potatoes')  # lst is now ['foo', 'bar', 'baz', 'potatoes']

对于有序序列,列表比使用整数键的字典更方便,因为列表支持索引顺序迭代、切片、追加和其他需要使用字典进行笨拙的键管理的操作。

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

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。

setattr()方法设置指定对象的指定属性的值。

语法是这样的-

setattr(object, name, value)
Example –

setattr(self,id,123)

它等价于self。Id = 123

正如您可能已经观察到的,setattr()期望将一个对象与值一起传递,以生成/修改一个新属性。

我们可以将setattr()与一个解决方案一起使用,以便能够在模块中使用。这里怎么——

import sys
x = "pikachu"
value = 46
thismodule = sys.modules[__name__]
setattr(thismodule, x, value)
print(pikachu)