我知道其他一些语言,如PHP,支持“变量变量名”的概念——也就是说,字符串的内容可以用作变量名的一部分。
我听说这通常是一个坏主意,但我认为它可以解决我的Python代码中的一些问题。
在Python中可以做这样的事情吗?会出什么问题?
如果您只是试图通过名称查找现有变量,请参见如何通过(字符串)名称选择变量。但是,首先考虑是否可以按照这个问题中的建议重新组织代码以避免这种需要。
我知道其他一些语言,如PHP,支持“变量变量名”的概念——也就是说,字符串的内容可以用作变量名的一部分。
我听说这通常是一个坏主意,但我认为它可以解决我的Python代码中的一些问题。
在Python中可以做这样的事情吗?会出什么问题?
如果您只是试图通过名称查找现有变量,请参见如何通过(字符串)名称选择变量。但是,首先考虑是否可以按照这个问题中的建议重新组织代码以避免这种需要。
当前回答
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)
其他回答
SimpleNamespace类可以使用setattr或SimpleNamespace的子类来创建新属性,并创建自己的函数来添加新的属性名(变量)。
from types import SimpleNamespace
variables = {"b":"B","c":"C"}
a = SimpleNamespace(**variables)
setattr(a,"g","G")
a.g = "G+"
something = a.a
大家的共识是使用字典来进行查询-请参阅其他答案。在大多数情况下,这是一个好主意,然而,这产生了许多方面:
您将自己负责这个字典,包括垃圾收集(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)
您可以使用字典来实现这一点。字典是键和值的存储。
>>> 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。
任何一组变量也可以包装在一个类中。 “变量”变量可以在运行时通过__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