如何在 Python 中创建 PHP variable variable names 的等价物?
不过,总的来说,我听说这是个坏主意。真的吗?
locals
返回的 dict 的修改不会影响 CPython 中的本地命名空间。这是不这样做的另一个原因。
您可以使用 dictionaries 来完成此操作。字典是键和值的存储。
>>> 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']
对于有序序列,列表比带有整数键的 dict 更方便,因为列表支持索引顺序、slicing、append
的迭代,以及其他需要使用 dict 进行笨拙的键管理的操作。
使用内置 getattr
函数按名称获取对象的属性。根据需要修改名称。
obj.spam = 'eggs'
name = 'spam'
getattr(obj, name) # returns 'eggs'
新程序员有时会编写如下代码:
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)
他们很快发现这行不通。
如果程序需要任意变量“名称”,则字典是最佳选择,如其他答案中所述。但是,如果您只是想创建许多变量并且不介意用整数序列来引用它们,那么您可能正在寻找 list
。如果您的数据是同质的,例如每日温度读数、每周测验分数或图形小部件网格,则尤其如此。
这可以按如下方式组装:
my_calculator.buttons = []
for i in range(10):
my_calculator.buttons.append(tkinter.Button(root, text=i))
这个 list
也可以用推导式在一行中创建:
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
在任何一种情况下,结果都是填充的 list
,第一个元素使用 my_calculator.buttons[0]
访问,下一个元素使用 my_calculator.buttons[1]
,依此类推。 “基本”变量名称成为 list
的名称,并使用可变标识符来访问它。
最后,不要忘记其他数据结构,例如 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
用于具有关联值的名称包。
每当您想使用可变变量时,使用字典可能会更好。所以不要写
$foo = "bar"
$$foo = "baz"
你写
mydict = {}
foo = "bar"
mydict[foo] = "baz"
这样您就不会意外覆盖以前存在的变量(这是安全方面),并且您可以拥有不同的“命名空间”。
使用globals()
实际上,您可以动态地将变量分配给全局范围,例如,如果您想要可以在全局范围 i_1
、i_2
... i_10
上访问的 10 个变量:
for i in range(10):
globals()['i_{}'.format(i)] = 'a'
这将为所有这 10 个变量分配“a”,当然您也可以动态更改值。现在可以像其他全局声明的变量一样访问所有这些变量:
>>> i_5
'a'
除了字典之外,您还可以使用集合模块中的 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)
namedtuple
是不可变的,因此它们与简单的带有点符号的 dicts 有点不同。话虽如此,这两个选项都促进了良好的设计原则,并且不会像该线程中的一半答案那样滥用全局命名空间。
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
如果您不想使用任何对象,您仍然可以在当前模块中使用 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
__dict__
变量。我想知道是否有一种通用机制来动态创建 any 全局变量。
globals()
可以做到这一点
您必须使用 globals()
built in method 来实现该行为:
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
我正在回答这个问题:How to get the value of a variable given its name in a string?,它作为副本关闭,并带有指向此问题的链接。
如果所讨论的变量是对象的一部分(例如类的一部分),那么一些有用的函数可以准确地实现 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")
“初始变量”
v.create_new_var(v.foo,"is actually not initial")
v.initial_variable
“实际上不是初始的”
# Python 3.8.2 (default, Feb 26 2020, 02:56:10)
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() 将产生相同的结果
# Python 3.8.2 (default, Feb 26 2020, 02:56:10)
#<?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
我在 python 3.7.3 中都试过了,你可以使用 globals() 或 vars()
>>> food #Error
>>> milkshake #Error
>>> food="bread"
>>> drink="milkshake"
>>> globals()[food] = "strawberry flavor"
>>> vars()[drink] = "chocolate flavor"
>>> bread
'strawberry flavor'
>>> milkshake
'chocolate flavor'
>>> globals()[drink]
'chocolate flavor'
>>> vars()[food]
'strawberry flavor'
共识是为此使用字典 - 请参阅其他答案。在大多数情况下,这是一个好主意,但是,这会产生许多方面:
您将自己负责这本字典,包括垃圾收集(in-dict 变量)等。
变量变量没有局部性或全局性,这取决于字典的全局性
如果要重命名变量名,则必须手动进行
但是,您要灵活得多,例如,您可以决定覆盖现有变量或......选择实现 const 变量以引发覆盖不同类型等的异常。
您可以决定覆盖现有变量或...
... 选择实现 const 变量
为不同类型的覆盖引发异常
等等
也就是说,我已经实现了一个 variable variables manager 类,它提供了上述一些想法。它适用于 python 2 和 3。
您可以像这样使用 the class:
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)
任何一组变量也可以封装在一个类中。 “变量”变量可以在运行时通过 __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
这应该是非常危险的......但你可以使用 exec():
a = 'b=5'
exec(a)
c = b*2
print (c)
结果:10
locals()['b'] = 5
(它也不能在函数中工作)。
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)
不定期副业成功案例分享
x = "foo"
和locals()["x"] = "bar"
,使用print x
给出 Jython 2.5.2 的输出bar
。这是使用 maximo 中的按需自动化脚本测试的。locals()
的文档明确指出:“本词典的内容不应被修改。” (强调我的)dict
)中的图片(显示内容)——在图片上绘图实际上不会改变真实的东西。locals()
返回一个真dict
;在函数中,dict
是通过在调用locals()
时在数组中加载名称和关联值来生成的,它不会看到未来的更改。如果它发生变化,则您处于全局或类范围(使用dict
范围)。