如何创build可变数量的variables?
我如何在Python中完成variablesvariables?
这里是一个详细的手册条目,例如: variablesvariables
一般来说,我听说这是一个糟糕的主意,这是Python中的一个安全漏洞。 真的吗?
使用字典来实现这一点。 字典是键和值的存储。
>>> dct = {'x': 1, 'y': 2, 'z': 3} >>> dct {'y': 2, 'x': 1, 'z': 3} >>> dct["y"] 2
您可以使用variables键名称来实现variablesvariables的效果,而不存在安全风险。
>>> x = "spam" >>> z = {x: "eggs"} >>> z["spam"] 'eggs'
合理?
使用内置的getattr
函数按名称获取对象的属性。 根据需要修改名称。
obj.spam = 'eggs' name = 'spam' getattr(obj, name) # returns 'eggs'
这不是一个好主意。 如果你正在访问一个全局variables,你可以使用globals()
。
>>> a = 10 >>> globals()['a'] 10
如果你想访问本地范围内的一个variables,你可以使用locals()
,但是你不能给返回的字典赋值。
更好的解决scheme是使用getattr
或将variables存储在字典中,然后按名称访问它们。
无论何时你想使用variablesvariables,最好使用一个字典。 所以,而不是写作
$foo = "bar" $$foo = "baz"
你写
mydict = {} foo = "bar" mydict[foo] = "baz"
这样你不会不小心覆盖以前存在的variables(这是安全性方面),你可以有不同的“命名空间”。
您也可以使用collections模块中的namedtuple来代替字典,从而使访问更容易。
例如:
#using dictionary variables = {} variables["first"] = 34 variables["second"] = 45 print variables["first"], variables["second"] #using namedtuple Variables = namedtuple('Variables', ['first', 'second']) vars = Variables(34, 45) print vars.first, vars.second
新的编码器有时会写这样的代码:
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) ...
编码器然后留下一堆命名variables,编码工作量为O( m * n ),其中m是命名variables的数量, n是该组variables需要访问的次数(包括创build)。 更敏锐的初学者观察到,每一行的唯一区别是一个基于规则而改变的数字,并决定使用一个循环。 然而,他们被困在如何dynamic创build这些variables名称,并可能会尝试这样的事情:
for i in range(10): my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)
他们很快发现这是行不通的。
如果程序需要任意variables“名称”,字典是最好的select,正如其他答案中所解释的那样。 但是,如果您只是试图创build许多variables,并且不介意用一系列整数引用它们,那么您可能正在寻找一个list
。 如果您的数据是同质数据,例如每日温度读数,每周测验分数或graphics小部件网格,则情况尤其如此。
这可以组装如下:
my_calculator.buttons = [] for i in range(10): my_calculator.buttons.append(tkinter.Button(root, text=i))
这个list
也可以用理解的方式在一行中创build:
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
两种情况下的结果都是填充list
,第一个元素用my_calculator.buttons[0]
访问,下一个用my_calculator.buttons[1]
,依此类推。 “基本”variables名称成为list
的名称,并使用不同的标识符来访问它。
最后,不要忘记其他数据结构,比如set
– 这与字典类似,除了每个“名称”没有附加值。 如果你只需要一个“袋”的对象,这可能是一个很好的select。 而不是像这样的东西:
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
,一个任意sorting的对象包的集合,或一个包含相关值的名称的dict
。
你必须使用globals()
方法来实现这个行为:
def var_of_var(k, v): globals()[k] = v print variable_name # NameError: name 'variable_name' is not defined some_name = 'variable_name' globals()[some_name] = 123 print variable_name # 123 some_name = 'variable_name2' var_of_var(some_name, 456) print variable_name2 # 456
一致的意见是为此使用一本字典 – 请参阅其他答案。 对大多数情况来说,这是一个好主意,但是由此产生了很多方面的问题:
- 你会自己负责这本字典,包括垃圾收集(字典variables)等。
- 对variablesvariables没有局部性或全局性,它取决于字典的整体性
- 如果你想重命名一个variables名,你必须手动完成
- 但是,你更灵活,例如
- 你可以决定覆盖现有的variables或…
- …select实现constvariables
- 对不同types的覆盖引发exception
- 等等
也就是说,我已经实现了一个variablespipe理器类,它提供了一些上述的想法。 它适用于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'])
如果你想只允许覆盖相同types的variables:
myVars = VariableVariablesManager(enforceSameTypeOnOverride = True) myVars['test'] = 25 myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)
任何一组variables也可以包装在一个类中。 通过__dict__属性直接访问内置字典,可以在运行时将“variables”variables添加到类实例中。
下面的代码定义了Variables类,它在构造过程中向其实例添加了variables(在本例中为属性)。 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(va, vb, vc) #will produce 100 100 100
我正在回答这个问题: 如何得到一个variables的值在一个string中的名称? 这是作为一个重复closures与这个问题的链接。
如果所讨论的variables是对象的一部分(例如类的一部分),那么一些有用的函数就是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
“其实不是最初的”
SimpleNamespace
类可用于使用setattr
或SimpleNamespace
子类创build新的属性,并创build自己的函数来添加新的属性名称(variables)。
from types import SimpleNamespace variables = {"b":"B","c":"C"} a = SimpleNamespace(**v) setattr(a,"g","G") ag = "G+" something = aa
如果你不想使用任何对象,你仍然可以在当前模块中使用setattr()
:
import sys current_module = module = sys.modules[__name__] # ie 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