我想通过Python中的while循环动态创建变量。有人有创造力吗?

评论

您能否解释“通过一个while循环”?我不知道那是什么意思。

解决什么问题?需要一些上下文。

我想创建一个while循环,并在该循环内让它不断创建变量,直到我告诉它停止为止。这有意义吗?

您是什么意思“动态创建变量”?动态如何?您可以只使用字典并为其指定各种值吗?

@Trivikram:不正确,变量范围是整个函数,而不仅仅是while循环。

#1 楼

除非非常需要创建一堆变量名,否则我将只使用字典,在其中可以动态创建键名并将每个键名关联一个值。

a = {}
k = 0
while k < 10:
    <dynamically create key> 
    key = ...
    <calculate value> 
    value = ...
    a[key] = value 
    k += 1


新的“集合”模块中还有一些有趣的数据结构可能适用:

http://docs.python.org/dev/library/collections.html

评论


@Josh等...在字典中创建项目(键,值)与在也被实现为字典的locals()或globals()中创建相同。我不知道为什么我被某个投票不足的狙击手拒绝了,因为我的答案在globals()中创建了一个项目,而Gintautas Miliauskas的答案却被投票了,而这个没有给出<动态创建键>操作方法的答案也被投票了3次。

–eyquem
2011-2-18在2:10

@eyquem我没有提供创建密钥的任何特定方法,因为我对OP实际需要的命名方案一无所知。相反,我只是给出了最通用,最干净的方案来解决该问题。

– JoshAdel
2011-2-18的2:36

@eyquem局部变量未实现为字典。几乎总是,locals()函数根据局部变量创建字典,但是除非调用locals(),否则字典不存在。

–邓肯
2011-2-18在8:20

