如何创建可变变量?
我知道其他一些语言,例如 PHP,支持“变量变量名”的概念 - 也就是说,字符串的内容可以用作变量名的一部分。
我听说这通常是一个坏主意,但我认为它可以解决我在 Python 代码中遇到的一些问题。
在Python中可以做这样的事情吗?会出现什么问题?
如果您只是想按名称查找现有变量,请参阅如何选择变量按(字符串)名称?。但是,首先考虑是否可以按照本问题中的建议重新组织代码以避免这种需要。
I know that some other languages, such as PHP, support a concept of "variable variable names" - that is, the contents of a string can be used as part of a variable name.
I heard that this is a bad idea in general, but I think it would solve some problems I have in my Python code.
Is it possible to do something like this in Python? What can go wrong?
If you are just trying to look up an existing variable by its name, see How can I select a variable by (string) name?. However, first consider whether you can reorganize the code to avoid that need, following the advice in this question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
我正在回答问题 如何获取字符串中给定名称的变量的值?
它作为副本关闭,并带有指向此问题的链接。 (编者注:它现在作为 How can我通过(字符串)名称选择一个变量?)
如果所讨论的变量是对象的一部分(例如类的一部分),那么一些有用的函数可以准确地实现这些功能:
hasattr
、getattr
和setattr
。例如,您可以:
然后您可以这样做:
I'm answering the question How to get the value of a variable given its name in a string?
which is closed as a duplicate with a link to this question. (Editor's note: It is now closed as a duplicate of How can I select a variable by (string) name?)
If the variables in question are part of an object (part of a class for example) then some useful functions to achieve exactly that are
hasattr
,getattr
, andsetattr
.So for example you can have:
Then you can do:
我已经在 python 3.7.3 中尝试过,您可以使用 globals() 或 vars()
参考:
https:// /www.daniweb.com/programming/software-development/threads/111526/setting-a-string-as-a-variable-name#post548936
I have tried both in python 3.7.3, you can use either globals() or vars()
Reference:
https://www.daniweb.com/programming/software-development/threads/111526/setting-a-string-as-a-variable-name#post548936
共识是为此使用字典 - 请参阅其他答案。对于大多数情况来说,这是一个好主意,但是,由此产生了很多方面:
也就是说,我已经实现了 变量管理器-类提供了上述一些想法。它适用于 python 2 和 3。
您可以使用 class 像这样:
如果您希望只允许覆盖相同类型的变量:
The consensus is to use a dictionary for this - see the other answers. This is a good idea for most cases, however, there are many aspects arising from this:
That said, I've implemented a variable variables manager-class which provides some of the above ideas. It works for python 2 and 3.
You'd use the class like this:
If you wish to allow overwriting of variables with the same type only:
任何变量集也可以包含在一个类中。
“变量”变量可以在运行时通过 __dict__ 属性直接访问内置字典来添加到类实例中。
以下代码定义了 Variables 类,该类在构造期间将变量(在本例中为属性)添加到其实例。变量名称取自指定列表(例如,可以由程序代码生成):
Any set of variables can also be wrapped up in a class.
"Variable" variables may be added to the class instance during runtime by directly accessing the built-in dictionary through __dict__ attribute.
The following code defines Variables class, which adds variables (in this case attributes) to its instance during the construction. Variable names are taken from a specified list (which, for example, could have been generated by program code):
应该说风险很大...
但你可以使用 exec():
结果:
10
It should be extremely risky...
but you can use exec():
Result:
10
setattr()方法设置指定对象的指定属性的值。
语法如下 -
相当于
self.id = 123
正如您可能已经观察到的,setattr() 期望将一个对象与要生成的值一起传递/修改一个新属性。
我们可以使用 setattr() 和解决方法,以便能够在模块中使用。这是如何——
The setattr() method sets the value of the specified attribute of the specified object.
Syntax goes like this –
which is equivalent to
self.id = 123
As you might have observed, setattr() expects an object to be passed along with the value to generate/modify a new attribute.
We can use setattr() with a workaround to be able to use within modules. Here’ how –
TL;DR:考虑使用
eval()
我找到此页面是因为我希望使用 python 字符串函数进行一些简单的模板处理(缺少完整的模板引擎) )。我正在寻找如何设置局部变量,这就是我到达这里的方式。
我的问题从一个简单的模板开始:
我填充这个模板的方式是这样的:
所以这会起作用:
但后来事情进展得很快。我尝试了一个新模板,我只想要第一个单词:
现在我的模板是这样的:
"Hello, {name.split()[0]}"
并且此代码出现错误。然后我了解到格式功能并没有按照我想要的方式工作。您不能向其传递任意代码。你需要传递它格式化的东西。所以我尝试了不同的解决方案。我编写了
populate
来使用eval
和 f 字符串而不是format
。 f 字符串(与格式不同)允许在大括号插值中使用 python 代码。所以像这样的 f 字符串 `f"Hello, {name.split()[0]}" 确实有效。让我们看看这个小部分的代码(这样你就不必离开这篇文章来找出 f 字符串):现在我只需要使用 f 字符串。所以我使用了
eval
。我的新填充是这样的:但是当我再次运行该程序时,我收到此错误:
我应该指出 f 字符串能够使用范围内的任何全局或局部变量填充字符串。为了解决我的问题,我可以将模板更改为
"Hello, {variables['name']}"
因为variables
肯定在范围内。这是非常糟糕的方法,因为现在模板编写者必须了解variables
字典。相反,我想让模板作者可以使用variables
字典中可用的每个键,就像我之前使用format(**variables)
所做的那样。为了解决我的问题,我想根据传递给
populate()
函数的variables
字典的内容来设置局部变量。我尝试了这个:
但这不起作用:
然后我尝试了这个,这起作用了:
所以第一个要点是您可以在函数中创建局部变量(或就此而言的全局变量)通过在 locals() 字典中设置键值对。
对于 eval 来说,第二个和第三个参数允许您传入局部变量和全局变量,因此您可以将 populate 函数简化为:
以上是我使用 eval 的方式 进行 f 字符串填充(或简单的模板评估)。但是
eval
也可以用来提供可变变量。TL;DR: Consider using
eval()
I found this page because I was looking to do some simple template processing with python string functions (short of including a full blown template engine). I was searching for how to set local variables, and that's how I got here.
My problem began with a simple template:
The way I populated this template was this way:
And so this would work:
But then things went south fast. I tried a new template where I only wanted the first word:
Now my template was this:
"Hello, {name.split()[0]}"
and this code got an error.And then I learned that the format function doesn't work the way I want it. You can't pass arbitrary code to it. You need to pass it formatting stuff. And so I tried a different solution. I coded
populate
to useeval
and an f-string instead offormat
. An f-string (unlike format) allows for python code in the curly brace interpolation. So an f-string like this `f"Hello, {name.split()[0]}" does work. Let's just see the code for this small part (so you don't have to leave this post to figure out f-string):Now I just had to use an f-string. So I used
eval
. My new populate is this:But when I ran the program again, I got this error:
I should point out that an f-string is able to populate the string with any global or local variable in scope. To fix my issue, I could change my template to
"Hello, {variables['name']}"
sincevariables
is definitely in scope. This is really bad approach because now the template writer has to know about a thevariables
dictionary. Rather, I want to make every key available in thevariables
dictionary available to the template author, as I had before withformat(**variables)
.To solve my problem, I wanted to set local variables based on the content of the
variables
dictionary passed to thepopulate()
function.I tried this:
And that didn't work:
And then I tried this and this worked:
And so the first take away is that you can create local variables in a function (or globals for that matter) by setting a key value pair in the locals() dictionary.
In the case of
eval
, the second and third parameters allow you to pass in local and global variables, and so you could simplify the populate function to just this:The above is how I used
eval
to do f-string population (or simplistic template evaluation). Buteval
can also be used to provide variable variables.您可以使用 字典 来完成此操作。字典是键和值的存储。
可以使用可变键名来达到可变变量的效果,而且不会有安全风险。
对于您正在考虑执行诸如
list 之类的操作的情况,可能更合适比一个字典。列表表示对象的有序序列,具有整数索引:
对于有序序列,列表比具有整数键的字典更方便,因为列表支持按索引顺序迭代,切片、
追加
以及其他需要使用字典进行笨拙密钥管理的操作。You can use dictionaries to accomplish this. Dictionaries are stores of keys and values.
You can use variable key names to achieve the effect of variable variables without the security risk.
For cases where you're thinking of doing something like
a list may be more appropriate than a dict. A list represents an ordered sequence of objects, with integer indices:
For ordered sequences, lists are more convenient than dicts with integer keys, because lists support iteration in index order, slicing,
append
, and other operations that would require awkward key management with a dict.使用内置的
getattr
函数获取按名称指定对象的属性。根据需要修改名称。Use the built-in
getattr
function to get an attribute on an object by name. Modify the name as needed.这不是一个好主意。如果您要访问全局变量,可以使用
globals()
< /a>.如果要访问本地范围内的变量,可以使用
locals()< /code>
,但不能为返回的字典赋值。
更好的解决方案是使用
getattr
或将变量存储在字典中,然后按名称访问它们。It's not a good idea. If you are accessing a global variable you can use
globals()
.If you want to access a variable in the local scope you can use
locals()
, but you cannot assign values to the returned dict.A better solution is to use
getattr
or store your variables in a dictionary and then access them by name.新编码员有时会编写这样的代码:
然后,编码员会留下一堆命名变量,编码工作量为 O(m * n),其中 m 是命名变量的数量,n 是需要访问(包括创建)这组变量的次数。更精明的初学者观察到每一行中的唯一区别是根据规则更改的数字,并决定使用循环。然而,他们陷入了如何动态创建这些变量名称的困境,并且可能会尝试这样的事情:
他们很快发现这不起作用。
如果程序需要任意变量“名称”,则字典是最佳选择,如其他答案中所述。但是,如果您只是尝试创建许多变量并且不介意用整数序列引用它们,那么您可能正在寻找
列表
。如果您的数据是同质的,例如每日温度读数、每周测验分数或图形小部件网格,则尤其如此。可以按如下方式组装:
此
list
也可以通过推导式在一行中创建:任一情况的结果都是填充的
list
,其中第一个元素可通过以下方式访问:my_calculator.buttons[0]
,下一个是my_calculator.buttons[1]
,依此类推。 “基本”变量名称成为列表的名称,并且使用变化的标识符来访问它。最后,不要忘记其他数据结构,例如
set
- 这类似于字典,只不过每个“名称”没有附加值。如果您只需要一“袋”物品,这可能是一个不错的选择。而不是这样的:您将拥有这样的:
使用
list
表示一系列相似的对象,使用set
表示任意顺序的对象包,或者使用>dict
用于一包具有关联值的名称。New coders sometimes write code like this:
The coder is then left with a pile of named variables, with a coding effort of O(m * n), where m is the number of named variables and n is the number of times that group of variables needs to be accessed (including creation). The more astute beginner observes that the only difference in each of those lines is a number that changes based on a rule, and decides to use a loop. However, they get stuck on how to dynamically create those variable names, and may try something like this:
They soon find that this does not work.
If the program requires arbitrary variable "names," a dictionary is the best choice, as explained in other answers. However, if you're simply trying to create many variables and you don't mind referring to them with a sequence of integers, you're probably looking for a
list
. This is particularly true if your data are homogeneous, such as daily temperature readings, weekly quiz scores, or a grid of graphical widgets.This can be assembled as follows:
This
list
can also be created in one line with a comprehension:The result in either case is a populated
list
, with the first element accessed withmy_calculator.buttons[0]
, the next withmy_calculator.buttons[1]
, and so on. The "base" variable name becomes the name of thelist
and the varying identifier is used to access it.Finally, don't forget other data structures, such as the
set
- this is similar to a dictionary, except that each "name" doesn't have a value attached to it. If you simply need a "bag" of objects, this can be a great choice. Instead of something like this:You will have this:
Use a
list
for a sequence of similar objects, aset
for an arbitrarily-ordered bag of objects, or adict
for a bag of names with associated values.每当您想使用可变变量时,最好使用字典。 不必
因此,您
编写这样的代码,这样您就不会意外地覆盖以前存在的变量(这是安全方面的),并且您可以拥有不同的“命名空间”。
Whenever you want to use variable variables, it's probably better to use a dictionary. So instead of writing
you write
This way you won't accidentally overwrite previously existing variables (which is the security aspect) and you can have different "namespaces".
使用
globals()
(免责声明:这是一种不好的做法,但这是对您的问题最直接的答案,请使用已接受答案中的其他数据结构)。实际上,您可以动态地将变量分配给全局范围,例如,如果您想要在全局范围内访问 10 个变量
i_1
,i_2
...i_10
:这会将“a”分配给所有这 10 个变量,当然您也可以动态更改该值。现在可以像其他全局声明的变量一样访问所有这些变量:
Use
globals()
(disclaimer: this is a bad practice, but is the most straightforward answer to your question, please use other data structure as in the accepted answer).You can actually assign variables to global scope dynamically, for instance, if you want 10 variables that can be accessed on a global scope
i_1
,i_2
...i_10
:This will assign 'a' to all of these 10 variables, of course you can change the value dynamically as well. All of these variables can be accessed now like other globally declared variable:
除了字典之外,您还可以使用
namedtuple
来自集合模块,这使得访问更容易。例如:
Instead of a dictionary you can also use
namedtuple
from the collections module, which makes access easier.For example:
SimpleNamespace
类可用于创建使用setattr
或子类SimpleNamespace
创建新属性,并创建您自己的函数来添加新属性名称(变量)。The
SimpleNamespace
class could be used to create new attributes withsetattr
, or subclassSimpleNamespace
and create your own function to add new attribute names (variables).如果您不想使用任何对象,您仍然可以在当前模块中使用
setattr()
:If you don't want to use any object, you can still use
setattr()
inside your current module:Python 中的变量
输出:
使用 globals()、locals() 或 vars() 将产生相同的结果
输出:
奖励(从字符串创建变量)
创建变量并解包元组:
输出:
Variable variables in Python
Output:
Using globals(), locals(), or vars() will produce the same results
Output:
Bonus (creating variables from strings)
Creating variables and unpacking tuple:
Output:
您必须使用
globals()
内置方法 实现该行为:You have to use
globals()
built in method to achieve that behaviour: