hat*_*rix 45 python sorting dictionary
I am trying to 'destructure' a dictionary and associate values with variables names after its keys. Something like
params = {'a':1,'b':2}
a,b = params.values()
Run Code Online (Sandbox Code Playgroud)
But since dictionaries are not ordered, there is no guarantee that params.values() will return values in the order of (a, b). Is there a nice way to do this?
小智 41
from operator import itemgetter
params = {'a': 1, 'b': 2}
a, b = itemgetter('a', 'b')(params)
Run Code Online (Sandbox Code Playgroud)
除了精心设计的lambda函数或字典理解之外,还可以使用内置库.
Sha*_*umo 26
比Jochen的建议更少重复的一种方法是使用辅助函数.这样可以灵活地按任意顺序列出变量名称,并且只解构dict中的变量的子集:
pluck = lambda dict, *args: (dict[arg] for arg in args)
things = {'blah': 'bleh', 'foo': 'bar'}
foo, blah = pluck(things, 'foo', 'blah')
Run Code Online (Sandbox Code Playgroud)
此外,您可以对键进行排序并获取值,而不是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)
Run Code Online (Sandbox Code Playgroud)
Syl*_*oux 14
Python只能"解构"序列,而不是字典.因此,要编写您想要的内容,您必须将所需的条目映射到正确的序列.就我自己而言,我能找到的最接近的匹配是(不是很性感):
a,b = [d[k] for k in ('a','b')]
Run Code Online (Sandbox Code Playgroud)
这也适用于发电机:
a,b = (d[k] for k in ('a','b'))
Run Code Online (Sandbox Code Playgroud)
这是一个完整的例子:
>>> 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
Run Code Online (Sandbox Code Playgroud)
dec*_*ory 11
使用 Python 3.10,您可以执行以下操作:
d = {"a": 1, "b": 2}
match d:
case {"a": a, "b": b}:
print(f"A is {a} and b is {b}")
Run Code Online (Sandbox Code Playgroud)
但它增加了两级额外的缩进,并且您仍然必须重复键名称。
也许你真的想做这样的事情?
def some_func(a, b):
print a,b
params = {'a':1,'b':2}
some_func(**params) # equiv to some_func(a=1, b=2)
Run Code Online (Sandbox Code Playgroud)
该from ... import语句允许我们解构和绑定对象的属性名称。当然,它只适用于sys.modules字典中的对象,因此可以使用如下的 hack:
import sys, types
mydict = {'a':1,'b':2}
sys.modules["mydict"] = types.SimpleNamespace(**mydict)
from mydict import a, b
Run Code Online (Sandbox Code Playgroud)
一个更严重的黑客是编写一个上下文管理器来加载和卸载模块:
with obj_as_module(mydict, "mydict_module"):
from mydict_module import a, b
Run Code Online (Sandbox Code Playgroud)
通过将__getattr__模块的方法直接指向__getitem__字典的方法,上下文管理器还可以避免使用SimpleNamespace(**mydict).
请参阅此答案以了解该想法的实现和一些扩展。
sys.modules人们还可以暂时用感兴趣的字典替换整个字典,并且import a, b不用from.
如果您害怕使用locals字典所涉及的问题,并且您更喜欢遵循原始策略,则可以使用python 2.7和3.1 collections.OrderedDicts中的 Ordered Dictionaries按照第一次插入的顺序恢复字典项
警告 1:如文档中所述,不能保证这适用于所有 Python 实现:
\n\n\n\n\nCPython 实现细节:此函数依赖于解释器中的 Python 堆栈帧支持,但不能保证在 Python 的所有实现中都存在该支持。如果在没有 Python 堆栈帧支持的实现中运行,则此函数返回 None。
\n
警告 2:这个函数确实使代码更短,但它可能与尽可能明确的 Python 哲学相矛盾。此外,它没有解决 John Christopher Jones 在评论中指出的问题,尽管您可以创建一个使用属性而不是键的类似函数。这只是一个演示,如果您真的愿意,您可以做到这一点!
\n\ndef destructure(dict_):\n if not isinstance(dict_, dict):\n raise TypeError(f"{dict_} is not a dict")\n # the parent frame will contain the information about\n # the current line\n parent_frame = inspect.currentframe().f_back\n\n # so we extract that line (by default the code context\n # only contains the current line)\n (line,) = inspect.getframeinfo(parent_frame).code_context\n\n # "hello, key = destructure(my_dict)"\n # -> ("hello, key ", "=", " destructure(my_dict)")\n lvalues, _equals, _rvalue = line.strip().partition("=")\n\n # -> ["hello", "key"]\n keys = [s.strip() for s in lvalues.split(",") if s.strip()]\n\n if missing := [key for key in keys if key not in dict_]:\n raise KeyError(*missing)\n\n for key in keys:\n yield dict_[key]\nRun Code Online (Sandbox Code Playgroud)\n\nIn [5]: my_dict = {"hello": "world", "123": "456", "key": "value"} \n\nIn [6]: hello, key = destructure(my_dict) \n\nIn [7]: hello \nOut[7]: \'world\'\n\nIn [8]: key \nOut[8]: \'value\'\nRun Code Online (Sandbox Code Playgroud)\n\n该解决方案允许您选择一些键,而不是全部键,就像在 JavaScript 中一样。对于用户提供的词典来说也是安全的
\n为什么没有人发布最简单的方法?
params = {'a':1,'b':2}
a, b = params['a'], params['b']
Run Code Online (Sandbox Code Playgroud)
小智 6
这是另一种方法,类似于JS中的解构分配如何工作:
params = {'b': 2, 'a': 1}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
Run Code Online (Sandbox Code Playgroud)
我们所做的是将params字典解压缩为键值(使用**)(如Jochen的回答所示),然后我们将这些值取入了lambda签名并根据键名进行了分配-这是一个奖励-我们还可以获得什么是一本字典不能在lambda的签名,所以如果你有:
params = {'b': 2, 'a': 1, 'c': 3}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
Run Code Online (Sandbox Code Playgroud)
应用lambda之后,其余变量现在将包含:{'c':3}
对于从字典中删除不需要的键很有用。
希望这可以帮助。