@eyquem,本地名称空间被实现为堆栈上的插槽,因此字节码可以将它们直接引用为堆栈帧中的偏移量(加上调用locals()时也包含的自由变量。Python2.x中的例外您可以在函数内部使用exec而不为exec指定本地名称空间。我不确定在哪里有记录:这不是语言定义的一部分,因为不同的实现可以选择不同的方式来实现本地名称空间。

–邓肯
2011-2-18在15:30

这是最好的答案。结果,这应该是规范的问题。

–马辛
14年8月15日在16:54

#2 楼

使用globals()可以实现:

import random

alphabet = tuple('abcdefghijklmnopqrstuvwxyz')


print '\n'.join(repr(u) for u in globals() if not u.startswith('__'))

for i in xrange(8):
    globals()[''.join(random.sample(alphabet,random.randint(3,26)))] = random.choice(alphabet)

print

print '\n'.join(repr((u,globals()[u])) for u in globals() if not u.startswith('__'))


一个结果:

'alphabet'
'random'

('hadmgoixzkcptsbwjfyrelvnqu', 'h')
('nzklv', 'o')
('alphabet', ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'))
('random', <module 'random' from 'G:\Python27\lib\random.pyc'>)
('ckpnwqguzyslmjveotxfbadh', 'f')
('i', 7)
('xwbujzkicyd', 'j')
('isjckyngxvaofdbeqwutl', 'n')
('wmt', 'g')
('aesyhvmw', 'q')
('azfjndwhkqgmtyeb', 'o')


我之所以使用随机是因为您没有说明要提供哪些“变量”名称,以及要创建哪些值。因为我认为创建名称而不绑定到对象是不可能的。

评论


OP需要一种创建与许多名称关联的许多值的方法。他说这是“动态创建变量”,但是使用字典是解决他的实际问题的正确方法。

– Ned Batchelder
2011-2-18在2:22

@Ned Batchelder也许这个问题被误导了。但我认为让他得到两个答案可能会更好:1-是的,您可以做您想做的事2-但是,出于这个原因,您要进入的方式并不是一个明智的选择。这样做,OP将学习两件事:Python功能强大,以及一些正确编码的建议。相反,如果阻止任何人自己思考和思考问题,那就是对头脑风暴和反思的一种约束。

–eyquem
2011-2-18在2:25

我认为您之所以被否决是因为,将垃圾邮件发送到globals字典通常不被视为最佳实践。实际上,在您自己的代码示例中,如果您的随机密钥生成器要生成一个已经存在于globals dict中的密钥(例如,密钥“ alphabet”),您会发生什么。另外,我认为OP的问题暗示他在创建“变量”后需要获取变量。他如何使用您的解决方案将他的动态变量与全局范围内已经存在的变量区分开?在这种情况下,单独的字典会更好。

– apiguy
2011-2-18在6:05

这是一个很好的答案。我偶然发现答案,但确实有这样做的必要,这使我不必写几乎重复的问题。

–acjay
13年6月6日在13:27

值得指出的是,这个答案提供了动态创建全局变量的方法。这意味着在globals()上定义的每个变量都将进入模块名称空间,并保持在那里,直到程序结束。在大多数情况下,当人们说“变量”时,它们表示函数局部变量,仅在执行函数的上下文中存在。在这种情况下,globals()可能无法解决问题。像JoshAdel提供的答案一样,考虑显式使用字典。

– Davide R.
15年6月29日在12:39

#3 楼

使用exec()方法。例如,假设您有一个词典,并且想要将每个键转换为其原始词典值的变量,则可以执行以下操作。

Python 2

>>> c = {"one": 1, "two": 2}
>>> for k,v in c.iteritems():
...    exec("%s=%s" % (k,v))

>>> one
1
>>> two
2


Python 3

>>> c = {"one": 1, "two": 2}
>>> for k,v in c.items():
...    exec("%s=%s" % (k,v))

>>> one
1
>>> two
2


评论


是的,这可以工作,但是我不知道您为什么要这样做-请记住,显式比隐式好,并且“可读性很重要”。恕我直言,这只是一个坏主意。

–托尼·萨福克66
2014年7月2日在18:31

@ chris-piekarski感谢您的回答。想要执行此操作的原因之一是,当您需要与希望将输入作为局部变量传递的第三方软件进行通信时,并且在编译时您不知道其期望的变量(我正在创建一个Paraview插件)例如,并且施加了这种约束)。

–丹尼尔(Daniel)
15年1月8日在17:42

请注意,这在函数执行上下文中的Python 3中不起作用。在顶层(模块)上下文中仍然可以。如果需要创建模块变量,建议您编辑globals()dict,或在模块对象上调用setattr()。

– Davide R.
15年6月29日在12:44

我还要强调一下,通常,当键或值由外部数据(用户输入,文件或其他任何内容)提供时,这会带来安全风险。使用eval / exec时的常规警告适用。您不希望有人将值设置为“ send_me_all_your_private_data()”并使其在您的计算机上执行。

– Davide R.
15年6月29日在12:48

实际上,这是一个很好的答案,并且是特定情况下的唯一解决方案。假设您有一个代表库存的数组。假设此库存中可以包含容器,并且这些容器都有自己的库存,代表该容器正在存放的物品。我知道这是唯一能够将INDEXES存储在字符串中并能够对其进行更改并动态访问不同索引的方法,例如如果您更改要查找的容器。

–道格拉斯
16年11月16日在19:38

#4 楼

将内容填充到全局和/或本地名称空间不是一个好主意。使用dict是如此的另一些语言... d['constant-key'] = value看起来很尴尬。 Python是OO。用大师的话来说:“”“命名空间是一个很棒的主意-让我们做更多的主意吧!”“”

类似:

>>> class Record(object):
...     pass
...
>>> r = Record()
>>> r.foo = 'oof'
>>> setattr(r, 'bar', 'rab')
>>> r.foo
'oof'
>>> r.bar
'rab'
>>> names = 'id description price'.split()
>>> values = [666, 'duct tape', 3.45]
>>> s = Record()
>>> for name, value in zip(names, values):
...     setattr(s, name, value)
...
>>> s.__dict__ # If you are suffering from dict withdrawal symptoms
{'price': 3.45, 'id': 666, 'description': 'duct tape'}
>>>


评论


我不明白你想说什么。为什么全局和局部名称空间不是好主意?因为“大多数名称空间当前都实现为Python词典”?那词典是“其他语言的”?为什么对字典有这样的批评?您认为实例的名称空间比字典更好用吗?好吧...你知道吗:

–eyquem
2011-2-18的3:20

“名称空间是从名称到对象的映射。大多数名称空间当前都是作为Python字典实现的,但通常不会以任何方式引起注意(性能除外),并且将来可能会发生变化。名称空间的示例包括:内置名称(如abs()和内置异常名称之类的功能);模块中的全局名称;函数调用中的局部名称。从某种意义上说,对象的属性集也形成了一个命名空间“

–eyquem
2011-2-18在3:21



(docs.python.org/release/2.5/tut/…)作者是GvR本人,它是用2.5版本编写的,但是不久以后,这就是为什么我提供此链接

–eyquem
2011-2-18在3:25



似乎没有字典以外的救赎。无论如何,Python是基于对象的,并在名称和对象之间到处使用映射,这是数据模型,因此无法逃避这一事实。那就是我所想的。我错了吗 ?

–eyquem
2011-2-18在3:29



顺便说一句:尽管有我的论点,我还是更喜欢您的解决方案。这比使用globals()更简单。我喜欢使用setattr()

–eyquem
2011-2-18在11:03



#5 楼

vars()['meta_anio_2012'] = 'translate'


评论


这与执行locals()['meta_anio_2012'] ='translate'相同,该函数无法在函数中使用,并且在文档中进行了特别警告。它还遭受其他答案的注释中指出的许多问题。

– DSM
2013年6月4日15:42



使用vars()函数来修改对象的变量绝对没有错,但是您需要对其稍加更新以使用它来将变量设置为模块(通过传入模块对象)。 vars(sys.modules [__ name __])['my_variable'] ='value'这样做没有错,因为它可以获取基础对象的__dict__。唯一可能不起作用的是,如果要获取的对象对属性具有写权限。

– OozeMeister
19-2-25在4:08



#6 楼

关键字参数允许您将变量从一个函数传递到另一个函数。这样,您可以将字典的键用作变量名(可以在while循环中填充该变量)。字典名称被调用时只需在其前面加上**

# create a dictionary
>>> kwargs = {}
# add a key of name and assign it a value, later we'll use this key as a variable
>>> kwargs['name'] = 'python'

# an example function to use the variable
>>> def print_name(name):
...   print name

# call the example function
>>> print_name(**kwargs)
python


没有**kwargs只是字典:

>>> print_name(kwargs)
{'name': 'python'}


#7 楼

注意:应该将其视为讨论而不是实际答案。

一种近似方法是在要创建变量的模块中操作__main__。例如,有一个b.py

#!/usr/bin/env python
# coding: utf-8


def set_vars():
    import __main__
    print '__main__', __main__
    __main__.B = 1

try:
    print B
except NameError as e:
    print e

set_vars()

print 'B: %s' % B


运行它会输出

$ python b.py
name 'B' is not defined
__main__ <module '__main__' from 'b.py'>
B: 1


,但是这种方法仅适用于一个单一模块脚本,因为它导入的__main__将始终代表python正在执行的入口脚本的模块,这意味着,如果b.py被其他代码所涉及,则将在入口脚本的范围内创建B变量,而不是在b.py本身中。假设有一个脚本a.py

#!/usr/bin/env python
# coding: utf-8

try:
    import b
except NameError as e:
    print e

print 'in a.py: B', B


运行它会输出

$ python a.py
name 'B' is not defined
__main__ <module '__main__' from 'a.py'>
name 'B' is not defined
in a.py: B 1


请注意,__main__是更改为'a.py'

评论


我的方法是..,new_var = eval('old_var'+ str(count))

– Shirjeel Ahmed Khan
19年4月26日在5:40

#8 楼

对于自由:

import random

alphabet = tuple('abcdefghijklmnopqrstuvwxyz')

globkeys = globals().keys()
globkeys.append('globkeys') # because name 'globkeys' is now also in globals()

print 'globkeys==',globkeys
print
print "globals().keys()==",globals().keys()

for i in xrange(8):
    globals()[''.join(random.sample(alphabet,random.randint(3,26)))] = random.choice(alphabet)
del i

newnames = [ x for x in globals().keys() if x not in globkeys ]
print
print 'newnames==',newnames

print
print "globals().keys()==",globals().keys()

print
print '\n'.join(repr((u,globals()[u])) for u in newnames)


结果

globkeys== ['__builtins__', 'alphabet', 'random', '__package__', '__name__', '__doc__', 'globkeys']

globals().keys()== ['__builtins__', 'alphabet', 'random', '__package__', '__name__', 'globkeys', '__doc__']

newnames== ['fztkebyrdwcigsmulnoaph', 'umkfcvztleoij', 'kbutmzfgpcdqanrivwsxly', 'lxzmaysuornvdpjqfetbchgik', 'wznptbyermclfdghqxjvki', 'lwg', 'vsolxgkz', 'yobtlkqh']

globals().keys()== ['fztkebyrdwcigsmulnoaph', 'umkfcvztleoij', 'newnames', 'kbutmzfgpcdqanrivwsxly', '__builtins__', 'alphabet', 'random', 'lxzmaysuornvdpjqfetbchgik', '__package__', 'wznptbyermclfdghqxjvki', 'lwg', 'x', 'vsolxgkz', '__name__', 'globkeys', '__doc__', 'yobtlkqh']

('fztkebyrdwcigsmulnoaph', 't')
('umkfcvztleoij', 'p')
('kbutmzfgpcdqanrivwsxly', 'a')
('lxzmaysuornvdpjqfetbchgik', 'n')
('wznptbyermclfdghqxjvki', 't')
('lwg', 'j')
('vsolxgkz', 'w')
('yobtlkqh', 'c')


另一种方式:

import random

pool_of_names = []
for i in xrange(1000):
    v = 'LXM'+str(random.randrange(10,100000))
    if v not in globals():
        pool_of_names.append(v)

alphabet = 'abcdefghijklmnopqrstuvwxyz' 

print 'globals().keys()==',globals().keys()

print
for j in xrange(8):
    globals()[pool_of_names[j]] = random.choice(alphabet)
newnames = pool_of_names[0:j+1]

print
print 'globals().keys()==',globals().keys()

print
print '\n'.join(repr((u,globals()[u])) for u in newnames)


结果:

globals().keys()== ['__builtins__', 'alphabet', 'random', '__package__', 'i', 'v', '__name__', '__doc__', 'pool_of_names']


globals().keys()== ['LXM7646', 'random', 'newnames', 'LXM95826', 'pool_of_names', 'LXM66380', 'alphabet', 'LXM84070', '__package__', 'LXM8644', '__doc__', 'LXM33579', '__builtins__', '__name__', 'LXM58418', 'i', 'j', 'LXM24703', 'v']

('LXM66380', 'v')
('LXM7646', 'a')
('LXM8644', 'm')
('LXM24703', 'r')
('LXM58418', 'g')
('LXM84070', 'c')
('LXM95826', 'e')
('LXM33579', 'j')


评论


-1:说两次并不是一个好主意。修改globals()不好,并且只能在非常特殊的情况下进行,通常涉及编码工具。如果您需要一组动态的命名值,请使用字典,这就是它们的用途。

– Ned Batchelder
2011-2-18在12:34

为什么要添加globals()只是为了转身并为您转储的所有名称保留一个单独的列表?字典将以更清洁,更简单,更易懂,更灵活和更安全的方式为您处理所有这些问题。仅仅因为您可以做某事并不意味着您应该做某事。

– Ned Batchelder
2011-2-18在12:35

@Ned Batchelder两次投票并没有使我理解更多。我不假装这两个代码是完美的论点:它们只是对自由主义在2点上提出批评的答案。他们不想证明使用globals()['X']来创建一个名称为X的新对象是很好的,该对象将被使用如下:li.append(X)等;

–eyquem
2011-2-18在16:33

@Ned Batchelder现在,多亏了约翰·马钦(John Machin)的回答和CODE,我知道了另一种方式:使用setattr()在名称为X的实例中创建一个新属性:很好。否则我什么都不懂。到现在为止,我编写了一些代码,约翰·马钦(John Machin)也是如此,邓肯(Duncan)给了我准确的解释,而您仅满足于两次下票并发出教条化的句子,即Modifying globals()是不好的。不要让我明白

–eyquem
2011-2-18在16:44

@Ned Batchelder而且,绝对地修改globals()也可以,因为我们在xrange(20)中只写v = 48或i时修改了globals()。我认为这在很大程度上是因为编写globals()[“ v”] = 48看起来很长而且很奇怪,因此没有认真考虑。但是,真正的怪异在哪里呢?我不明白

–eyquem
2011-2-18在16:53