我知道其他一些语言,如PHP,支持“变量变量名”的概念——也就是说,字符串的内容可以用作变量名的一部分。
我听说这通常是一个坏主意,但我认为它可以解决我的Python代码中的一些问题。
在Python中可以做这样的事情吗?会出什么问题?
如果您只是试图通过名称查找现有变量,请参见如何通过(字符串)名称选择变量。但是,首先考虑是否可以按照这个问题中的建议重新组织代码以避免这种需要。
我知道其他一些语言,如PHP,支持“变量变量名”的概念——也就是说,字符串的内容可以用作变量名的一部分。
我听说这通常是一个坏主意,但我认为它可以解决我的Python代码中的一些问题。
在Python中可以做这样的事情吗?会出什么问题?
如果您只是试图通过名称查找现有变量,请参见如何通过(字符串)名称选择变量。但是,首先考虑是否可以按照这个问题中的建议重新组织代码以避免这种需要。
当前回答
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
其他回答
我回答的问题如何得到一个变量的值给定它的名字在一个字符串? 这是一个带有问题链接的副本。(编者注:它现在被关闭为“如何通过(字符串)名称选择变量?”的副本?)
如果所讨论的变量是对象的一部分(例如类的一部分),则可以使用hasattr、getattr和setattr函数来实现这一点。
例如,你可以有:
class Variables(object):
def __init__(self):
self.foo = "initial_variable"
def create_new_var(self, name, value):
setattr(self, name, value)
def get_var(self, name):
if hasattr(self, name):
return getattr(self, name)
else:
raise "Class does not have a variable named: " + name
然后你可以这样做:
>>> v = Variables()
>>> v.get_var("foo")
'initial_variable'
>>> v.create_new_var(v.foo, "is actually not initial")
>>> v.initial_variable
'is actually not initial'
新程序员有时会写这样的代码:
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():
import sys
current_module = module = sys.modules[__name__] # i.e the "file" where your code is written
setattr(current_module, 'variable_name', 15) # 15 is the value you assign to the var
print(variable_name) # >>> 15, created from a string
您也可以使用collections模块中的namedtuple来代替字典,这使得访问更容易。
例如:
# using dictionary
variables = {}
variables["first"] = 34
variables["second"] = 45
print(variables["first"], variables["second"])
# using namedtuple
Variables = namedtuple('Variables', ['first', 'second'])
v = Variables(34, 45)
print(v.first, v.second)
任何一组变量也可以包装在一个类中。 “变量”变量可以在运行时通过__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