50

我正在学习 Python,目前正在通过字典进行更多学习。

我在想;

如果我有一个像这样的字典:d = {'key_1': 'value_a', 'key_2': 'value_b'}并且我想将此字典分离/划分为变量,其中每个变量是字典中的一个键,每个变量值是字典中该键的值。

实现这一目标的最佳pythonic方法是什么?

d = {'key_1': 'value_a', 'key_2': 'value_b'}
#perform the command and get
key_1 = 'value_a'
key_2 = 'value_b'

我试过了:key_1, key_2 = d但它没有用。

基本上,我正在寻求专家的智慧,以了解是否有更好的方法将 2 行代码减少为 1 行。

注意:这不是动态变量创建。

4

10 回答 10

64

现有的答案将起作用,但它们本质上都是在重新实现 Python 标准库中已经存在的函数:operator.itemgetter()

文档

返回一个可调用对象,该对象使用操作数的 __getitem__() 方法从其操作数中获取项目。如果指定了多个项目,则返回查找值的元组。例如:

在 f = itemgetter(2) 之后,调用 f(r) 返回 r[2]。

在 g = itemgetter(2, 5, 3) 之后,调用 g(r) 返回 (r[2], r[5], r[3])。


换句话说,你的解构 dict 分配变成了这样:

from operator import itemgetter

d = {'key_1': 'value_a', 'key_2': 'value_b'}
key_1, key_2 = itemgetter('key_1', 'key_2')(d)

# prints "Key 1: value_a, Key 2: value_b"
print("Key 1: {}, Key 2: {}".format(key_1, key_2))
于 2018-03-16T05:53:22.613 回答
28

问题是 dicts 是无序的,所以你不能使用简单的d.values(). 您当然可以首先按键对字典进行排序,然后解压缩值:

# Note: in python 3, items() functions as iteritems() did
#       in older versions of Python; use it instead
ds = sorted(d.iteritems())
name0, name1, name2..., namen = [v[1] for v in ds]

你也可以,至少在一个对象内,做类似的事情:

for k, v in dict.iteritems():
    setattr(self, k, v)

此外,正如我在上面的评论中提到的,如果您可以将需要解压字典的所有逻辑作为变量放入函数中,您可以这样做:

def func(**kwargs):
    # Do stuff with labeled args

func(**d)
于 2012-06-22T13:11:00.693 回答
23

以前没有提到的解决方案是

dictget = lambda d, *k: [d[i] for i in k]

然后使用它:

key_1, key_2 = dictget(d, 'key_1', 'key_2')

其优点是即使要检索更多变量,它也具有很强的可读性。

然而,更具可读性的是一个“真正的”函数,例如

def dictget(d, *k):
    """Get the values corresponding to the given keys in the provided dict."""
    return [d[i] for i in k]
    # or maybe
    return (d[i] for i in k) # if we suppose that we have bigger sets of result
    # or, equivalent to this
    for i in k:
        yield d[i]

它也支持使用文档字符串进行评论,并且是首选。

于 2012-06-22T13:51:37.923 回答
5
var1, var2 = (lambda key1, key2: (key1, key2))(**d)

如果你想让任何阅读你的代码的人头疼,你可以使用匿名函数来解包这样的值。

于 2013-08-27T12:53:17.333 回答
4

如果你够勇敢,你可以这样做:

for k, v in d.items():
    locals()[k] = v

但是勇敢可能还不够——你可能还必须鲁莽等等。

如果你想成为像@ecatmur 一样鲁莽的英雄,你可以这样做:

locals().update(d)

但是现在 OP 更新了他的问题并回答了评论,看来这不是他真正想做的。仅作记录:动态创建变量有充分的理由——即使这里的每个人都同意它不是 Pythonic。很多解释器风格的问题都可以通过动态改变你的范围来解决。只需以受控方式执行此操作即可。而且......呃,不要将它部署到一些生产站点;)

于 2012-06-22T13:15:47.297 回答
2

我实际上有一个用例,在其中我将__init__方法的所有参数拉入对象构造的 self 命名空间中:

vars(self).update(somedict)

vars函数为您提供与传递的对象关联的“命名空间”的字典。但是,由于 CPython 的实现细节,这不适用于函数中的局部变量。所以它不应该适用于所有的口译员。

对于全局命名空间,您可以替换vars(self)globals(),但这确实表明您的逻辑有问题。如前所述,对于局部变量,这无论如何都不起作用(NameError即使您为字典分配了值也会如此)。

于 2012-06-22T13:15:00.937 回答
2

我认为这应该可以解决您的问题

d = {'key_1': 'value_a', 'key_2': 'value_b'}
for k,v in d.items():
    exec '%s=%s'%(k,v)
于 2012-06-22T17:38:06.447 回答
1

@glglgl 的回答不是最多票,这个回答对我有用,

solution1={'variable': np.array([75, 74]), 'function': 0}

def dict_get(d, *k):
    for i in k:
        yield d[i]


variables, obj_func = dict_get(solution1, 'variable', 'function')

a, b=variables

print(a)

参考:@glglgl

于 2021-01-30T07:40:10.380 回答
0

不建议动态声明变量,因为很难找到变量名的来源。也就是说,可以在 python 中组合一个解决方案动态变量名,但我不推荐它。使用普通的旧字典可能会更好。

于 2012-06-22T13:14:30.667 回答
-1

这是一个解决方案,它在调用堆栈帧上使用 Python 的检查模块来确定如何从提供的字典中提取正确的值。现在唯一的检查是确保每个输出变量都有一个可用的值,但如果需要,可以随意添加额外的检查。

import inspect
def update(src):
    result = []
    cprev = inspect.currentframe().f_back
    #print(cprev.f_code.co_names)
    for v in cprev.f_code.co_names[1:]:
        if src is cprev.f_locals[v]: continue
        if v in src:
            result.append(src[v])
        else:
            raise NameError(v + " has no source for update")
    return result

用法如下所示:

src={'a': 1, 'b': 2, 'c': 3}
a,b,c = update(src)
于 2019-04-12T05:34:31.270 回答