从变量列表创建字典

56

我正在寻找一种无需显式编写键来创建字典的方法。

我想创建一个函数,该函数获取变量数量并创建一个字典,其中变量名是键,它们的值是变量值。

与编写以下函数不同:

def foo():
    first_name = "daniel"
    second_name = "daniel"
    id = 1
    return {'first_name':first_name, 'second_name':second_name}

我想使用这个函数得到相同的结果:

create_dict_from_variables(first_name, second_name)

有没有什么方法可以这样做?

8个回答

32

您至少需要编写变量名才能完成,但可以这样编写速记:

>>> foo = 1
>>> bar = 2
>>> d = dict(((k, eval(k)) for k in ('foo', 'bar')))
>>> d
{'foo': 1, 'bar': 2}
或者作为一个函数:
def createDict(*args):
     return dict(((k, eval(k)) for k in args))

>>> createDict('foo','bar')
{'foo': 1, 'bar': 2}

你也可以使用globals()而非eval()

>>> dict(((k, globals()[k]) for k in ('foo', 'bar')))

d = dict(((k, eval(k)) for k in ('foo', 'bar'))) 这段代码在命令行或脚本中可以正常工作,但一旦放入函数中就会失败,我无法找出原因。 - Kevin
1
为了澄清(我的评论编辑框超时了),即使在上面我有一个输出“a is [1, 2] of type <class 'list'>”的print(),dict()命令仍然会失败并显示“NameError: name 'a' is not defined”。我已经定义了a = [1,2]b = [10,20,30]以及keys = ['a','b'],并尝试使用d = dict(((k, eval(k)) for k in keys))来定义d。那么为什么这个命令在命令行上运行时可以正常工作,但在函数中却不行呢?这是作用域的问题吗? - Kevin

25

pip install sorcery

from sorcery import dict_of

a = 1
b = 2
c = 3
d = dict_of(a, b, c)
print(d)
# {'a': 1, 'b': 2, 'c': 3}

1
它是救星,我迫切需要它。现在可以轻松记录任何变量并查看它们。 - Santhosh

8
你可以使用 locals,但我建议不要这样做。请明确地完成。
>>> import this
[...]
Explicit is better than implicit.
[...]

如果您显式地编写代码,那么它通常会更好、更可预测、更不容易出错,而且更易于理解。


1
考虑过使用本地变量,但我不想传递太多的临时变量。 - Idok
@user1087310:那么,你已经考虑了唯一可能的可能性。既然你已经排除了这个可能性,那么知道没有其他方法可以做到;明确地去做,并享受它! - Chris Morgan
2
自从我开始使用Python以来,已经很久没有遇到过做不到的事情了。我正在编写一些需要为其他函数返回大量参数的函数。返回的字典几乎与变量名相同,所以在明确写出键时,我很容易犯错。但是我的祖父曾告诉我,生活并不容易 :) - Idok
@Chris Morgan,抱歉,为什么不使用locals呢?在这里看起来很理想-函数需要从变量名和值中形成一个字典,这些变量在函数中。我正在寻找类似的东西,以创建一个字典,用于传递到SQL查询中,以从函数参数替换命名占位符,并且它似乎正是我所需要的。那为什么不呢?无论如何,我在函数内部有变量,必须手动创建这样的字典而不使用locals。 - Arleg
@Arleg: locals()让你的代码变得不可预知,更容易出错和难以理解,因为隐式比显式更糟糕。(它的作用不是很明显,因此很容易通过无意中添加或删除返回值来出错。) - Chris Morgan

3
原则上,可以通过将变量名称传递给函数create_dict,然后使用模块inspectcreate_dict函数中访问调用者堆栈帧来实现。

2
不,没有这样的东西,因为Python函数无法获取有关用于调用函数的变量的信息。此外,想象一下做这样的事情:
create_dict_from_variables(first_name[:-3] + "moo", last_name[::2])

该函数无法知道用于创建参数的表达式。

1

这个问题有一个有趣的解决方案,不需要使用外部库。然而,需要稍微不同的语法:eval(f(a,b))

# Auxiliary Function
f = lambda s: f"dict({ ','.join( f'{k}={k}' for k in s.split(',') ) })"

first_name  = "daniel"
second_name = "joe"
D           = eval(f('first_name,second_name'))

print(D)
# {'first_name': 'daniel', 'second_name': 'joe'}

在上面的例子中,OP的主要目标仍然实现了,因为我们只需输入变量名一次即可创建字典。但是,语法仍然有点冗长。
PS.上述代码的一个重要优点是,我们在其原始命名空间中评估字典,这消除了与函数作用域(globals(),locals()等)相关的任何限制。这是我使用此方法的主要动机。

1
事实上,有一种方式:

from varname import nameof

def foo(first_name,second_name):
    return {nameof(first_name):first_name, nameof(second_name):second_name}

first_name = "daniel"
second_name = "daniel"

print (foo(first_name,second_name))

输出:

{'first_name': 'daniel', 'second_name': 'daniel'}

您可以在下面获取python-varname软件包:

https://github.com/pwwang/python-varname

基本用法:

from varname import nameof

s = 'Hey!'

print (nameof(s))

输出:

s

-3

你不能这样做。

你的函数可以定义为:

def create_dict_from_variables(first_name, second_name):
    return something_from(first_name, second_name)

你可以调用这个函数:

create_dict_from_variables('abcd', 'efgh')

这两个参数 'abcd''efgh' 不是命名变量。


2
不正确(请参见Vasus的答案)且无益。请查看Not_a_Golfer的Pythonic答案。 - nealmcb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接