我正在尝试“分解”字典,并在其键之后将值与变量名称相关联。就像是
params = {'a':1,'b':2}
a,b = params.values()
但是由于字典没有排序,因此不能保证params.values()
将返回的顺序为(a, b)
。有没有很好的方法可以做到这一点?
我正在尝试“分解”字典,并在其键之后将值与变量名称相关联。就像是
params = {'a':1,'b':2}
a,b = params.values()
但是由于字典没有排序,因此不能保证params.values()
将返回的顺序为(a, b)
。有没有很好的方法可以做到这一点?
let {a, b} = params
。它提高了可读性,并且与您要谈论的Zen完全兼容。
let {a: waffles} = params
。即使您已经习惯了,也要花几秒钟才能弄清楚。
Answers:
如果您担心使用locals词典时会遇到问题,并且希望遵循最初的策略,可以使用python 2.7和3.1集合中的Ordered Dictionary.OrderedDicts可以按首次插入字典的顺序来恢复字典项
from operator import itemgetter
params = {'a': 1, 'b': 2}
a, b = itemgetter('a', 'b')(params)
除了详细的lambda函数或字典理解之外,还可以使用内置库。
attrgetter
从适用于对象属性(obj.a
)的同一标准库模块中扩展答案以使用。这与JavaScript的主要区别在于obj.a === obj["a"]
。
KeyError
则会引发异常
a, b = [d[k] for k in ('a','b')]
的方式更自然/可读(形式更常见)。这仍然是一个有趣的答案,但这不是最直接的解决方案。
get_id = itemgetter(KEYS)
稍后使用这样的操作serial, code, ts = get_id(document)
会更简单。诚然,您必须对高阶函数感到满意,但是Python通常对它们非常满意。例如,请参阅有关装饰器的文档,例如@contextmanager
。
一种比Jochen的建议少重复的方法是使用助手功能。这使您可以灵活地以任何顺序列出变量名,并且仅解构dict中的子集:
pluck = lambda dict, *args: (dict[arg] for arg in args)
things = {'blah': 'bleh', 'foo': 'bar'}
foo, blah = pluck(things, 'foo', 'blah')
另外,可以代替键的排序和获取值来代替joaquin的OrderedDict。唯一要注意的是,您需要按字母顺序指定变量名,并分解dict中的所有内容:
sorted_vals = lambda dict: (t[1] for t in sorted(dict.items()))
things = {'foo': 'bar', 'blah': 'bleh'}
blah, foo = sorted_vals(things)
lambda
变量分配a ,则最好将常规函数语法与一起使用def
。
itemgetter
从operator
标准库。:)
Python仅能“分解”序列,而不能字典。因此,要编写所需的内容,必须将所需的条目映射到适当的顺序。就我自己而言,我能找到的最接近的匹配是(不是很性感):
a,b = [d[k] for k in ('a','b')]
这也适用于生成器:
a,b = (d[k] for k in ('a','b'))
这是一个完整的示例:
>>> d = dict(a=1,b=2,c=3)
>>> d
{'a': 1, 'c': 3, 'b': 2}
>>> a, b = [d[k] for k in ('a','b')]
>>> a
1
>>> b
2
>>> a, b = (d[k] for k in ('a','b'))
>>> a
1
>>> b
2
也许您真的想做这样的事情?
def some_func(a, b):
print a,b
params = {'a':1,'b':2}
some_func(**params) # equiv to some_func(a=1, b=2)
这是另一种方法,类似于JS中的解构分配如何工作:
params = {'b': 2, 'a': 1}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
我们所做的是将params字典解压缩为键值(使用**)(如Jochen的回答所示),然后我们将这些值取入了lambda签名并根据键名进行了分配-这是一个奖励-我们还可以获得什么是一本字典不能在lambda的签名,所以如果你有:
params = {'b': 2, 'a': 1, 'c': 3}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
应用lambda之后,其余变量现在将包含:{'c':3}
对于从字典中删除不需要的键很有用。
希望这可以帮助。
警告1:如文档中所述,不能保证此方法可在所有Python实现上都可以使用:
CPython实现细节:此函数依赖于解释器中的Python堆栈框架支持,并不能保证在所有Python实现中都存在。如果在没有Python堆栈框架支持的实现中运行,则此函数返回None。
警告2:此函数的确会使代码更短,但可能与Python尽可能明确的哲学相矛盾。而且,尽管您可以创建一个类似的功能来使用属性而不是键,但是它并没有解决John Christopher Jones在评论中指出的问题。这只是一个演示,如果您确实愿意,您可以这样做!
def destructure(dict_):
if not isinstance(dict_, dict):
raise TypeError(f"{dict_} is not a dict")
# the parent frame will contain the information about
# the current line
parent_frame = inspect.currentframe().f_back
# so we extract that line (by default the code context
# only contains the current line)
(line,) = inspect.getframeinfo(parent_frame).code_context
# "hello, key = destructure(my_dict)"
# -> ("hello, key ", "=", " destructure(my_dict)")
lvalues, _equals, _rvalue = line.strip().partition("=")
# -> ["hello", "key"]
keys = [s.strip() for s in lvalues.split(",") if s.strip()]
if missing := [key for key in keys if key not in dict_]:
raise KeyError(*missing)
for key in keys:
yield dict_[key]
In [5]: my_dict = {"hello": "world", "123": "456", "key": "value"}
In [6]: hello, key = destructure(my_dict)
In [7]: hello
Out[7]: 'world'
In [8]: key
Out[8]: 'value'
该解决方案使您可以选择一些键,而不是全部,例如JavaScript。用户提供的字典也很安全
好吧,如果您想在课堂上学习这些,可以随时这样做:
class AttributeDict(dict):
def __init__(self, *args, **kwargs):
super(AttributeDict, self).__init__(*args, **kwargs)
self.__dict__.update(self)
d = AttributeDict(a=1, b=2)
由于字典可以保证在Python> = 3.7中保持其插入顺序,所以这意味着现在这样做是完全安全和惯用的:
params = {'a': 1, 'b': 2}
a, b = params.values()
print(a)
print(b)
输出:
1 2
b, a = params.values()
,因为它使用的是订单而不是名称。
itemgetter
是执行此操作最有效的方法。这不适用于Python 3.6或更低版本,并且由于它依赖顺序,因此一开始可能会造成混淆。
我不知道这是不是很好的风格,但是
locals().update(params)
会成功的 然后a
,您有了,b
而params
字典中的任何内容都可以作为相应的局部变量使用。