dict理解中的Python元组解包

dict理解中的Python元组解包,python,dictionary,iterable-unpacking,dictionary-comprehension,Python,Dictionary,Iterable Unpacking,Dictionary Comprehension,我正在尝试编写一个函数,将形式为'a=5,b=7'的字符串转换为dict{'a':5,'b':7}。下面的代码片段是在主for循环中发生的-它们将字符串的单个部分转换为单个dict元素 这很好: s = 'A=5' name, value = s.split('=') d = {name: int(value)} 这不是: s = 'A=5' d = {name: int(value) for name, value in s.split('=')} ValueError: need more

我正在尝试编写一个函数,将形式为
'a=5,b=7'
的字符串转换为dict
{'a':5,'b':7}
。下面的代码片段是在主
for
循环中发生的-它们将字符串的单个部分转换为单个dict元素

这很好:

s = 'A=5'
name, value = s.split('=')
d = {name: int(value)}
这不是:

s = 'A=5'
d = {name: int(value) for name, value in s.split('=')}
ValueError: need more than 1 value to unpack

为什么我不能在dict理解中打开元组呢?如果我能做到这一点,那么我可以很容易地将整个函数变成一个紧凑的dict理解。

在代码中,
s.split('=')
将返回列表:
['a',5']
。迭代该列表时,每次都会返回一个字符串(第一次是
'a'
,第二次是
'5'
),因此无法将该字符串解压为两个变量

您可以尝试:
对于名称,使用[s.split('=')中的值。]

更有可能的是,您有一个要拆分的字符串的iterable,然后您的dict理解变得简单(2行):

当然,如果你沉迷于单行程序,你可以将它组合起来,但我不会。下面的代码如何:

a="A=5, b=9"
b=dict((x, int(y)) for x, y in re.findall("([a-zA-Z]+)=(\d+)", a))
print b
输出:

{'A': 5, 'b': 9}
例如,此版本还可以与其他形式的输入一起使用

a="A=5 b=9 blabla: yyy=100"
我会给你

{'A': 5, 'b': 9, 'yyy': 100}

请参阅mgilson错误发生原因的答案。要实现您的目标,您可以使用:

d = {name: int(value) for name,value in (x.split('=',1) for x in s.split(','))}
要计算空格,请根据需要使用
.strip()
(例如:
x.strip().split('=',1)

为了可读性,您应该使用普通for in-loop,而不是理解

strs='A=5, b=7'
dic={}
for x in strs.split(','):
  name,val=x.split('=')
  dic[name.strip()]=int(val)

当然你可以这样做:

>>> s = 'A=5, b=7'
>>> {k: int(v) for k, v in (item.split('=') for item in s.split(','))}
{'A': 5, ' b': 7}
但在这种情况下,我只会使用更重要的代码:

>>> d = {}
>>> for item in s.split(','):
        k, v = item.split('=')
        d[k] = int(v)


>>> d
{'A': 5, ' b': 7}

有些人倾向于相信你会因为使用
eval
而下地狱,但是

s = 'A=5, b=7'
eval('dict(%s)' % s)
或者更好,为了安全(感谢mgilson指出这一点):

这个怎么样

>>> s
'a=5, b=3, c=4'
>>> {z.split('=')[0].strip(): int(z.split('=')[1]) for z in s.split(',')}
{'a': 5, 'c': 4, 'b': 3}

如果我将
s.split('=')
作为列表中的唯一元素,这是否有效
对于name,在[s.split('=')]
中的值?我编写comment@BigYellowCactus--苏尼斯。直到今天早上我才发现自己离得有多近。(我一直在更努力地获得史诗级的作品,但我离这部作品还有一点距离)。这有点可笑——也许我的答案越来越好了,但我有点相信人们才刚刚开始对我的东西进行评价,因为我有将近1.5万个代表…@BigYellowCactus——我知道我的技能已经因为这么久的闲逛而有所提高。也许有一天我会用它来学习ruby之类的东西。。。我也希望有一天能拿到银(和金)的gnuplot徽章,但遗憾的是,这个标签上没有足够的问题@mgilson我正在尽我最大的努力去做
pygame
,但是即使是铜牌也很难得到:-)数字仍然是字符串可能没有必要,但是为什么不使用
\w+
而不是
[a-zA-Z]
。唯一真正的区别是你将开始在左手边选择下划线(和数字?)。当然,这可以是多种多样的,这只是一个例子。另外,
\u w=5
将匹配,标识符可能只是字母(来自他的示例)。如果需要,您必须为有效标识符添加一个更复杂的表达式(
\u w
对C/C++f.e.)不好。我正要给出一个答案:如果要彻底检查,还可以使用
.split('=',1)
,以确保正确解压。@mgilson如果输入格式不正确,仍会发生异常。。。(即,当调用
int(value)
-时,它仍然是
ValueError
)@mgibsonbr——这一点很好。我没有想到在打开元组后会发生什么。虽然这个错误可能比其他“没有足够的参数来解包”稍微有用一些。我考虑过这一点,但我从不喜欢直接为列表编制索引。我想知道是否有一种更具可读性的方法来执行此操作这也会将字符串拆分为所需的两倍,这有点浪费,因为您“获得”的唯一好处是将代码放入1行(难以读取)而不是4行(易于读取)…您可以使其更安全:
eval('dict(%s)%s,{“内置”:无,'dict':dict})
--我认为使用此选项将关闭注入型攻击的漏洞(尽管如果我错了,我希望通过(最好是友好的)评论听到)。我肯定会选择清晰、简单的函数版本,而不是代码中任何内联版本,因为我预期这些版本的运行时间会超过一次。它肯定更符合Python的Zen。你的问题是“为什么我不能解包元组…”因此,我将避免添加到不断增长的答案中,这些答案实际上会告诉您如何解决这个问题,但一个简单的方法是使用带有iterable参数的
dict
构造函数。
s = 'A=5, b=7'
eval('dict(%s)' % s)
s = 'A=5, b=7'
eval('dict(%s)' % s, {'__builtins__': None, 'dict': dict})
>>> s
'a=5, b=3, c=4'
>>> {z.split('=')[0].strip(): int(z.split('=')[1]) for z in s.split(',')}
{'a': 5, 'c': 4, 'b': 3}