How do I create a variable number of variables?
如何在Python中完成变量?
这里有一个详细的手工输入,例如:变量
不过,我听说这通常是个坏主意,这是Python中的一个安全漏洞。是真的吗?
您可以使用字典来完成这项工作。字典是键和值的存储。
1 2 3 4 5 | >>> dct = {'x': 1, 'y': 2, 'z': 3} >>> dct {'y': 2, 'x': 1, 'z': 3} >>> dct["y"] 2 |
您可以使用变量键名来实现变量的效果,而不存在安全风险。
1 2 3 4 | >>> x ="spam" >>> z = {x:"eggs"} >>> z["spam"] 'eggs' |
如果你想做类似的事情
1 2 3 4 | var1 = 'foo' var2 = 'bar' var3 = 'baz' ... |
列表可能比dict更合适。列表表示具有整数索引的有序对象序列:
1 2 3 | l = ['foo', 'bar', 'baz'] print(l[1]) # prints bar, because indices start at 0 l.append('potatoes') # l is now ['foo', 'bar', 'baz', 'potatoes'] |
对于有序序列,列表比带整数键的dict更方便,因为列表支持索引顺序、切片、
使用内置的
1 2 3 | obj.spam = 'eggs' name = 'spam' getattr(obj, name) # returns 'eggs' |
这不是个好主意。如果要访问全局变量,可以使用
1 2 3 | >>> a = 10 >>> globals()['a'] 10 |
如果要访问本地作用域中的变量,可以使用
更好的解决方案是使用
每当你想使用变量时,最好使用字典。所以不是写作
1 2 | $foo ="bar" $$foo ="baz" |
你写
1 2 3 | mydict = {} foo ="bar" mydict[foo] ="baz" |
这样,您就不会意外地覆盖以前存在的变量(这是安全方面),并且您可以拥有不同的"名称空间"。
新的编码人员有时会这样编写代码:
1 2 3 4 | 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是需要访问(包括创建)一组变量的次数。更精明的初学者注意到每一行的唯一区别是一个根据规则变化的数字,并决定使用循环。但是,他们会陷入如何动态创建这些变量名的困境,可能会尝试如下操作:
1 2 | for i in range(10): my_calculator.('button_%d' % i) = tkinter.Button(root, text=i) |
他们很快发现这行不通。
如果程序需要任意变量"名称",字典是最好的选择,如其他答案所述。但是,如果你只是想创建许多变量,而不介意用一个整数序列来引用它们,那么你可能在寻找一个
可按如下方式组装:
1 2 3 | my_calculator.buttons = [] for i in range(10): my_calculator.buttons.append(tkinter.Button(root, text=i)) |
这个
1 | my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)] |
这两种情况下的结果都是填充的
最后,不要忘记其他数据结构,如
1 2 3 4 5 | keyword_1 = 'apple' keyword_2 = 'banana' if query == keyword_1 or query == keyword_2: print('Match.') |
您将获得:
1 2 3 | keywords = {'apple', 'banana'} if query in keywords: print('Match.') |
使用
除了字典,您还可以使用Collections模块中的
例如:
1 2 3 4 5 6 7 8 9 10 | # 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) |
如果您不想使用任何对象,您仍然可以在当前模块中使用
1 2 3 4 | 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 |
您必须使用
1 2 3 4 5 6 7 8 9 10 11 | 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 |
1 2 3 4 5 6 7 | from types import SimpleNamespace variables = {"b":"B","c":"C"} a = SimpleNamespace(**v) setattr(a,"g","G") a.g ="G+" something = a.a |
使用
实际上,您可以动态地将变量分配给全局作用域,例如,如果您希望在全局作用域
1 2 | for i in range(10): globals()['i_{}'.format(i)] = 'a' |
这将为所有这10个变量分配"a",当然您也可以动态地更改值。现在可以像其他全局声明的变量一样访问所有这些变量:
1 2 | >>> i_5 'a' |
我要回答的问题是:如何在字符串中获取给定变量名的值?它作为副本关闭,并带有指向此问题的链接。
如果所讨论的变量是对象的一部分(例如,类的一部分),那么要精确实现的一些有用函数是
例如,您可以有:
1 2 3 4 5 6 7 8 9 10 | 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) |
然后你可以做:
1 2 | v = Variables() v.get_var("foo") |
"initial_variable"
1 2 | v.create_new_var(v.foo,"is actually not initial") v.initial_variable |
"is actually not initial"
大家的共识是用字典来解释这个问题——见其他答案。对于大多数情况来说,这是一个好主意,但是,由此产生的许多方面:
- 您将自己负责这个字典,包括垃圾收集(在dict变量中)等。
- 变量既没有局部性也没有全局性,这取决于字典的全局性。
- 如果要重命名变量名,则必须手动执行。
- 但是,您的灵活性要高得多,例如
- 您可以决定覆盖现有变量或…
- …选择实现常量变量
- 对不同类型的覆盖引发异常
- 等。
也就是说,我实现了一个变量管理器类,它提供了上面的一些想法。它适用于python 2和3。
你可以这样使用这个类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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']) |
如果只允许覆盖相同类型的变量:
1 2 3 | myVars = VariableVariablesManager(enforceSameTypeOnOverride = True) myVars['test'] = 25 myVars['test'] ="Cat" # <- raises Exception (different type on overwriting) |
请参阅以下示例以创建变量运行时。您可以使用
1 2 | for i in range(3): globals() ['variable_'+str(i)] = i |
在上面的例子中,我想创建三个变量:运行时的
1 2 3 4 5 6 7 8 | variable_0 [Output]:0 variable_1 [Output]:1 variable_2 [Output]:2 |
要访问运行时创建的变量值,可以使用
1 2 3 4 5 6 7 8 | for i in range(3): globals() ['variable_'+str(i)] = i print('Variable Value:',eval('variable_'+str(i))) [Output]: Variable Value: 0 Variable Value: 1 Variable Value: 2 |
有一种已知的方法来模拟变量的容器,它支持两种访问方法:通过变量的名称和字符串键。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class Vars: def __init__(self, **kw): self.__dict__.update(kw) def __getitem__(self, key): return self.__dict__[key] def __setitem__(self, key, val): self.__dict__[key] = val def __contains__(self, name): return name in self.__dict__ def __nonzero__(self): return bool(self.__dict__) def __iter__(self): return iter(self.__dict__) def __len__(self): return len(self.__dict__) def __copy__(self): return self.__class__(**self.__dict__) def __repr__(self): return 'Vars(' + ', '.join('%s=%r' % (k,v) for k,v in self.__dict__.items()) + ')' >>> vars = Vars() >>> vars.a = 1 >>> vars['b'] = 2 >>> print(vars) Vars(a=1, b=2) >>> print(vars['a'], vars.b) 1 2 >>> print(tuple(vars)) ('a', 'b') |
任何一组变量也可以包装在一个类中。"variable"变量可以在运行时通过uudict_uuuu属性直接访问内置字典添加到类实例中。
下面的代码定义了变量类,它在构造过程中将变量(在本例中是属性)添加到其实例中。变量名取自指定的列表(例如,该列表可能是由程序代码生成的):
1 2 3 4 5 6 7 8 9 10 11 | # 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 |
您可以使用内置函数
1 2 3 4 | >>> foo = 'bar' >>> vars()[foo] = 'something' >>> bar 'something' |