本问题已经有最佳答案,请猛点这里访问。
是否可以基于字符串的值创建变量名?
我有一个脚本,它将读取一个文件中的信息块,并将它们存储在字典中。然后将每个块的字典附加到"master"字典中。文件中信息块的数量会有所不同,并使用"完成"一词来指示块的结尾。
我想这样做:
master={}
block=0
for lines in file:
if line !="done":
$block.append(line)
elif line =="done":
master['$block'].append($block)
block = block + 1
如果文件包含这样的内容:
eggs
done
bacon
done
ham
cheese
done
号
结果将是一本字典,有3个列表:
master = {'0': ["eggs"], '1': ["bacon"], '2': ["ham","cheese"]}
这是怎么做到的?
把你的字典变成了python字典。
在我看来,你似乎不需要字典,因为你正在使用从0开始的整数对字典项进行顺序索引。而是使用列表列表。
也许我不应该包括这个例子,但我仍然想知道是否有一种方法可以根据字符串的值(而不仅仅是字典键)来命名变量。
我真的建议你用列表来代替。有没有什么具体的点,为什么你需要数组式的听写?
如果可以使用数组,则可以使用以下命令:
with open("yourFile") as fd:
arr = [x.strip().split() for x in fd.read().split("done")][:-1]
输出:
[['eggs'], ['bacon'], ['ham', 'cheese']]
。
如果需要数字字符串索引,可以使用以下方法:
with open("yourFile") as fd:
l = [x.strip().split() for x in fd.read().split("done")][:-1]
print dict(zip(map(str,range(len(l))),l))
@投反对票的人:你能解释一下行动吗?
为什么有人投反对票?在我看来,它比其他答案更正确,因为它不仅回答了问题,而且提供了比OP预期更优雅的数据结构。
@劳弗尔:我没抓到你。什么??
我同意这一点,一个列表是一个更好的数据结构-我实际上正在为我的答案写一个类似的想法。这就是说,我觉得你的第二部分很难看——如果你想要听写,按照我的方法,在列表中,按照第一个thrustmaster的方法。
@Thrustmaster:不过,我建议您用for循环来构造您的应答代码,因为OP似乎已经比较适合使用这种流控制语法了。更简洁并不一定更好,尤其是当涉及到列表理解和生成器表达式时。
@亚瑟,我不认为这意味着你应该放弃更恰当(并且在所有方面都更好)的清单理解。
@弗朗西斯:是的,我明白。但是,建议一种更易读、更简洁、更为Python式的做事方式有什么坏处吗?
不幸的是,列表理解泄漏了一个文件引用。(旁注:我认为从itertools.count获得回报时打电话给str比getnextnumber要干净得多。)
@朋友们:我不是想建议你们不要把自己的清单包括在内,不要说它是正确的做事方式。然而,由于对于初学者来说,这种语法通常不熟悉或不直观,所以我通常额外提供类似的for循环版本,供初学者参考。
@DSM一般来说,字典的一个更干净的解决方案是一个简单的带有defaultdict的循环。
@DSM:谢谢你指出这一点。当我试图使它紧凑的时候,我没有想到这一点。:)
你似乎误解了字典的工作原理。他们拿的钥匙是物体,所以这里不需要魔法。
但是,我们可以使用collections.defaultdict根据需要制作子列表,从而使您的代码更好。
from collections import defaultdict
master = defaultdict(list)
block = 0
for line in file:
if line =="done":
block += 1
else:
master[block].append(line)
不过,我建议,如果你想要连续的、有编号的索引,字典是不必要的——这就是列表的目的。在这种情况下,我建议您遵循Thrustmaster的第一个建议,或者作为一个替代方案:
from itertools import takewhile
def repeat_while(predicate, action):
while True:
current = action()
if not predicate(current):
break
else:
yield current
with open("test") as file:
action = lambda: list(takewhile(lambda line: not line =="done", (line.strip() for line in file)))
print(list(repeat_while(lambda x: x, action)))
号
我认为"完成"的分裂注定要失败。考虑以下列表:
eggs
done
bacon
done
rare steak
well done stake
done
。
从Thrustmaster偷东西(我偷东西给了+1),我建议:
>>> dict(enumerate(l.split() for l in open(file).read().split('
done
') if l))
{0: ['eggs'], 1: ['bacon'], 2: ['ham', 'cheese']}
我知道这需要一个尾随的""。如果有问题,可以使用"open(file.read()+''"或甚至"+'行'",如果最后完成是可选的。
这是您的代码,用于并列:
master={}
block=0
for lines in file:
if line !="done":
$block.append(line)
elif line =="done":
master['$block'].append($block)
block = block + 1
。
正如ThrustMaster在文章中提到的,在这里使用嵌套列表更有意义。以下是您将如何做到这一点的方法;我在结构上尽可能少地更改了您的原始代码:
master=[[]] # Start with a list containing only a single list
for line in file: # Note the typo in your code: you wrote"for lines in file"
if line !="done":
master[-1].append(line) # Index -1 is the last element of your list
else: # Since it's not not"done", it must in fact be"done"
master.append([])
。
这里唯一的一点是,在您的EDOCX1[1]列表的末尾会有一个额外的列表,因此您应该在EDOCX1[2]中添加一行,以检测最后一个空子列表:
del master[-1]
使用setattr或globals()。请参阅如何在当前模块上调用setattr()?
读一读这个问题,其实这不是他要问的。
事实上,如果是这样的话,你的答案是正确的,所以我将把那个留在这里,投票给你。